package com.madeorsk.smartnotes;

import java.util.HashMap;
import java.util.Map;

import javafx.animation.FadeTransition;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.Duration;

public class ListBox extends ScrollPane
{
	private boolean editable;

	private VBox main;
	private VBox listContainer;

	private Runnable listChangeListener;

	public ListBox(boolean editable)
	{
		this.editable = editable;

		this.setFitToHeight(true);
		this.setFitToWidth(true);

		this.main = new VBox();
		this.main.setPadding(new Insets(0, 15, 0, 15));
		this.listContainer = new VBox();
		this.main.getChildren().add(this.listContainer);

		if (this.editable)
		{
			final HBox addListItemBox = new HBox();
			{
				addListItemBox.getChildren().add(new ImageView(new Image("/com/madeorsk/smartnotes/res/AddCheckbox.png")));
				Label addListItemLabel = new Label("Add a new item");
				addListItemLabel.setPadding(new Insets(0, 0, 0, 13));
				addListItemLabel.setId("text");
				addListItemBox.getChildren().add(addListItemLabel);
				addListItemBox.setAlignment(Pos.CENTER_LEFT);
				addListItemBox.setCursor(Cursor.HAND);
				// Fade and opacity
				addListItemBox.setOpacity(0.4);
				addListItemBox.setOnMouseEntered((MouseEvent e) -> {
					FadeTransition transition = new FadeTransition(Duration.millis(200), addListItemBox);
					transition.setFromValue(0.4);
					transition.setToValue(1.0);
					transition.play();
				});
				addListItemBox.setOnMouseExited((MouseEvent e) -> {
					FadeTransition transition = new FadeTransition(Duration.millis(200), addListItemBox);
					transition.setFromValue(1.0);
					transition.setToValue(0.4);
					transition.play();
				});
				addListItemBox.setOnMouseClicked((MouseEvent e) -> {
					ListBox.this.listContainer.getChildren().add(new ListBoxItem("", ListBox.this.editable));
				});
			}
			this.main.getChildren().add(addListItemBox);
		}

		this.setContent(this.main);
	}

	public void updateList(Map<String, Boolean> content)
	{
		this.listContainer.getChildren().clear();
		for (String item : content.keySet())
			this.listContainer.getChildren().add(new ListBoxItem(item, this.editable).setChecked(content.get(item).booleanValue()));
	}

	public void setListChangeListener(Runnable listener)
	{
		this.listChangeListener = listener;
	}

	public Map<String, Boolean> getList()
	{
		Map<String, Boolean> list = new HashMap<String, Boolean>();
		for (Node child : this.listContainer.getChildren())
		{
			ListBoxItem item = (ListBoxItem) child;
			if (item.getText() != null && !item.getText().isEmpty())
				list.put(item.getText(), item.isChecked());
		}
		return list;
	}

	private class ListBoxItem extends HBox
	{
		private ListCheckbox checkbox;
		private TextField field;

		public ListBoxItem(String text, boolean editable)
		{
			ChangeListener<Object> change = (ObservableValue<? extends Object> ov, Object oldValue, Object newValue) -> {
				if (ListBox.this.listChangeListener != null)
					ListBox.this.listChangeListener.run();
			};
			this.checkbox = new ListCheckbox();
			this.checkbox.checkedProperty().addListener(change);
			this.getChildren().add(this.checkbox);
			this.field = new TextField(text);
			this.field.setId("text");
			this.field.setEditable(editable);
			this.field.prefWidthProperty().bind(ListBox.this.listContainer.widthProperty().subtract(this.checkbox.widthProperty()));
			if (editable)
				this.field.textProperty().addListener(change);
			else
			{
				this.field.setCursor(Cursor.HAND);
				this.field.setOnMouseClicked((MouseEvent e) -> {
					ListBoxItem.this.setChecked(!ListBoxItem.this.isChecked());
				});
			}
			this.getChildren().add(this.field);
		}

		public String getText()
		{
			return this.field.getText();
		}

		public ListBoxItem setChecked(boolean checked)
		{
			this.checkbox.setChecked(checked);
			return this;
		}

		public boolean isChecked()
		{
			return this.checkbox.isChecked();
		}

		private class ListCheckbox extends VBox
		{
			private BooleanProperty checked = new SimpleBooleanProperty();

			public ListCheckbox()
			{
				this.setId("imageButton");
				this.setAlignment(Pos.CENTER);
				this.setCursor(Cursor.HAND);
				this.getChildren().add(new ImageView(new Image("/com/madeorsk/smartnotes/res/Checkbox-unchecked.png")));

				this.setOnMouseClicked((MouseEvent e) -> {
					if (ListCheckbox.this.isChecked())
						ListCheckbox.this.setChecked(false);
					else
						ListCheckbox.this.setChecked(true);
				});
			}

			public void setChecked(boolean checked)
			{
				this.checked.set(checked);
				ListCheckbox.this.getChildren().clear();
				if (checked)
					ListCheckbox.this.getChildren().add(new ImageView(new Image("/com/madeorsk/smartnotes/res/Checkbox-checked.png")));
				else
					ListCheckbox.this.getChildren().add(new ImageView(new Image("/com/madeorsk/smartnotes/res/Checkbox-unchecked.png")));
			}

			public ObservableBooleanValue checkedProperty()
			{
				return this.checked;
			}

			public boolean isChecked()
			{
				return this.checked.get();
			}
		}
	}
}
