package de.lazyzero.NazeWiiConf.utils;

import static lu.tudor.santec.i18n.Translatrix._;

import java.io.IOException;
import java.util.Vector;
import java.util.logging.Level;

import de.lazyzero.NazeWiiConf.NazeWiiConf;
import de.lazyzero.NazeWiiConf.gui.NazeBaseConfPanel;
import de.lazyzero.NazeWiiConf.gui.NazeSettingsPanel;

public class NazeCommunicator extends Thread implements NazeListener{
	
	
	static String line;
	private NazeListener listener;
	private boolean hasInterrupted = false;
	private NazeConfiguration nazeConfiguration;
	private NazePort serialPort;
	private NazeBaseConfPanel nazeBaseConfPanel;
	private NazeSettingsPanel nazeSettingsPanel;
	private NazeWiiLogger logger;
	private static boolean isReadingSettings;
	
	public NazeCommunicator(NazeBaseConfPanel nazeBaseConfPanel, NazeSettingsPanel nazeSettingsPanel, NazeConfiguration nazeConfiguration, NazePort serialPort) {
		this.nazeBaseConfPanel = nazeBaseConfPanel;
		this.nazeSettingsPanel = nazeSettingsPanel;
		this.nazeConfiguration = nazeConfiguration;
		logger = NazeWiiConf.getInstance().getLogger();
		this.serialPort = serialPort;
	}

