package cz.uhk.fim.dragonboatassistant.app;

import java.util.concurrent.TimeUnit;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.PolylineOptions;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.os.Bundle;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import cz.uhk.fim.dragonboatassistant.R;
import cz.uhk.fim.dragonboatassistant.core.GoogleAPIActivity;
import cz.uhk.fim.dragonboatassistant.util.Converter;
import cz.uhk.fim.dragonboatassistant.util.Forecast;

public class TrackingActivity extends GoogleAPIActivity implements SensorEventListener {
	
	private SensorManager sManager;
	private Sensor sensor;
	private SeekBar seekBar;
	PolylineOptions lineOptions;
	Forecast forecast;
	Forecast forecast2;
	Converter millisToSecsConverter;
	Converter secsToMinsConverter;

	Location from;
	Location to;
	
	float elapsedDistMeters;
	float dist;
	float speed;
	float maxSpeed;
	float avgSpeedPerPartes;
	float avgSpeedTotal;	
	float calibration;
	float balanceAngle;
	float accuracy;
	float SENSITIVITY = 60;
	float THRESHOLD;
	float FC_DISTANCE = 2000;
	float FC_DISTANCE2 = 500;
	
	long elapsedTimeSecs;
	long seconds;
	long mins;
	long startMillis;
	long endMillis;
	long fromTime;
	long toTime;
	long totalCounter;
	long corectCounter;
	long tiltPercentage;
	
	int count;	
	
	boolean tracking;
	boolean calibrate;	
	boolean excessiveTilt;

	TextView distText;
	TextView accurText;
	TextView speedText;
	TextView avgSpeedText;
	TextView textTime;
	TextView textBalance;
	TextView textBalanceCenter;
	TextView balanceColorRight;
	TextView forecastIntroText;
	TextView forecastText;
	TextView forecastText2;
	TextView percentageText;
	
	Switch startTrackingSwitch;

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		System.out.println("Vytvářím třídu TrackingActivity");
		setContentView(R.layout.activity_tracking);
		
		forecast = new Forecast(FC_DISTANCE);
		forecast2 = new Forecast(FC_DISTANCE2);
		
		millisToSecsConverter = new Converter(TimeUnit.MILLISECONDS, TimeUnit.SECONDS);
		secsToMinsConverter = new Converter(TimeUnit.SECONDS, TimeUnit.MINUTES);

		distText = (TextView) findViewById(R.id.distText);
		accurText = (TextView) findViewById(R.id.accurText);
		speedText = (TextView) findViewById(R.id.speedText);
		avgSpeedText = (TextView) findViewById(R.id.avgSpeedText);
		textTime = (TextView) findViewById(R.id.textTime);
		forecastIntroText = (TextView) findViewById(R.id.forecastIntro);
		forecastText = (TextView) findViewById(R.id.forecastText);
		forecastText2 = (TextView) findViewById(R.id.forecastText2);
		percentageText = (TextView) findViewById(R.id.percentageText);
		textBalance = (TextView) findViewById(R.id.textBalance);
		textBalanceCenter = (TextView) findViewById(R.id.textBalanceCenter);
		balanceColorRight = (TextView) findViewById(R.id.balanceColorRight);
		seekBar = (SeekBar) findViewById(R.id.seekBar1);
		sManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		sensor = sManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
		
		distText.setTextSize(18);
		accurText.setTextSize(15);
		speedText.setTextSize(18);
		avgSpeedText.setTextSize(15);
		textTime.setTextSize(18);
		forecastIntroText.setTextSize(16);
		forecastText.setTextSize(18);
		forecastText2.setTextSize(18);
		percentageText.setTextSize(18);
		
		initTexts();

		from = null;
		to = null;
		elapsedDistMeters = 0;
		dist = 0;
		speed = 0;
		maxSpeed = 0;
		avgSpeedPerPartes = 0;
		avgSpeedTotal = 0;
		elapsedTimeSecs = 0;
		calibration = 0;
		balanceAngle = 0;
		mins = 0;
		count = 0;
		totalCounter = 0;
		corectCounter = 0;
		tiltPercentage = 0;
		calibrate = false;
		excessiveTilt = false;
		lineOptions = new PolylineOptions().color(Color.BLUE);

