package xyz.thastertyn.UserInterface.Listeners;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.naming.ConfigurationException;

import com.googlecode.lanterna.TerminalPosition;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.gui2.Borders;
import com.googlecode.lanterna.gui2.Direction;
import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.Window;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import com.googlecode.lanterna.gui2.WindowListener;
import com.googlecode.lanterna.gui2.dialogs.MessageDialog;
import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton;
import com.googlecode.lanterna.input.KeyStroke;
import com.googlecode.lanterna.input.KeyType;

import xyz.thastertyn.Config.Config;
import xyz.thastertyn.UserInterface.Content.AbsenceList;
import xyz.thastertyn.UserInterface.Content.JecnaContent;
import xyz.thastertyn.UserInterface.Content.Marks;
import xyz.thastertyn.UserInterface.Content.Reports;
import xyz.thastertyn.UserInterface.Content.Timetable;
import xyz.thastertyn.UserInterface.Dialogs.EscapeDialog;
import xyz.thastertyn.UserInterface.Dialogs.HelpDialog;

/**
 * Holds all the content displayables and moves between them when needed on tab, or shift tab press
 */
// The biggest and greatest. 
public class WindowSwitchListener implements WindowListener, UpdateListener, ContentResetListener {
	private WindowBasedTextGUI textGUI;

	private JecnaContent[] contents = {
		new Timetable(this),
		new Marks(this), // This being first doesn't resize properly for some reason
		new Reports(this),
		new AbsenceList(this)
	};

	private Label[] tabs = new Label[contents.length];

	private Panel tabsPanel = new Panel(new LinearLayout(Direction.HORIZONTAL));
	private Panel holderPanel = new Panel();

	int current = contents.length - 1;

	public WindowSwitchListener(Panel holder, WindowBasedTextGUI textGUI)
	{
		this.textGUI = textGUI;
		holder.addComponent(tabsPanel);
		holder.addComponent(holderPanel.withBorder(Borders.singleLine()));

		for(int i = 0; i < contents.length; i++)
		{
			this.tabs[i] = contents[i].getLabel();
			tabsPanel.addComponent(this.tabs[i]);
		}

		next();
		showStartHelp();
	}

	private void showStartHelp()
	{
		Config config = Config.getInstance();


		boolean showDialog = true;
		try {
			String value = config.getConfig("dont_show_help_again");

			if(value.equals("true"))
			{
				showDialog = false;
			}

		} catch (ConfigurationException e) {
			e.printStackTrace();
		}

		if(showDialog)
		{
			HelpDialog dialog = new HelpDialog(true);

			Boolean dontShowDialog = dialog.showDialog(textGUI);

			if(dontShowDialog)
			{
				config.addConfig("dont_show_help_again", dontShowDialog.toString());
				
				if(!config.writeConfig())
				{
					showException("Chyba ulozeni", "Nepodarilo se ulozit udaje");
				}
			}
		}
	}

	private void next()
	{
		if(current + 1 == contents.length)
		{
			current = 0;
		}else{
			current++;
		}
		
		loadPanel();
	}

	private void previous()
	{
		if(current - 1 == -1)
		{
			current = contents.length - 1;
		}else{
			current--;
		}
		loadPanel();
	}

	private void loadPanel()
	{
		checkIfDownloaded();

		holderPanel.removeAllComponents();
		tabsPanel.removeAllComponents();

		setPanelPreferedSize();
		updateLabels();
	}

	private void checkIfDownloaded()
	{
		if(!contents[current].hasStarted())
		{
			try{
				contents[current].downloadDefault();
			}catch(IOException e)
			{
				showException("Neco se nepovedlo", e.getLocalizedMessage());
			}
		}
	}

	/**
	 * If a panel is smaller than the bar with labels, make it at least the bar size
	 */
	private void setPanelPreferedSize()
	{
		contents[current].getPanel().setSize(contents[current].getPanel().calculatePreferredSize()); // Fix for reports not being big enough

		int labelTabColumnSize = tabsPanel
			.getSize()
			.getColumns();

		int currentPanelColumnSize = contents[current]
			.getPanel()
			.getSize()
			.getColumns();

		if(currentPanelColumnSize < labelTabColumnSize)
		{
			int currentPanelRowSize = contents[current].getPanel().getPreferredSize().getRows();
			holderPanel.addComponent(
				contents[current]
					.getPanel()
					.setPreferredSize(new TerminalSize(
										labelTabColumnSize,
										currentPanelRowSize))); // Pretty janky, but basically just create a new TerminalSize with height the same and the width of label bar
			return;
		}

		holderPanel.addComponent(contents[current].getPanel());
	}

	/**
	 * Gets all labels again and properly sets their borders to single or double depending on {@link #current}
	 */
	private void updateLabels()
	{
		for(int i = 0; i < tabs.length; i++)
		{
			if(i == current)
			{
				tabsPanel.addComponent(tabs[i].withBorder(Borders.doubleLine()));
			}else{
				tabsPanel.addComponent(tabs[i].withBorder(Borders.singleLine()));
			}
		}
	}

	/**
	 * Calls the {@link #current}'s showOptions with a textGui
	 */
	private void showOptions()
	{
		try{
			contents[current].showOptions(textGUI);
		}catch(IOException e)
		{
			showException("Neco se nepovedlo", "Naskytl problem s pripojenim. Bud neni zadne, nebo prilis pomale.");
		}
	}

	@Override
	public void onInput(Window basePane, KeyStroke keyStroke, AtomicBoolean deliverEvent) {
		KeyType type = keyStroke.getKeyType();

		switch(type)
		{
			case Tab:
				next();
				break;
			case ReverseTab: // Shift + Tab
				previous();
				break;
			case Character:
				if(keyStroke.getCharacter() == ' ') // Space
				{
					showOptions();
				}
				break;
			case Escape:
				EscapeDialog dialog = new EscapeDialog(textGUI, this);
				dialog.showDialog(textGUI);
				break;
			case F1:
				HelpDialog helpDialog = new HelpDialog(false);
				helpDialog.showDialog(textGUI);
				break;
			default:
				break;
		}
	}

	@Override
	public void onUnhandledInput(Window basePane, KeyStroke keyStroke, AtomicBoolean hasBeenHandled) {
		hasBeenHandled.set(true);
	}

	@Override
	public void onResized(Window window, TerminalSize oldSize, TerminalSize newSize) {
		window.invalidate();
	}

	@Override
	public void onMoved(Window window, TerminalPosition oldPosition, TerminalPosition newPosition) {
		window.invalidate();
	}

	/**
	 * Force a full redraw, usefull when a change via logout or {@link xyz.thastertyn.Types.Option} is used
	 */
	@Override
	public void updatePanel() {
		holderPanel.removeAllComponents();
		setPanelPreferedSize();
		holderPanel.addComponent(contents[current].getPanel());
	}

	private void showException(String title, String text)
	{
		MessageDialog.showMessageDialog(textGUI, title, text, MessageDialogButton.OK);
	}

	/**
	 * On user change should wipe everything
	 */
	@Override
	public void reset()
	{
		contents = new JecnaContent[] {
			new Timetable(this),
			new Marks(this),
			new Reports(this),
			new AbsenceList(this)
		};
		loadPanel();
	}
}
