package IEEERobotics.IOIOAI.VT;

import java.text.DecimalFormat;

import com.androidplot.Plot.BorderStyle;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.StepFormatter;
import com.androidplot.xy.XYPlot;
import com.androidplot.xy.XYStepMode;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TableRow.LayoutParams;
import ioio.lib.api.IOIO;
import ioio.lib.api.exception.ConnectionLostException;

public class DebugCode {
	private IOIORoboticsActivity _parent;
	private IOIO _ioio;
	private Context _appContext;
	private View _view;
	private SharedPreferences _sharedPrefs;
	private Handler _handler = new Handler();
	private Boolean _connected = false;
	
	// Input classes to be implemented
	private InputInterface _lineFollowIn;
	private InputInterface _voltageIn;
	private InputInterface _waveformIn;
	private InputInterface _capacitanceIn;
	private InputInterface _temperatureIn;
	
	// Updater thread
	private Thread _pollingThread;
	
	// Labels
	private TextView _lineFollowLabel;
	private TextView _voltageLabel;
	private TextView _waveformLabel;
	private TextView _capacitanceLabel;
	private TextView _temperatureLabel;
	
	// Plots
	private XYPlot _lineFollowPlot;
	private XYPlot _voltagePlot;
	private XYPlot _waveformPlot;
	private XYPlot _capacitancePlot;
	private XYPlot _temperaturePlot;
	
	// Data for each plot
	private GenericXYSeries _lineFollowData;
	private GenericXYSeries _voltageData;
	private GenericXYSeries _waveformData;
	private GenericXYSeries _capacitanceData;
	private GenericXYSeries _temperatureData;
	
	// Constant values
	private static int _graphHeight = 80;	// Height in dp
	private static int _textSize = 15;		// TextSize for the labels
	private static int _graphLength;
	private static int _updateSleepPeriod;
	
	/** Class initializer */
	public DebugCode(IOIORoboticsActivity parent) {
		_parent = parent;
		_appContext = IOIORoboticsActivity.context_;
		
		// Get values from shared preferences
		_sharedPrefs = PreferenceManager.getDefaultSharedPreferences(_appContext);
		_graphLength = Integer.parseInt(_sharedPrefs.getString("pref_GraphLength", "100"));
		
		// Create the overall view with the labels and plots
		createView();
	}
	
	/** Starting poing for executing Debug code */
	public void Run() {
		_updateSleepPeriod = Integer.parseInt(_sharedPrefs.getString("pref_UpdateInterval", "100"));
		
		// Initialize the input classes
		initializeInputs();
		
		// Create the updater thread
		setupPollingThread();
		
		_parent.logMessage("Updater thread started");
		_pollingThread.start();
	}
	
	/** Initialize input classes */
	private void initializeInputs() {
		_parent.logMessage("Initializing inputs");
		
		_ioio = IOIORoboticsActivity.IOIOInstance_;
		
		// Initialize each input class (opens pins)
		try {
			_lineFollowIn = new InputLineFollower();
			_lineFollowIn.initialize(_ioio);
			
			_voltageIn = new InputVoltage();
			_voltageIn.initialize(_ioio);
			
			_waveformIn = new InputWaveform();
			_waveformIn.initialize(_ioio);
			
			_capacitanceIn = new InputCapacitance();
			_capacitanceIn.initialize(_ioio);
			
			_temperatureIn = new InputTemperature();
			_temperatureIn.initialize(_ioio);
			
			_connected = true;
		} catch (ConnectionLostException e) {
	
		}
		
		if (_connected) {
			// Update the status labels for each graphs
			_lineFollowLabel.setText("Pin #" + _lineFollowIn.getPinDescription());
			_voltageLabel.setText("Pin #" + _voltageIn.getPinDescription());
			_waveformLabel.setText("Pin #" + _waveformIn.getPinDescription());
			_capacitanceLabel.setText("Pin #" + _capacitanceIn.getPinDescription());
			_temperatureLabel.setText("Pin #" + _temperatureIn.getPinDescription());
		}
	}