		// get a handle to the GoogleMap object and register the callback
		mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map2);
		super.mapFragment.getMapAsync(this);

		startTrackingSwitch = (Switch) findViewById(R.id.switch1);
		startTrackingSwitch.setChecked(false);
		startTrackingSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				tracking = isChecked;
				if (isChecked) {
					startMillis = System.currentTimeMillis();
					//seconds = 0;
					//dist = 0;
					from = lastKnownLocation;
					fromTime = System.currentTimeMillis();
					Toast.makeText(TrackingActivity.this,"Sledování bylo spuštěno",Toast.LENGTH_LONG).show();
				} else {
					elapsedTimeSecs = elapsedTimeSecs + seconds;
					elapsedDistMeters = elapsedDistMeters + dist;
					seconds = 0;
					dist = 0;
					speed = 0;
					Toast.makeText(TrackingActivity.this,"Sledování bylo pozastaveno",Toast.LENGTH_LONG).show();
				}
			}
		});
	}
	
	public void initTexts() {		
		textTime.setText("Celkový čas: 0sec");
		distText.setText("Vzdálenost: 0km (0m)");
		accurText.setText("c: " + 0  + " acc: " + 0);
		speedText.setText("Rychlost:  " + "0,0" + " m/s" + " (" + 0 + " km/h)");
		avgSpeedText.setText("(max: " + "0,0" + " km/h" + ", prům: " + 0 + " km/h)");
		forecastText.setText("čas na " + String.format("%.0f", FC_DISTANCE) + "m: neznámý");
		forecastText2.setText("čas na " + String.format("%.0f", FC_DISTANCE2) + "m: neznámý");
		percentageText.setText("Čas aktivity ve spr. náklonu: ");
	}

	@Override
	protected void onStart() {
		super.onStart();
		sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
				SensorManager.SENSOR_DELAY_FASTEST);
	}

	@Override
	protected void onStop() {
		sManager.unregisterListener(this);
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	public long getSessionTime() {
		endMillis = System.currentTimeMillis();
		return endMillis - startMillis;
	}

	//public long convertTime(long time, TimeUnit convertTo, TimeUnit convertFrom) {
		//return convertTo.convert(time, convertFrom);
	//}

	public void recountTime() {

		seconds = millisToSecsConverter.convertTime(getSessionTime(), TimeUnit.SECONDS, TimeUnit.MILLISECONDS);
		mins = secsToMinsConverter.convertTime(elapsedTimeSecs + seconds, TimeUnit.MINUTES, TimeUnit.SECONDS);
		if (mins > 0)
			textTime.setText("Celkový čas: " + mins + "min " + ((elapsedTimeSecs + seconds) - mins*60) + "sec");
		else
			textTime.setText("Celkový čas: " + (elapsedTimeSecs + seconds) + "sec");
		
		if (totalCounter > 0) {			
			tiltPercentage = (100*corectCounter) / totalCounter;
		}
		percentageText.setText("Čas aktivity ve spr. náklonu: " + tiltPercentage + "%");
		System.out.println("percentage = " + tiltPercentage);
	}
	
	public void forecastTimeFor(float distance) {
		//Forecast forecast = new Forecast(distance);
		forecast.forecastMinsSeconds(speed);
		forecastText.setText("čas na " + String.format("%.0f", FC_DISTANCE) + "m: " + 
		forecast.convertedMinutes + "m " + forecast.convertedSeconds + "s");
		
		forecast2.forecastMinsSeconds(speed);
		forecastText2.setText("čas na " + String.format("%.0f", FC_DISTANCE2) + "m: " + 
		forecast2.convertedMinutes + "m " + forecast2.convertedSeconds + "s");
	}

	@Override
	public void onConnected(Bundle connectionHint) {
		super.onConnected(connectionHint);
		if (lastKnownLocation != null) {
			if (from == null) {
				from = lastKnownLocation;
				fromTime = System.currentTimeMillis();
				to = lastKnownLocation;
			}
		}
	}

	@Override
	public void onMapReady(GoogleMap map) {
		super.onMapReady(map);
	}

	@Override
	public void onLocationChanged(Location location) {
		System.out.println("debug location update");
		super.onLocationChanged(location);
		accuracy = location.getAccuracy();
		if (tracking) {
			if (accuracy < DISPLACEMENT) {
				to = location;
				toTime = System.currentTimeMillis();
				dist = dist + from.distanceTo(to);
				speed = getSpeedInMPS(from, to, fromTime, toTime);
				if (speed > 1)
				forecastTimeFor(FC_DISTANCE);
				// max speed
				if (speed > maxSpeed) maxSpeed = speed;
				// avg speed (per partes)
				avgSpeedPerPartes = (avgSpeedPerPartes + speed) / 2;
				// avg speed (total)
				avgSpeedTotal = (elapsedDistMeters + dist) / (elapsedTimeSecs + seconds);
				
				from = location;
				fromTime = System.currentTimeMillis();
			}
			count = count + 1;
		}
		updateMap(location, map);
		renderTextViews();
	}

	protected void updateMap(Location loc, GoogleMap map) {
		System.out.println("debug update map");
		super.updateMap(loc, map);
		if (tracking && (accuracy < DISPLACEMENT)) {
			lineOptions.add(new LatLng(loc.getLatitude(), loc.getLongitude()));
			map.addPolyline(lineOptions);
		}
	}

	private void renderTextViews() {
		distText.setText("Vzdálenost: " + String.format("%.2f", (elapsedDistMeters+dist) / 1000) + "km (" + String.format("%.0f", elapsedDistMeters+dist) + "m)");
		accurText.setText("c: " + count  + " acc: " + String.format("%.0f", accuracy));
		speedText.setText("Rychlost:  " + String.format("%.1f", speed) + " m/s" + " (" + String.format("%.0f", convertToKmPerHour(speed)) + " km/h)");
		avgSpeedText.setText("(max: " + String.format("%.1f", convertToKmPerHour(maxSpeed)) + " km/h" + ", prům: " + String.format("%.0f", convertToKmPerHour(avgSpeedTotal)) + " km/h)");
	}

	// metody rozhranní SensorEventListener
	@Override
	public void onSensorChanged(SensorEvent event) {
		
		System.out.println("debug");

		if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
			System.out.println("Senzor je nyní nespolehlivý");
			return;
		}
		// Sensor sensor = event.sensor;
		if (sensor.getType() == Sensor.TYPE_GRAVITY) {
			if (calibrate) {
				calibration = (SENSITIVITY * event.values[0]) * (-1);
				Toast.makeText(TrackingActivity.this,"Byla provedena kalibrace",Toast.LENGTH_LONG).show();
				calibrate = false;
			}
			balanceAngle = (SENSITIVITY * event.values[0]) + calibration;
			seekBar.setProgress((int) (50 - balanceAngle));
			System.out.println(balanceAngle);
			THRESHOLD = (SENSITIVITY / 2) - 13;
			if (balanceAngle > THRESHOLD) {
				excessiveTilt = true;
				textBalance.setBackgroundColor(Color.RED);
				balanceColorRight.setBackgroundColor(Color.TRANSPARENT);
			}
			if (balanceAngle < THRESHOLD && balanceAngle > (-THRESHOLD)) {
				excessiveTilt = false;
				textBalance.setBackgroundColor(Color.TRANSPARENT);
				balanceColorRight.setBackgroundColor(Color.TRANSPARENT);
				textBalanceCenter.setBackgroundColor(Color.GREEN);
			}
			if (balanceAngle < (-THRESHOLD)) {
				excessiveTilt = true;
				textBalance.setBackgroundColor(Color.TRANSPARENT);
				balanceColorRight.setBackgroundColor(Color.RED);
			}
		}

		if (tracking) {
			totalCounter ++;
			if (!excessiveTilt) corectCounter ++;
			recountTime();
		}
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		
	}
	
	public float convertToKmPerHour(float mPerSec) {
		return (float) (3.6 * mPerSec);
	}
	
	public float getSpeedInMPS(Location from, Location to, long timeFrom, long timeTo) {
		float distance = from.distanceTo(to); //metry
		long time = millisToSecsConverter.convertTime((timeTo - timeFrom), TimeUnit.SECONDS, TimeUnit.MILLISECONDS); //sekundy
		float speed = distance/time; // m/s
		return speed;
	}
	
	public void calibrate(View v) {
		calibrate = true;
	}
	
	public void reset(View v) {
		tracking = false;
		startTrackingSwitch.setChecked(false);
		from = lastKnownLocation;
		to = lastKnownLocation;
		elapsedDistMeters = 0;
		dist = 0;
		speed = 0;
		maxSpeed = 0;
		avgSpeedPerPartes = 0;
		avgSpeedTotal = 0;
		elapsedTimeSecs = 0;
		seconds = 0;
		mins = 0;
		count = 0;
		totalCounter = 0;
		corectCounter = 0;
		tiltPercentage = 0;
		percentageText.setText("Čas aktivity ve spr. náklonu: ");
		lineOptions = new PolylineOptions().color(Color.BLUE);
		super.map.clear();
		renderTextViews();
		textTime.setText("Celkový čas: " + (elapsedTimeSecs + seconds) + "sec");
		Toast.makeText(TrackingActivity.this,"Aktivita byla vynulována",Toast.LENGTH_LONG).show();
	}
	
	public void stop(View v) {
		
		final Intent intent = new Intent(getApplicationContext(), OverviewActivity.class);
		intent.putExtra("time", elapsedTimeSecs + seconds);
		intent.putExtra("distance", elapsedDistMeters + dist);
		intent.putExtra("maxSpeed", maxSpeed);
		intent.putExtra("avgSpeed", avgSpeedTotal);
		intent.putExtra("tilt", tiltPercentage);

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
	      alertDialogBuilder.setMessage("Aktivita bude ukončena a ve sledování již nebude možno pokračovat");
	      
	      alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
	         @Override
	         public void onClick(DialogInterface arg0, int arg1) {
	            //Toast.makeText(MainActivity.this,"You clicked yes button",Toast.LENGTH_LONG).show();
	        	 startActivity(intent);
	         }
	      });
	      
	      alertDialogBuilder.setNegativeButton("Zrušit",new DialogInterface.OnClickListener() {
	         @Override
	         public void onClick(DialogInterface dialog, int which) {
	            //finish();
	         }
	      });
	      
	      AlertDialog alertDialog = alertDialogBuilder.create();
	      alertDialog.show();
		
	}

}
