package com.authorwjf.bounce;
import static com.authorwjf.bounce.BluetoothChatService.KILOMETERS_IN_A_MILE;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;
public class AnimatedView extends ImageView{
private Context mContext;
int x = -1;
int y = -1;
//private int xVelocity = 10;
private int yVelocity = 5;
private Handler h;
private final int FRAME_RATE = 30;
private int sashay = 0;
private int flambe = 15;
private double scoreNum = 0;
private double amount = scoreNum/100;
private int scoreDec = 0;
private String getURL = "http://omnidrive.herokuapp.com/getscore?fbid=";
private int timeSinceLastRec = 0;
private long counter = 0;
String rec = "";
int recCountup = 0;
int status = 0;
boolean scrollIn = false;
private double speed = 0;
// Image data
private int winWidth = -1;
private int winHeight = -1;
private int greenWidth = -1;
private int greenHeight = -1;
private int grayWidth = -1;
private int grayHeight = -1;
private int ballWidth = -1;
private BitmapDrawable greenCircle = null;
private BitmapDrawable grayCircle = null;
private BitmapDrawable ball = null;
private MediaPlayer mp1;
private long last;
private Bitmap grayMap;
private int[] grayPixels;
private double lastMPG = 0;
private int coinCounter = 0;
private double lastCoinCheck = 0;
private ArrayList<Double> avgMpgThisDrive = new ArrayList<Double>();
private HashMap<String, Integer> recTracker = new HashMap<String, Integer>();
public static int totalCoinsWon = 0;
public static int rep = 0;
public static String recommendedTip = "";
public static double avgMpg = 0;
public static long totalDriveTime = 0;
private long startDriveTime = 0;
private double currentSpeed = -1;
private double speedDeltaTolerance = 100;
private final double TOLERANCE_SCALE_DECREASE = 0.9;
private double engineLoadTolerance = 100;
private int slowSpeed = 0;
private long speedingWarning = 0;
private final int MAX_TOLERANCE = 100;
public AnimatedView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
h = new Handler();
getURL += Main.fbid;
updateCoins(false);
startDriveTime = System.currentTimeMillis();
}
private Runnable r = new Runnable() {
@Override
public void run() {
invalidate();
}
};
private String getRecommendation() {
speedingWarning++;
String speed = BluetoothChatService.retrieveDatum("speed");
if(speed != null) {
double now = Double.parseDouble(speed);
if(now > 65 * KILOMETERS_IN_A_MILE && speedingWarning > 100){
speedingWarning = 0;
return "Try to avoid going too quickly.";
}
else if(now < 5 * KILOMETERS_IN_A_MILE && ++slowSpeed > 100){
slowSpeed = 0;
return "Avoid idling your engine.";
}
slowSpeed = 0;
double delta = now - currentSpeed;
if(currentSpeed < 0) {
delta = 0;
}
currentSpeed = now;
if(delta >= speedDeltaTolerance) {
speedDeltaTolerance = MAX_TOLERANCE;
return "Try to avoid flooring the accelerator.";
}
else if(delta <= -speedDeltaTolerance) {
speedDeltaTolerance = MAX_TOLERANCE;
return "Try to avoid flooring the brake pedal.";
}
}
engineLoadTolerance *= TOLERANCE_SCALE_DECREASE;
String engineLoad = BluetoothChatService.retrieveDatum("engine load");
if(engineLoad != null && Double.parseDouble(engineLoad) >= engineLoadTolerance) {
engineLoadTolerance = 100;
return "Don't push the engine too hard - avoid sudden changes in speed.";
}
speedDeltaTolerance *= TOLERANCE_SCALE_DECREASE;
return "No recommendation.";
}
/* Updates the player's total number of coins to the database once the drive
* has concluded
*/
private class updateCoinsTask extends AsyncTask<String, Integer, Integer> {
@Override
protected Integer doInBackground(String... params) {
try {
HttpClient client = new DefaultHttpClient();
String url = "http://omnidrive.herokuapp.com/getcoins?coins=" + totalCoinsWon;
HttpGet get = new HttpGet(url);
HttpResponse responseGet = client.execute(get);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
}
/* Gets the initial number of coins from the database. The total number of coins won
* is updated based on this initial number.
*/
private class getInitialCoinsTask extends AsyncTask<String, Integer, Integer> {
@Override
protected Integer doInBackground(String... params) {
try {
HttpClient client = new DefaultHttpClient();
String url = "http://www.omnidrive.io/api/?fbid="+ Main.fbid;
HttpGet get = new HttpGet(url);
HttpResponse responseGet = client.execute(get);
HttpEntity responseEntity = responseGet.getEntity();
String response = EntityUtils.toString(responseEntity);
if (!response.equals(null)) {
JSONObject currUser;
try {
currUser = new JSONObject(response);
String curCoinsString = currUser.optString("coins");
if(curCoinsString != null) {
int initialCoins = Integer.parseInt(curCoinsString);
totalCoinsWon += initialCoins;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
}
private class setScoreTask extends AsyncTask<String, Integer, Integer> {
@Override
protected Integer doInBackground(String... params) {
double mpg = BluetoothChatService.currentMPG;
if (mpg != scoreNum) {
lastMPG = scoreNum;
scoreNum = mpg;
}
scoreNum = mpg;
avgMpgThisDrive.add(mpg);
return 0;
}
}
private void updateCoins(boolean update) {
if (update) {
(new updateCoinsTask()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getURL);
} else {
(new getInitialCoinsTask()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getURL);
}
}
private void setScore() {
(new setScoreTask()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getURL);
}
private void drawRecommendation(Canvas c, Paint scorePaint) {
Rect notification = new Rect(0, getHeight() - status, getWidth(), getHeight());
scorePaint.setColor(Color.parseColor("#3498db"));
scorePaint.setStyle(Style.FILL);
c.drawRect(notification, scorePaint);
scorePaint.setTextSize(40);
scorePaint.setColor(Color.WHITE);
Rect recBounds = new Rect();
scorePaint.getTextBounds(rec, 0, rec.length(), recBounds);
c.drawText(rec, this.getWidth()/2 - recBounds.width() / 2, this.getHeight() - status + recBounds.height() + 12, scorePaint);
}
private double calculateAverageMPG() {
int sum = 0;
for (int i=0; i< avgMpgThisDrive.size(); i++) {
sum += i;
}
return sum / (avgMpgThisDrive.size() + 0.1);
}
private void drawCircles(BitmapDrawable greenCircle, BitmapDrawable grayCircle, Canvas c, double amt) {
Paint scorePaint = new Paint();
if (scoreNum <=25) {
scorePaint.setColor(Color.RED);
} else {
scorePaint.setColor(Color.WHITE);
}
scorePaint.setTextSize(200);
if (scoreDec == 4) {
setScore();
double difference = scoreNum - lastMPG;
//amt = scoreNum/100;
//amount = amt;
if (difference < 0 ) {
speed = -.0001 * (-1) * difference;
} else {
speed = 0.0001 * difference;
}
scoreDec = 0;
if (scoreNum == 99) {
last = System.currentTimeMillis();
}
else if (scoreNum % 10 == 0) {
long curr = System.currentTimeMillis();
last = curr;
}
} else {
scoreDec++;
}
String score = String.format("%.2g%n", scoreNum);
winWidth = this.getWidth();
winHeight = this.getHeight();
Rect bounds = new Rect();
scorePaint.getTextBounds(score, 0, score.length(), bounds);
int scoreX = winWidth/2 - bounds.width()/2 - 15;
int scoreY = greenWidth/2 + bounds.height()/2 - 10;
int endX = grayWidth;
int endY = (int)(grayHeight * (1 - amount));
int greenX = winWidth/2 - greenWidth/2;
int grayX = winWidth/2 - grayWidth/2;
c.drawBitmap(greenCircle.getBitmap(), greenX, 10, null);
c.drawBitmap(grayPixels, 0, grayMap.getWidth(), grayX, 10, endX, endY, false, null);
//c.drawBitmap(transform, grayX, 10, null);
timeSinceLastRec++;
c.drawText(score, scoreX, scoreY, scorePaint);
if (lastMPG > 0 && (scoreNum - lastMPG < 0) && timeSinceLastRec > 600) {
if (rec.equals("")) {
rec = getRecommendation();
if (recTracker.containsKey(rec)) {
int curNumber = recTracker.get(rec);
recTracker.put(rec, curNumber++);
} else {
recTracker.put(rec, 1);
}
timeSinceLastRec = 0;
mp1.start();
scrollIn = true;
} else {
if (scrollIn) {
if (status < 80) {
status += 10;
} else {
scrollIn = false;
}
} else {
recCountup++;
if (recCountup > 80) {
status -= 10;
}
}
if (status > -10) {
drawRecommendation(c, scorePaint);
}
}
} else {
// reset recommendation variables
rec = "";
recCountup = 0;
scrollIn = false;
status = 0;
}
if (coinCounter == 50) {
double diff = scoreNum - lastCoinCheck;
if (diff > 0) {
makeToast(diff);
}
coinCounter = 0;
lastCoinCheck = scoreNum;
}
coinCounter++;
}
private void makeToast(double diff) {
Context context = mContext;
CharSequence text = "Great job!! + " + (int)diff + " coins!";
int duration = Toast.LENGTH_LONG;
totalCoinsWon += (int)diff;
rep += (int) diff;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
/* Adjust flambe speed around a mean of 15. Note: The speed of the droplet descent isn't changed.
* Only the amount of time between droplets is changed. The higher this amount of time, the "slower"
* the droplets, and the more your score is improving at the moment. */
private void adjustFlambe() {
if (scoreNum > 0 && lastMPG > 0) {
int improvement = (int) (scoreNum - lastMPG);
/* only change flambe if a reasonable number is found for scoreNum - lastMPG. If
* an out-of-range improvement is found, it is likely because the car is just starting up. The
* droplets should not change their speed in this case.
*/
if (Math.abs(improvement) < 5) {
flambe += improvement;
}
}
/* Last check to ensure flambe is within a reasonable range */
if (flambe < 5) {
flambe = 5;
} else if (flambe > 25) {
flambe = 25;
}
}
private String updateBestTip() {
String bestRec = "";
int maxHits = 0;
for(String key : recTracker.keySet()) {
int currentHits = recTracker.get(key);
if (currentHits > maxHits) {
bestRec = key;
maxHits = currentHits;
}
}
return bestRec;
}
protected void onDraw(Canvas c) {
if (BluetoothChatService.end_game) {
totalDriveTime = System.currentTimeMillis() - startDriveTime;
// convert to minutes
totalDriveTime = totalDriveTime/(1000 * 60);
recommendedTip = updateBestTip();
updateCoins(true);
avgMpg = calculateAverageMPG();
Activity a = (Activity) mContext;
Intent k = new Intent(a, SummaryActivity.class);
a.startActivity(k);
}
if(++counter % 10 == 0) {
drawRecommendation(c, new Paint());
}
if (greenCircle == null) {
greenCircle = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.darkcircle1);
grayCircle = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.graycircle);
grayMap = grayCircle.getBitmap();
ball = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.waterdrop);
winWidth = this.getWidth();
winHeight = this.getHeight();
grayWidth = grayCircle.getBitmap().getWidth();
grayHeight = grayCircle.getBitmap().getHeight();
greenWidth = greenCircle.getBitmap().getWidth();
greenHeight = greenCircle.getBitmap().getHeight();
ballWidth = ball.getBitmap().getWidth();
grayPixels = new int[grayMap.getWidth() * grayMap.getHeight()];
grayCircle.getBitmap().getPixels(grayPixels, 0, grayMap.getWidth(), 1, 1, grayMap.getWidth() - 1, grayMap.getHeight() - 1);
}
if (flambe >= 15) {
if (x<0 && y <0) {
x = winWidth/2 - ballWidth/2;
y = winHeight/2;
yVelocity *= 1.1;
} else {
y += yVelocity;
if (sashay < 2) {
yVelocity *= 1.1;
sashay++;
} else if (sashay < 18) {
yVelocity *= 1.25;
sashay++;
} else {
yVelocity *= 1.2;
}
if ((y > winHeight) || (y < 0)) {
yVelocity = 5;
x = winWidth/2 - ballWidth/2;
y = winHeight/2;
sashay = 0;
flambe = 0;
}
}
if (flambe > 0) {
c.drawBitmap(ball.getBitmap(), x, y, null);
}
amount += speed;
if (amount < 0.01) {
amount = 0.01;
} else if (amount > 0.99) {
amount = 0.99;
}
drawCircles(greenCircle, grayCircle, c, amount);
h.postDelayed(r, FRAME_RATE);
} else {
flambe++;
amount += speed;
if (amount < 0.001) {
amount = 0.001;
} else if (amount > 0.99) {
amount = 0.99;
}
drawCircles(greenCircle, grayCircle, c, amount);
h.postDelayed(r, FRAME_RATE);
}
adjustFlambe();
}
}