package meerkat.voting.gui.panels.select_candidate_by_picture;

import com.google.common.util.concurrent.FutureCallback;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import meerkat.protobuf.BallotQuestionUiElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;


/**
 * Created by Vladimir Eliezer Tokarev on 10/3/2016.
 * This object updates the visual representations of the voters binaryDatas
 */
class PicturesAnswersUpdater implements EventHandler{

    private final Logger logger = LoggerFactory.getLogger(PicturesAnswersUpdater.class);

    private Stage currentStage;
    private int columIndex;
    private List<BallotQuestionUiElement.UIAnswer> allAvailableAnswers;
    private FutureCallback<BallotQuestionUiElement.UIAnswer> imageUpdate;

    PicturesAnswersUpdater(Stage primaryStage) {
        this.currentStage = primaryStage;
        this.columIndex = 0;
        // The lookup works only after the css have been randered
        this.currentStage.getScene().getRoot().applyCss();
        this.allAvailableAnswers = new ArrayList<>();
        this.logger.debug("Created pictures answers updater.");
    }

    /**
     * Sets the call back object which will be called every time the voter choose different candidate picture
     * @param imageUpdate the callback object itself
     */
    public void SetImageUpdate(FutureCallback<BallotQuestionUiElement.UIAnswer> imageUpdate){
        this.imageUpdate = imageUpdate;
    }

    /**
     * Gets all the binaryDatas from the ballot ui question and puts them into the binaryDatas container
     *
     * @param question the ballot question that contains all the pictures that are the answers
     */
    void UpdateAnswers(BallotQuestionUiElement.BallotQuestionUIElement question) {
        this.RemoveAllAnswers();
        List<BallotQuestionUiElement.UIAnswer> answers = new ArrayList<>(question.getAnswers().getAnswers().getAnswersList());

        if (question.getRandomizeListOrder()) {
            Collections.shuffle(answers);
        }
        for (BallotQuestionUiElement.UIAnswer answer: answers){
            try {
                this.allAvailableAnswers.add(answer);
                this.AddAnswer(answer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.currentStage.show();
        this.logger.debug("Updated the all the pictures answers.");
    }

    /**
     * Gets the container of the binaryDatas
     *
     * @return GridPane object
     */
    private GridPane GetAnswersContainer() {
        return (GridPane) this.currentStage.getScene().lookup("#AnswersGridPane");
    }

    /**
     * Remove all previous binaryDatas from the container
     */
    private void RemoveAllAnswers() {
        this.GetAnswersContainer().getChildren().remove(0, this.GetAnswersContainer().getChildren().size());
        this.logger.debug("Removed all the current answers.");
    }

    /**
     * Creates binaryData element which is grid pane with the binaryData and check box
     *
     * @param answer object which have the answer and its description
     * @param location the location of the picture
     * @return GridPane which contains string and check box
     */
    private GridPane GetAnswerElement(BallotQuestionUiElement.UIAnswer answer, int location) throws IOException {
        GridPane gridPane = new GridPane();

        BufferedImage bufferedImage = ImageIO.read(answer.getAnswer().newInput());
        Image image = SwingFXUtils.toFXImage(bufferedImage, null);

        ImageView imageView = new ImageView();
        imageView.setImage(image);

        Label description = new Label(answer.getDescription());
        BorderPane descriptionBorderPane = new BorderPane();
        descriptionBorderPane.setCenter(description);

        BorderPane borderPane = new BorderPane();
        CheckBox checkBox = new CheckBox();
        checkBox.setId(location+"-checkbox");
        checkBox.setOnAction(this);
        borderPane.setCenter(checkBox);

        gridPane.add(imageView, 2 , 1);
        gridPane.add(descriptionBorderPane, 2, 2);
        gridPane.add(borderPane, 2, 3);

        gridPane.setPrefSize(100, 100);
        gridPane.setPadding(new Insets(10));

        this.logger.debug("Wraped the given picrute in grid panel and returens it.");
        return gridPane;
    }

    /**
     * Adds the GridPane binaryData to the panel
     *
     * @param answer the binaryData string to represent to the user
     */
    private void AddAnswer(BallotQuestionUiElement.UIAnswer answer) throws IOException {
        GridPane container = this.GetAnswersContainer();

        this.columIndex++;
        GridPane newAnswer = this.GetAnswerElement(answer, this.columIndex);
        container.addColumn(1);

        container.add(newAnswer, this.columIndex, 0);
        this.currentStage.show();
        this.logger.debug("Added the answer picture to the answers grid pane.");
    }

    /**
     * Unchecks all  the check boxes that are not target box
     * @param target
     */
    private void uncheckBoxes(CheckBox target){
        GridPane answersContainer = this.GetAnswersContainer();
        for (Node child : answersContainer.getChildren()){
            GridPane answer = (GridPane)child;
            BorderPane  borderPane = (BorderPane) answer.getChildren().get(2);
            CheckBox checkBox = (CheckBox)borderPane.getCenter();
            if (!Objects.equals(checkBox.getId(), target.getId()) && checkBox.isSelected()){
                checkBox.fire();
            }
        }
        this.logger.debug("Unchecked all the answers that the voter hasnt selected.");
    }

    @Override
    /**
     * Saves the user chose
     */
    public void handle(Event event) {
        if (event.getSource() instanceof CheckBox) {
            CheckBox target = ((CheckBox)event.getSource());

            if (target.isSelected()) {
                String answerIndex = target.getId().split("-")[0];
                System.out.println(answerIndex);
                this.imageUpdate.onSuccess(this.allAvailableAnswers.get(Integer.parseInt(answerIndex) - 1));
                this.uncheckBoxes(target);
            }
        }
    }

}
