package meerkat.voting.gui.panels.select_candidate_name;

import com.google.common.util.concurrent.FutureCallback;
import javafx.event.Event;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import meerkat.protobuf.BallotQuestionUiElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;


/**
 * Created by Vladimir Eliezer Tokarev on 10/2/2016.
 * This object gets the current stage and appends to the container of the names
 * the different names that there are in the config object and saves the use answer
 */
class StringsAnswersUpdater implements javafx.event.EventHandler{

    private final Logger logger = LoggerFactory.getLogger(StringsAnswersUpdater.class);
    private Stage currentStage;
    private int rowAmount;
    private FutureCallback<String> updateAnswer;

    StringsAnswersUpdater(Stage primaryStage) {
        this.currentStage = primaryStage;
        this.rowAmount = 0;
        // The lookup works only after the css have been randered
        this.currentStage.getScene().getRoot().applyCss();
        this.logger.debug("Created new StringsAnswersUpdater object.");
    }

    /**
     * The update answers method will be called every time the user select different answer
     * @param updateAnswer the method that will get the new answer every time
     */
    public void SetUpdateAnswers(FutureCallback<String> updateAnswer){
        this.updateAnswer = updateAnswer;
    }

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

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

    /**
     * Creates answer element which is grid pane with the answer and check box
     * @param answer string answer to show to the voter
     * @return GridPane which contains string and check box
     */
    private GridPane GetAnswerElement(String answer){
        GridPane gridPane = new GridPane();

        Label label = new Label();
        label.setText(answer);
        label.setPrefSize(550, 30);
        GridPane.setConstraints(label, 1, 1);

        CheckBox checkBox = new CheckBox();
        checkBox.setId(answer+"-checkBox");
        checkBox.setOnAction(this);
        GridPane.setConstraints(checkBox, 10, 1);

        gridPane.getChildren().addAll(label, checkBox);
        this.logger.debug("Wraped answer (" + answer + " ) in answer element and returned it.");
        return  gridPane;
    }

    /**
     * Adds the GridPane answer to the panel
     * @param answer is the answer string to represent to the user
     */
    private void AddAnswer(String answer){
        GridPane container = this.GetAnswersContainer();

        GridPane newAnswer = this.GetAnswerElement(answer);
        container.addRow(0);

        this.rowAmount++;
        container.add(newAnswer, 0, this.rowAmount);
        this.logger.debug("Added " + answer + " to all answers");
    }

    /**
     * Gets all the answers from the ballot ui question and puts them into the answers container
     * Checks if the answers should be randomized, if they are then randomize them
     * @param question the questions that have all the information to be reporesneted
     */
    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){
            this.AddAnswer(answer.getAnswer().toStringUtf8());
        }
        this.currentStage.show();
        this.logger.debug("Removed all the old answers and add all the news ones.");
    }

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

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

            if (target.isSelected()) {
                String answer = target.getId().split("-")[0];
                this.updateAnswer.onSuccess(answer);
                this.uncheckBoxes(target);
            }
        }
    }

}
