package uy.edu.fing.chesstrack.modulovision;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import uy.edu.fing.chesstrack.ajedrez.Logica;
import uy.edu.fing.chesstrack.communication.Client;
import uy.edu.fing.chesstrack.modulomodelador.Modelador;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Environment;
import android.util.Log;

public class Manager {

	private static final String TAG = "CHESSTRACK::MANAGER";
	private static Manager _instance;
	private static final int ARMANDO_TABLERO = 0;
	private static final int JUGANDO = 1;
	private static final int OK = 1;
	private static final int NOT = 0;
	private static final String WELCOME_MSG = ""
			+ "--------------------------------------------------------------------------\n"
			+ "  .:: CHESSTRACK ::. seguimiento de una partida de Ajedrez\n"
			+ "\n"
			+ "                                                              TImag 2014\n"
			+ "                                           Nicolas Furquez - Aylen Ricca\n"
			+ "--------------------------------------------------------------------------\n";

	private static int _estado;
	private static int _salida;
	private static Adquisicion _adquisicion;
	private static Client _client;
	private static DetectorOclusion _detectorOclusion;
	private static Modelador _modelador;
	private static Logica _logica;
	private final boolean _debug;
	private int _cantJugada;

	protected Manager() {
		_estado = ARMANDO_TABLERO;
		_salida = NOT;
		_adquisicion = null;
		_client = null;
		_debug = false;
		_cantJugada = 0;
	}

	public static Manager getInstance() {
		if (_instance == null) {
			_instance = new Manager();
		}
		return _instance;
	}

	public static int get_estado() {
		return _estado;
	}

	public static void set_estado(int _estado) {
		Manager._estado = _estado;
	}

	public void setConnection(String ip, int port) {
		Log.i(TAG, "Setting connection");
		_client = Client.getInstance();
		_client.EstablishConnection(ip, port);
		_client.SendData(WELCOME_MSG);
		_salida = OK;
	}

	public boolean calibrar(Mat frame) {
		Log.i(TAG, "Calibrando");
		if (Calibracion.getInstance().calibrar(frame)) {
			ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM,
					50);
			toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200); // ms
			if (_salida == OK) {
				_client.SendData("FIN calibrar\n . . . armando tablero!\n");
			}
			try {
				_adquisicion = new Adquisicion();
				_modelador = new Modelador();
				_logica = new Logica();
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}
			return true;
		}
		Log.i(TAG, "No calibrado");
		ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 50);
		toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 700);
		return false;
	}

	public void iniciarJuego() {
		_estado = JUGANDO;
		// beep
		_detectorOclusion = new DetectorOclusion();
		ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 50);
		toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200); // ms

		if (_salida == OK) {
			Mat tableroInicio = _logica.getTableroInicio();
			_client.SendData("TableroINICIO!\n");
			_client.SendData(" ".concat(tableroInicio.dump().concat("\n")));
		}
	}

	public Mat processFrame(Mat inputFrame) {
		Log.i(TAG, "Acondicionamiento");
		Mat region = _adquisicion.processFrame(inputFrame);

		Log.i(TAG, "TYPE=" + (inputFrame.type() == CvType.CV_8UC4));
		Log.i(TAG, "CHANNEL=" + (inputFrame.channels() == 4));

		switch (_estado) {
		case ARMANDO_TABLERO:
			Log.i(TAG, "Armando Tablero");
			Mat nuevo = _modelador.getMatrizFichas(region);
			if (_logica.validarTableroArmado(nuevo)) {
				iniciarJuego();
			}
			break;
		case JUGANDO:
			Log.i(TAG, "Jugando");
			//if (_detectorOclusion.hayNuevoTableroValido(region)) {
				Log.i(TAG, "Tablero Valido");
				// llamar al modelador
				Mat aux = _modelador.getMatrizFichas(region);
				// Log.i(TAG, "MATRIZ=" + aux.dump());
				region = _modelador.dibujarEscaquesSobel(1);
				SaveImage(region);

				if (_logica.validarNuevoTablero(aux)) {
					if (_salida == OK) {
						_client.SendData("Nuevo Tablero Valido = ["
								+ String.valueOf(_cantJugada) + "]\n");
						_cantJugada++;
						_client.SendData(" ".concat(aux.dump().concat("\n")));
					}
				}
			//}
			break;
		}

		if (_debug) {
			Log.i(TAG, "DEBUG");
			Mat tmp = Mat.zeros(inputFrame.size(), CvType.CV_8UC4);
			Mat matTMP = tmp.submat(Calibracion.getRectROI());
			region.copyTo(matTMP);
			return tmp;
		}
		return inputFrame;
	}

	public void destroy() {
		if (_client != null) {
			_client.Stop();
		}
	}
	
	public void SaveImage (Mat mat) {
		   Mat mIntermediateMat = new Mat();
		   Imgproc.cvtColor(mat, mIntermediateMat, Imgproc.COLOR_RGBA2BGR, 3);

		   File path = new File(Environment.getExternalStorageDirectory() + "/DCIM/");
		   path.mkdirs();
		   String timeStamp = Integer.toString(_cantJugada++);
		   File file = new File(path, "image".concat(timeStamp).concat(".png"));
		   
		   String filename = file.toString();
		   Boolean bool = Highgui.imwrite(filename, mIntermediateMat);

		   if (bool)
		    Log.i(TAG, "SUCCESS writing image to external storage");
		   else
		    Log.i(TAG, "Fail writing image to external storage");
		}
}