	/** Sets up the updater thread to poll for data */
	private void setupPollingThread() {
		// Create a new thread to poll for new data at set interval
		_pollingThread = new Thread(new Runnable() {
			// Output decimal format
			DecimalFormat df = new DecimalFormat("#.####");
			@Override
			public void run() {
				try {
					while (true) {
						// Run until the interrupt signal is sent to the thread
						if (Thread.currentThread().isInterrupted()) {
							break;
						}
						
						if (_connected) {
							// Read in values from input classes
							double ret = _lineFollowIn.getValue();
							updateLineFollowText(_lineFollowIn.getPinDescription() + "   Current Value: " + df.format(ret));
							_lineFollowData.addDataToList(ret);
							
							ret = _voltageIn.getValue();
							updateVoltageText(_voltageIn.getPinDescription() + "   Current Value: " + df.format(ret));
							_voltageData.addDataToList(ret);
							
							ret = _waveformIn.getValue();
							updateWaveformText(_waveformIn.getPinDescription() + "   Current Value: " + df.format(ret));
							_waveformData.addDataToList(ret);
							
							ret = _capacitanceIn.getValue();
							updateCapacitanceText(_capacitanceIn.getPinDescription() + "   Current Value: " + df.format(ret));
							_capacitanceData.addDataToList(ret);
							
							ret = _temperatureIn.getValue();
							updateTemperatureText(_temperatureIn.getPinDescription() + "   Current Value: " + df.format(ret));
							_temperatureData.addDataToList(ret);
							
							// Redraw graph and sleep for set period of time
							redrawGraphs();
						}
						Thread.sleep(_updateSleepPeriod);
					}
				} catch (Exception e) {
					stopPollingThread();
				}
			}
		});
	}

	/** Sends an interrupt signal to the thread and notifies input classes to close pins */
	public void stopPollingThread() {
		if (_pollingThread.isAlive()) {
			_parent.logMessage("Stopping updater thread");
			_pollingThread.interrupt();
		}
		
		if (_connected) {
			_lineFollowIn.closePins();
			_voltageIn.closePins();
			_waveformIn.closePins();
			_capacitanceIn.closePins();
			_temperatureIn.closePins();
		}
		
		_connected = false;
	}

