package com.baselet.diagram;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;

import javax.swing.JEditorPane;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baselet.control.constants.SystemInfo;
import com.baselet.control.enums.Metakey;
import com.baselet.control.enums.Program;
import com.baselet.control.util.Utils;
import com.baselet.gui.CurrentGui;
import com.baselet.gui.listener.HyperLinkActiveListener;

public class StartUpHelpText extends JEditorPane implements ContainerListener, ComponentListener {

	private static final long serialVersionUID = 1L;

	static final Logger log = LoggerFactory.getLogger(StartUpHelpText.class);

	private DrawPanel panel;
	private boolean visible;

	public StartUpHelpText(DrawPanel panel) {
		super();
		this.panel = panel;

		// If the GUI is null (e.g.: if main is used in batch mode) the startup help text is not required
		if (CurrentGui.getInstance().getGui() == null) {
			return;
		}

		panel.addContainerListener(this);
		panel.addComponentListener(this);
		addMouseListener(new DelegatingMouseListener());
		try {
			if (UpdateCheckTimerTask.getInstance().getFilename() == null) {
				showHTML(createTempFileWithText(getDefaultTextWithReplacedSystemspecificMetakeys()));
			}
			else {
				showHTML(UpdateCheckTimerTask.getInstance().getFilename());
			}
		} catch (IOException e) {
			// #361: such an error should not crash UMLet, instead a simple information should be shown that something has gone wrong
			log.error("Cannot load startupinfo", e);
			setText("Cannot load startupinfo");
			setSize(130, 10);
		}
	}

	// Must be overwritten to hide the helptext if a the custom elements panel is toggled without elements on the drawpanel
	@Override
	public void setEnabled(boolean en) {
		super.setEnabled(en);
		if (en && visible) {
			if (panel.getGridElements().size() == 0) {
				setVisible(true);
			}
			else {
				visible = false;
			}
		}
		else {
			visible = isVisible();
			setVisible(false);
		}
	}

	static InputStream getStartUpFileName() {
		return StartUpHelpText.class.getClassLoader().getResourceAsStream("startuphelp.html");
	}

	private void showHTML(String filename) throws MalformedURLException, IOException {
		this.setPage(new URL("file:///" + filename));
		addHyperlinkListener(new HyperLinkActiveListener());
		setEditable(false);
		setBackground(Color.WHITE);
		setSelectionColor(getBackground());
		setSelectedTextColor(getForeground());
	}

	static String createTempFileWithText(String textToWriteIntoFile) throws IOException {
		File tempFile = File.createTempFile(Program.getInstance().getProgramName() + "_startupfile", ".html");
		tempFile.deleteOnExit();
		FileWriter w = new FileWriter(tempFile);
		w.write(textToWriteIntoFile);
		w.close();
		return tempFile.getAbsolutePath();
	}

	private static String getDefaultTextWithReplacedSystemspecificMetakeys() throws FileNotFoundException {
		StringBuilder sb = new StringBuilder("");
		Scanner sc = null;
		try {
			sc = new Scanner(getStartUpFileName());
			while (sc.hasNextLine()) {
				String line = sc.nextLine();
				if (SystemInfo.META_KEY == Metakey.CTRL) {
					line = line.replace(Metakey.CMD.toString(), Metakey.CTRL.toString());
				}
				else if (SystemInfo.META_KEY == Metakey.CMD) {
					line = line.replace(Metakey.CTRL.toString(), Metakey.CMD.toString());
				}
				sb.append(line).append("\n");
			}
		} finally {
			if (sc != null) {
				sc.close();
			}
		}
		return sb.toString();
	}

	@Override
	public void componentAdded(ContainerEvent e) {
		boolean gridElementAdded = panel.getElementToComponent(e.getChild()) != null;
		if (gridElementAdded) {
			setVisible(false);
		}
	}

	@Override
	public void componentRemoved(ContainerEvent e) {
		if (e.getContainer().getComponentCount() <= 1 && !equals(e.getChild())) {
			setVisible(true);
		}
	}

	@Override
	public void componentResized(ComponentEvent arg0) {
		Dimension size = panel.getSize();
		Dimension labelSize = getPreferredSize();
		this.setSize(labelSize);
		int minDistanceFromTop = 25;
		int labelSizeToSubtract = Math.max(150, labelSize.height); // the upper border of the startup panel is at least 200px over the middle of the screen (necessary to have a good position for small update info windows)
		this.setLocation(size.width / 2 - labelSize.width / 2, Math.max(minDistanceFromTop, size.height / 2 - labelSizeToSubtract));
	}

	@Override
	public void paint(Graphics g) {
		// Subpixel rendering must be disabled for the startuphelp (looks bad)
		((Graphics2D) g).setRenderingHints(Utils.getUxRenderingQualityHigh(false));
		super.paint(g);
		((Graphics2D) g).setRenderingHints(Utils.getUxRenderingQualityHigh(true));
	}

	@Override
	public void componentHidden(ComponentEvent arg0) {}

	@Override
	public void componentMoved(ComponentEvent arg0) {}

	@Override
	public void componentShown(ComponentEvent arg0) {}

	/**
	 * The MouseListener of this JEditorPane just delegates the
	 * MouseEvents up to the DiagramListener of the Handler
	 */
	private class DelegatingMouseListener implements MouseListener {

		@Override
		public void mouseClicked(MouseEvent e) {
			panel.getHandler().getListener().mouseClicked(e);
		}

		@Override
		public void mouseEntered(MouseEvent e) {
			panel.getHandler().getListener().mouseEntered(e);
		}

		@Override
		public void mouseExited(MouseEvent e) {
			panel.getHandler().getListener().mouseExited(e);
		}

		@Override
		public void mousePressed(MouseEvent e) {
			panel.getHandler().getListener().mousePressed(e);
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			panel.getHandler().getListener().mouseReleased(e);
		}
	}
}
