/* Copyright (c) 2017 Christopher Cromer
 * Copyright (c) 2017 Carlos Faúndez
 *
 * This file is part of mt. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution.
 * This file may not be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file.
 */

package cl.cromer.mt;

import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 * Controlar las acciones de reconocimiento individual
 */
public class IndividualController extends VBox {
	/**
	 * El contenido de la venta
	 */
	@FXML
	private VBox contenido;

	/**
	 * La cadena que ingresa el usuario
	 */
	@FXML
	private TextField cadena;

	/**
	 * La cinta en la pantalla
	 */
	@FXML
	private HBox cinta;

	/**
	 * El boton de acapter cadena
	 */
	@FXML
	private Button aceptar;

	/**
	 * El boton que corre paso a paso
	 */
	@FXML
	private Button paso;

	/**
	 * La descripcion de que hace la maquina
	 */
	@FXML
	private Text descripcion;

	/**
	 * La cadena acapatada por el usario
	 */
	private String cadenaAceptada;

	/**
	 * Los estados finales que viene de la ventana anterior
	 */
	private EstadosFinales estadosFinales;

	/**
	 * La maquina turning pasado para correr
	 */
	private Maquina maquina;

	/**
	 * Donde estaba el cabezal anteriormente
	 */
	private int cabezalAnterior;

	/**
	 * La cantidad de cajas que está en la pantalla
	 */
	private int cajas;

	/**
	 * El numero qx del estado anterior
	 */
	private int estadoPrevio;

	/**
	 * El simbolo que lee antes que la maquina escribe
	 */
	private char simboloAnterior;

	/**
	 * Si debe mover o si debe mostrar lo que lee y escribe
	 */
	private boolean mover;

	/**
	 * Este metodo se crea una caja para poner un simbolo de la cinta
	 *
	 * @param label El label para encontrar la caja despues
	 * @param texto El simbolo de la cinta
	 *
	 * @return Retorna un StackPane que contiene la caja
	 */
	private static StackPane crearCaja(String label, String texto) {
		Rectangle rectangle = new Rectangle();
		rectangle.setHeight(20);
		rectangle.setWidth(20);
		rectangle.setFill(Color.WHITE);
		rectangle.setStroke(Color.BLACK);
		rectangle.setId("caja_" + label);
		Text text = new Text();
		text.setId("simbolo_" + label);
		text.setFill(Color.BLACK);
		text.setText(texto);

		StackPane stackPane = new StackPane();
		stackPane.getChildren().addAll(rectangle, text);
		return stackPane;
	}

	/**
	 * Boton de aceptar cadena
	 */
	@FXML
	protected void aceptarCadena() {
		Scene scene = contenido.getScene();
		estadosFinales = (EstadosFinales) scene.getUserData();
		maquina = estadosFinales.getMaquina();
		maquina.reset();
		cadenaAceptada = cadena.getText();
		StringBuilder temp = new StringBuilder(cadenaAceptada);
		temp.insert(0, "#");
		temp.insert(cadenaAceptada.length() + 1, "#");
		cadenaAceptada = temp.toString();
		cinta.getChildren().clear();
		for (int i = 0; i < cadenaAceptada.length(); i++) {
			cinta.getChildren().add(crearCaja(String.valueOf(i), String.valueOf(cadenaAceptada.charAt(i))));
			cajas = i + 1;
		}
		Rectangle rectangle = (Rectangle) scene.lookup("#caja_1");
		rectangle.setFill(Color.BLUE);
		Text simbolo = (Text) scene.lookup("#simbolo_1");
		simbolo.setFill(Color.WHITE);

		cadena.setText("");
		cadena.setDisable(true);
		aceptar.setDisable(true);
		paso.setDisable(false);
		cabezalAnterior = 1;
		estadoPrevio = 0;
		mover = false;
		simboloAnterior = '\0';

		descripcion.setText("Inicio en estado q" + maquina.getEstadoActual().getQ());
	}

	/**
	 * Boton de cerrar
	 */
	@FXML
	protected void paso() {
		Scene scene = contenido.getScene();

		int resultado = 0;
		if (!mover) {
			resultado = maquina.comprobarCadenaS2S(new StringBuilder(cadenaAceptada), estadosFinales.getEstadosElegidos().stream().mapToInt(i -> i).toArray());
		}

		if (resultado == 1) {
			MT.mostrarMensaje("Resultado", "La cadena fue aceptada!");
			cadena.setDisable(false);
			aceptar.setDisable(false);
			paso.setDisable(true);
			maquina.reset();
		}
		else if (resultado == -1) {
			MT.mostrarMensaje("Resultado", "La cadena fue rechazada!");
			cadena.setDisable(false);
			aceptar.setDisable(false);
			paso.setDisable(true);
			maquina.reset();
		}
		else {
			if (maquina.getCintaAnterior().length() > cajas) {
				for (int i = cajas; i < maquina.getCintaAnterior().length(); i++) {
					cinta.getChildren().add(crearCaja(String.valueOf(i), String.valueOf(maquina.getCintaAnterior().charAt(i))));
				}
			}

			for (int i = 0; i < maquina.getCintaAnterior().length(); i++) {
				Text simbolo = (Text) scene.lookup("#simbolo_" + i);
				if (i == maquina.getCabezal() && (mover || simboloAnterior == '\0')) {
					simboloAnterior = simbolo.getText().charAt(0);
				}
				simbolo.setText(String.valueOf(maquina.getCintaAnterior().charAt(i)));
			}

			if (mover) {
				String move;
				switch (maquina.getEnlaceActual().getMovimiento()) {
					case 'L': {
						move = "se movio a la izquierda";
						break;
					}
					case 'R': {
						move = "se movio a la derecha";
						break;
					}
					default: {
						move = "no se movio";
						break;
					}
				}
				descripcion.setText("La cinta " + move + "\nCambia del estado q" + estadoPrevio + " al estado q" + maquina.getEstadoActual().getQ());

				// Undo cabezel anterior
				Rectangle rectangle = (Rectangle) scene.lookup("#caja_" + cabezalAnterior);
				rectangle.setFill(Color.WHITE);
				Text simbolo = (Text) scene.lookup("#simbolo_" + cabezalAnterior);
				simbolo.setFill(Color.BLACK);

				// Cabezel
				rectangle = (Rectangle) scene.lookup("#caja_" + maquina.getCabezal());
				rectangle.setFill(Color.BLUE);
				simbolo = (Text) scene.lookup("#simbolo_" + maquina.getCabezal());
				simbolo.setFill(Color.WHITE);

				cabezalAnterior = maquina.getCabezal();
				estadoPrevio = maquina.getEstadoActual().getQ();
				mover = false;
			}
			else {
				Text simbolo = (Text) scene.lookup("#simbolo_" + cabezalAnterior);
				descripcion.setText("Se leyo el simbolo \"" + simboloAnterior + "\" y se escribio el simbolo \"" + simbolo.getText() + "\"");
				mover = true;
			}
		}
	}

	/**
	 * Boton de cerrar
	 */
	@FXML
	protected void cerrar() {
		Scene scene = contenido.getScene();
		Stage stage = (Stage) scene.getWindow();
		stage.close();
	}
}