	/** Create the view containing the text labels and plots */
	private void createView() {
		_lineFollowLabel = new TextView(_appContext);
		_lineFollowLabel.setText("Line Follow Plot Label");
		_lineFollowLabel.setTextSize(_textSize);
		
		_lineFollowPlot = new XYPlot(_appContext, "LineFollowPlot");
		_lineFollowPlot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, _graphHeight));
		_lineFollowData = new GenericXYSeries("Line Follow", _graphLength);
		setPlotDetails(_lineFollowPlot, _lineFollowData, 3.3, true);
		
		_voltageLabel = new TextView(_appContext);
		_voltageLabel.setText("Voltage Plot Label");
		_voltageLabel.setTextSize(_textSize);
		
		_voltagePlot = new XYPlot(_appContext, "VoltagePlot");
		_voltagePlot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, _graphHeight));
		_voltageData = new GenericXYSeries("Voltage Data", _graphLength);
		setPlotDetails(_voltagePlot, _voltageData, 3.3, false);
		
		_waveformLabel = new TextView(_appContext);
		_waveformLabel.setText("Waveform Plot Label");
		_waveformLabel.setTextSize(_textSize);
		
		_waveformPlot = new XYPlot(_appContext, "WaveformPlot");
		_waveformPlot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, _graphHeight));
		_waveformData = new GenericXYSeries("Waveform Data", _graphLength);
		setPlotDetails(_waveformPlot, _waveformData, 3.3, false);
		
		_capacitanceLabel = new TextView(_appContext);
		_capacitanceLabel.setText("Capacitance Plot Label");
		_capacitanceLabel.setTextSize(_textSize);
		
		_capacitancePlot = new XYPlot(_appContext, "CapacitancePlot");
		_capacitancePlot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, _graphHeight));
		_capacitanceData = new GenericXYSeries("Capacitance Data", _graphLength);
		setPlotDetails(_capacitancePlot, _capacitanceData, 3.3, false);
		
		_temperatureLabel = new TextView(_appContext);
		_temperatureLabel.setText("Temperature Plot Label");
		_temperatureLabel.setTextSize(_textSize);
		
		_temperaturePlot = new XYPlot(_appContext, "TemperaturePlot");
		_temperaturePlot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, _graphHeight));
		_temperatureData = new GenericXYSeries("Temperature Data", _graphLength);
		setPlotDetails(_temperaturePlot, _temperatureData, 3.3, false);
		
		// Create the main layout and add each subview to it
		LinearLayout layout = new LinearLayout(_appContext);
		layout.setOrientation(LinearLayout.VERTICAL);
		layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
		layout.addView(_lineFollowLabel);
		layout.addView(_lineFollowPlot);
		addDivider(layout);
		layout.addView(_voltageLabel);
		layout.addView(_voltagePlot);
		addDivider(layout);
		layout.addView(_waveformLabel);
		layout.addView(_waveformPlot);
		addDivider(layout);
		layout.addView(_capacitanceLabel);
		layout.addView(_capacitancePlot);
		addDivider(layout);
		layout.addView(_temperatureLabel);
		layout.addView(_temperaturePlot);
		
		ScrollView scroller = new ScrollView(_appContext);
    	scroller.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    	scroller.addView(layout);
    	
		_view = scroller;
	}
	
	/** Adds a divider to the specified layout */
	private void addDivider(View layout) {
		View ruler = new View(_appContext);
		ruler.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, 2));
		ruler.setBackgroundColor(Color.rgb(50, 50, 50));
		
		((LinearLayout)layout).addView(ruler);
	}
	
	/** Associates the graph with the data and set how the graph looks */
	private void setPlotDetails(XYPlot plot, GenericXYSeries data, double range, boolean useStep) {
		// Associate data with plot
		if (!useStep)
			plot.addSeries(data, new LineAndPointFormatter(Color.rgb(0, 0, 200), Color.rgb(0, 0, 100),Color.rgb(150, 150, 190)));
		else {
			StepFormatter stepFormatter = new StepFormatter(Color.rgb(0, 0, 0), Color.rgb(150, 190, 150));
			stepFormatter.getLinePaint().setStrokeWidth(1);
			plot.addSeries(data, stepFormatter);
		}
		// Set boundary and ticks
		plot.setRangeBoundaries(0, range, BoundaryMode.FIXED);
		plot.setDomainBoundaries(0, _graphLength, BoundaryMode.FIXED);
		plot.setDomainStepValue(5);
		plot.setRangeStep(XYStepMode.SUBDIVIDE, 4);
		plot.setTicksPerRangeLabel(3);
		
		// Remove labels and legend
		plot.getLegendWidget().setVisible(false);
		plot.getDomainLabelWidget().setVisible(false);
		plot.getRangeLabelWidget().setVisible(false);
		plot.getTitleWidget().setVisible(false);
		
		// Remove extra margin space
		plot.getGraphWidget().setMargins(0, 10, 10, 0);
		plot.getGraphWidget().setRangeLabelWidth(30);
		plot.getGraphWidget().setDomainLabelWidth(15);
		plot.getGraphWidget().setMarginLeft(-5);
		plot.getGraphWidget().setMarginRight(25);
		plot.setPlotMargins(0, -10, 0, -5);
		plot.setPlotPadding(0, 0, 0, 0);

		// Background color for the plot and divider line colors
		plot.getGraphWidget().getGridBackgroundPaint().setColor(Color.BLACK);
		plot.getGraphWidget().getGridLinePaint().setColor(Color.GRAY);
		plot.getGraphWidget().getDomainOriginLinePaint().setColor(Color.WHITE);
        plot.getGraphWidget().getRangeOriginLinePaint().setColor(Color.WHITE);
		
        // Background for the widget (not the plot itself)
		plot.getGraphWidget().setBackgroundPaint(null);
		plot.setBackgroundPaint(null);
		plot.setBorderPaint(null);
		
		plot.setBorderStyle(BorderStyle.SQUARE, null, null);
		plot.disableAllMarkup();
	}

	private void updateLineFollowText(final String message) {
		_handler.post(new Runnable() {
			@Override
			public void run() {
				_lineFollowLabel.setText(message);
			}
		});
	}
	
	private void updateVoltageText(final String message) {
		_handler.post(new Runnable() {
			@Override
			public void run() {
				_voltageLabel.setText(message);
			}
		});
	}
	
	private void updateWaveformText(final String message) {
		_handler.post(new Runnable() {
			@Override
			public void run() {
				_waveformLabel.setText(message);
			}
		});
	}
	
	private void updateCapacitanceText(final String message) {
		_handler.post(new Runnable() {
			@Override
			public void run() {
				_capacitanceLabel.setText(message);
			}
		});
	}
	
	private void updateTemperatureText(final String message) {
		_handler.post(new Runnable() {
			@Override
			public void run() {
				_temperatureLabel.setText(message);
			}
		});
	}
	
	/** Redraws the graphs */
	private void redrawGraphs() {
		_handler.post(new Runnable() {
			@Override
			public void run() {
				_lineFollowPlot.redraw();
				_voltagePlot.redraw();
				_waveformPlot.redraw();
				_capacitancePlot.redraw();
				_temperaturePlot.redraw();
			}
		});
	}
	
	public View getView() {
		return _view;
	}
}