	public void run(){
		try {
			while ((line = serialPort.readLine()) != null && !isInterrupted()) { // while loop begins here
//				System.out.println("line: " + line);
				
				if (line.length() > 1) {
					listener.dataReceived(line);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
			
	public boolean isInterrupted() {
		return hasInterrupted;
	}

	
	
	
	
//	public static void main(String[] args) {
////		final SerialReader sr = new SerialReader(9600, "/dev/cu.usbserial-A700eC94");
//		NazeConfiguration nc = new NazeConfiguration();
//		NazePort np = new NazePort("/dev/cu.SLAB_USBtoUART", 115200);
//		
//		final NazeCommunicator sr = new NazeCommunicator(nc, np);
//		sr.setListener(sr);
//		
//		try {
//			np.openPort();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		
//		sr.start();
//		
//		sr.openCLI();
//		sr.readFeatureList();
//		sr.readMixerList();
//		sr.readMap();
//		sr.readSettings();
//		sr.readEnabledFeatures();
//		sr.readEnabledMixer();
//		sr.readStatus();
//		sr.readVersion();
//		
//		sr.writeDefaults();
//		
//		sr.closeCLI();
//		
//		try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		System.out.println(nc.toString());
//
//		while(true);
//	}
	
	public void readMixerList() {
		byte[] command = {'m', 'i', 'x', 'e', 'r', ' ', 'l', 'i', 's', 't', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void readEnabledMixer() {
		byte[] command = {'m', 'i', 'x', 'e', 'r', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void readMap() {
		byte[] command = {'m', 'a', 'p', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void readStatus() {
		byte[] command = {'s', 't', 'a', 't', 'u', 's', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void readVersion() {
		byte[] command = {'v', 'e', 'r', 's', 'i', 'o', 'n', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * reads the list of available features
	 */
	public void readFeatureList() {
		byte[] command = {'f', 'e', 'a', 't', 'u', 'r', 'e', ' ', 'l', 'i', 's', 't', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void readEnabledFeatures() {
		byte[] command = {'f', 'e', 'a', 't', 'u', 'r', 'e', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void readSettings() {
		byte[] command = {'s', 'e', 't', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void writeDefaults() {
		byte[] command = {'d', 'e', 'f', 'a', 'u', 'l', 't', 's', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	public void writeMixer(String name) {
		String mixer = "mixer " + name + '\n';
		byte[] command = mixer.getBytes();
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
		logger.log(Level.INFO, _("nazeCommunicator.saveMixer"), true);
	}

	public void writeFeature(String name) {
		String feature = "feature " + name + '\n';
		byte[] command = feature.getBytes();
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
		logger.log(Level.INFO, _("nazeCommunicator.saveFeature"), true);
	}
	
	public void writeMap(String mapping) {
		String map = "map " + mapping + '\n';
		byte[] command = map.getBytes();
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
		logger.log(Level.INFO, _("nazeCommunicator.saveMapping"), true);
	}
	
	public void writeSetting(String name, int value) {
		String setting = "set " + name + "=" + value + '\n';
		byte[] command = setting.getBytes();
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
		logger.log(Level.INFO, _("nazeCommunicator.saveSetting"), true);
	}


	
	public void openCLI() {

		byte[] command = { '#', '\n' };
		// int command = '#';
		try {
			serialPort.write(command);
			logger.log(Level.INFO, "open CLI");
		} catch (IOException e) {
			e.printStackTrace();
			logger.log(Level.WARNING, "open CLI failed");
			return;
		}

		System.out.println("stop");
	}

	public void closeCLI() {
		byte[] command = {'e', 'x', 'i', 't', '\n'};
		try {
			serialPort.write(command);
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}

	
	public NazeListener getListener() {
		return listener;
	}

	public void setListener(NazeListener listener) {
		this.listener = listener;
	}
	
	@Override
	public void dataReceived(String answer) {
		System.out.println(answer);
		if (answer.contains("Entering CLI Mode")){
			System.out.println("CLI opened!");
			
		} else if (answer.contains("Saving")) {
			System.out.println("CLI closed!");
		} else if (answer.contains("Available features")) {
			Vector<String> features = new Vector<String>();
			features.removeAllElements();
			answer = answer.replaceFirst("Available features:", "").trim();
			String[] answers = answer.split(" ");
			for (String feature : answers) {
				features.add(feature);
			}
			nazeConfiguration.setFeatures(features);
			nazeBaseConfPanel.updateFeatures();
		} else if (answer.contains("Available mixers")) {
			Vector<String> mixers = new Vector<String>();
			mixers.removeAllElements();
			answer = answer.replaceFirst("Available mixers:", "").trim();
			String[] answers = answer.split(" ");
			for (String mixer : answers) {
				mixers.add(mixer);
			}
			nazeConfiguration.setMixers(mixers);
			nazeBaseConfPanel.updateMixers();
		} else if (answer.contains("Current settings:")) {
			isReadingSettings = true;
		} else if (answer.contains("#")) {
			if (isReadingSettings) {
				isReadingSettings = false;
				nazeSettingsPanel.updateSettings();
			}
		} else if (answer.contains("=")) {
			String[] set = answer.split("=");
			nazeConfiguration.getSettings().put(set[0].trim(), Integer.parseInt(set[1].trim()));
//			System.out.println("setting: " + set[0].trim() + "=" + nazeConfiguration.getSettings().get(set[0].trim()));
		} else if (answer.contains("Current assignment")) {
			answer = answer.replaceFirst("Current assignment:", "").trim();
			nazeConfiguration.setMap(answer);
			nazeBaseConfPanel.updateMap();
		} else if (answer.contains("Enabled features")) {
			Vector<String> features = new Vector<String>();
			features.removeAllElements();
			answer = answer.replaceFirst("Enabled features:", "").trim();
			String[] answers = answer.split(" ");
			for (String feature : answers) {
				features.add(feature);
			}
			nazeConfiguration.setEnabledFeatures(features);
			nazeBaseConfPanel.updateEnabledFeatures();
		} else  if (answer.contains("Current mixer")) {
			answer = answer.replaceFirst("Current mixer:", "").trim();
			nazeConfiguration.setEnabledMixer(answer);
			nazeBaseConfPanel.updateSelectedMixer();
			/*
			 * System Uptime: 334 seconds, Voltage: 0 * 0.1V (2S battery)
 			 * Detected sensors: ACC BARO MAG   ACCHW: MMA845x
			 * Cycle Time: 1518, I2C Errors: 0
			 */
		} else if (answer.contains("System Uptime")) {
			String uptime = answer;
			String voltage = answer;
			
			uptime = uptime.replaceFirst("System Uptime:", "").trim();
			int i = uptime.indexOf("seconds");
			uptime = uptime.substring(0, i).trim();
			nazeConfiguration.setUptime(Integer.parseInt(uptime));
			
			int j = voltage.indexOf("Voltage");
			voltage = voltage.substring(j+8).trim();
			nazeConfiguration.setVoltage(voltage);
			nazeBaseConfPanel.updateStatus();
		} else 	if (answer.contains("Detected sensors")) {
			String sensors = answer;
			String acchw = answer;
			
			Vector<String> sensorsList = new Vector<String>();
			sensorsList.removeAllElements();
			sensors = sensors.replaceFirst("Detected sensors:", "");
			int i = sensors.indexOf("  ");
			sensors = sensors.substring(0, i).trim();
			String[] sensorsAvailable = sensors.split(" ");
			for (String sensorAvailable : sensorsAvailable) {
				sensorsList.add(sensorAvailable);
			}
			nazeConfiguration.setAvailableSensors(sensorsList);

			int j = acchw.indexOf("ACCHW");
			acchw = acchw.substring(j+6).trim();
			nazeConfiguration.setAccHardware(acchw);
			nazeBaseConfPanel.updateStatus();
		} else if (answer.contains("Cycle Time")) {
			String cycle = answer;
			String errors = answer;
			
			cycle = cycle.replaceFirst("Cycle Time:", "").trim();
			int i = cycle.indexOf("I2C");
			cycle = cycle.substring(0, i-2).trim();
			nazeConfiguration.setCycleTime(Integer.parseInt(cycle));
			
			int j = errors.indexOf("I2C Errors:");
			errors = errors.substring(j+11).trim();
			nazeConfiguration.setI2cErrors(Integer.parseInt(errors));
			nazeBaseConfPanel.updateStatus();
		} else if (answer.contains("Resetting to defaults")) {
			System.out.println("Reset Naze to defaults!");
		} else if (answer.contains("version")) {
			answer = answer.replaceFirst("Version:", "").trim();
			nazeConfiguration.setVersion(answer);
			nazeBaseConfPanel.updateVersion();
		} else if (answer.contains("Rebooting")) {
			logger.log(Level.INFO, _("nazeCommunicator.reboot"), true);
		} else {
			System.out.println("answer: " + answer);
		}
	}

}
