content: /**
   * Copyright 2020 Alexander Herzog
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package ui.tutorial;
  
  import java.awt.BorderLayout;
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.Insets;
  import java.awt.Point;
  import java.awt.Toolkit;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.io.Serializable;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Timer;
  import java.util.TimerTask;
  
  import javax.swing.JFrame;
  import javax.swing.WindowConstants;
  import javax.swing.text.Document;
  import javax.swing.text.Element;
  import javax.swing.text.html.HTMLDocument;
  import javax.swing.text.html.StyleSheet;
  
  import language.Language;
  import systemtools.help.HTMLBrowser;
  import systemtools.help.HTMLBrowserPanel;
  import systemtools.help.HelpBase;
  import ui.MainPanel;
  import ui.help.BookData;
  import ui.tools.FlatLaFHelper;
  import ui.tutorial.pages.PageAddDispose;
  import ui.tutorial.pages.PageAddProcess;
  import ui.tutorial.pages.PageAddSource;
  import ui.tutorial.pages.PageCloseConnect;
  import ui.tutorial.pages.PageConnect1;
  import ui.tutorial.pages.PageConnect2;
  import ui.tutorial.pages.PageDone;
  import ui.tutorial.pages.PageOpenConnect;
  import ui.tutorial.pages.PageOpenTemplates;
  import ui.tutorial.pages.PageSetupModel;
  import ui.tutorial.pages.PageSetupProcess;
  import ui.tutorial.pages.PageSetupSource;
  import ui.tutorial.pages.PageStart;
  
  /**
   * Dieses Fenster fgt sich selbst neben dem Hauptfenster ein und zeigt ein
   * interaktives Tutorial an. Es muss dafr mit dem <code>MainPanel</code>
   * verknpft werden.
   * @author Alexander Herzog
   * @see MainPanel
   */
  public class TutorialWindow extends JFrame {
  	/**
  	 * Serialisierungs-ID der Klasse
  	 * @see Serializable
  	 */
  	private static final long serialVersionUID = -2770321276617641597L;
  
  	/** Programm-<code>MainPanel</code> mit dem das interaktive Tutorial zusammenarbeiten soll. */
  	private final MainPanel mainPanel;
  	/** Fenster in dem sich das {@link #mainPanel} befindet */
  	private final JFrame mainFrame;
  	/** Position des Hauptfensters vor dem Aufruf des Tutorial-Fensters */
  	private Point saveMainFrameLocation;
  	/** Gre des Hauptfensters vor dem Aufruf des Tutorial-Fensters */
  	private Dimension saveMainFrameSize;
  
  	/** Aktuelle Sprache */
  	private final String language;
  	/** Aktuelle Tutorial-Seite */
  	private TutorialPage page=null;
  	/** Liste der Tutorial-Seiten */
  	private final List<TutorialPage> pages;
  
  	/** Regelmige Prfung des Modells */
  	private final Timer timer;
  	/** Hilfe-Browser fr die Tutorial-Seiten */
  	private final HTMLBrowserPanel browser;
  
  	/**
  	 * Tutorial-Fensters<br>
  	 * (Da es nur ein Tutorial-Fenster geben darf, schliet
  	 * der Konstruktor ggf. vorherige Tutorial-Fenster.)
  	 */
  	private static TutorialWindow currentTutorialWindow=null;
  
  	/**
  	 * Konstruktor der Klasse <code>TutorialWindow</code>.<br>
  	 * Der Konstruktor erstellt das Fenster und macht es auch sichtbar.
  	 * War bereits eine Instanz dieser Klasse sichtbar, so wird
  	 * diese zunchst ausgeblendet.
  	 * @param mainPanel	Programm-<code>MainPanel</code> mit dem das interaktive Tutorial zusammenarbeiten soll.
  	 */
  	public TutorialWindow(final MainPanel mainPanel) {
  		super(Language.tr("InteractiveTutorial.Title"));
  		if (currentTutorialWindow!=null) currentTutorialWindow.close();
  		currentTutorialWindow=this;
  		this.mainPanel=mainPanel;
  
  		/* Fenster zu Panel finden */
  		Component c=mainPanel;
  		while (c!=null) {if (c instanceof JFrame) break; c=c.getParent();}
  		mainFrame=(JFrame)c;
  
  		/* Position des Hauptfensters speichern, Hauptfenster und Tutorialfenster anordnen */
  		final Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
  		final Insets insets=Toolkit.getDefaultToolkit().getScreenInsets(getGraphicsConfiguration());
  		final int w=screenSize.width-insets.left-insets.right;
  		final int h=screenSize.height-insets.top-insets.bottom;
  		if (mainFrame!=null) {
  			saveMainFrameLocation=mainFrame.getLocation();
  			saveMainFrameSize=mainFrame.getSize();
  			mainFrame.setLocation(insets.left,insets.top);
  			mainFrame.setSize(3*w/4,h);
  		}
  		setLocation(3*w/4+insets.left,insets.top);
  		setSize(1*w/4,h);
  
  		/* Beim Schlieen Hauptfenster wiederherstellen */
  		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  		addWindowListener(new WindowAdapter() {
  			@Override public void windowClosing(WindowEvent event) {close();}
  		});
  
  		/* Icon */
  		if (mainFrame!=null) {
  			setIconImage(mainFrame.getIconImage());
  		}
  
  		/* Liste mit allen verfgbaren Seiten aufbauen */
  		language=Language.tr("Numbers.Language");
  		pages=new ArrayList<>();
  		buildPagesList();
  
  		/* GUI aufbauen */
  		browser=HTMLBrowser.getBrowser(HelpBase.ViewerMode.HTML_VIEWER_SWING);
  		getContentPane().setLayout(new BorderLayout());
  		getContentPane().add(browser.asScrollableJComponent(),BorderLayout.CENTER);
  		loadPage(pages.get(0).getPageName());
  
  		browser.init(()->loadPage(browser.getLastClickedURLDescription()),element->preprocessPage(element),null);
  
  		/* Prfen, ob Bedingung fr nchste Seite erfllt ist */
  		timer=new Timer("TutorialModelSupervisor");
  		timer.schedule(new TimerTask() {
  			@Override
  			public void run() {
  				if (page==null) return;
  				final String nextPage=page.checkNextCondition(TutorialWindow.this.mainPanel);
  				if (nextPage!=null) {page=null; loadPage(nextPage);}
  			}
  		},250,250);
  
  		/* Fenster anzeigen */
  		setVisible(true);
  	}
  
  	/**
  	 * Schliet das Fenster wieder. Wird entweder durch das Klicken des
  	 * Nutzers auf die Schlieen-Schaltflche ausgelst oder von einer
  	 * neuen Instanz, die zunchst das Fenster der alten Instanz schliet.
  	 */
  	private void close() {
  		if (mainFrame!=null) {
  			mainFrame.setLocation(saveMainFrameLocation);
  			mainFrame.setSize(saveMainFrameSize);
  		}
  		page=null;
  		timer.cancel();
  		setVisible(false);
  		currentTutorialWindow=null;
  	}
  
  	/**
  	 * Schliet ein mglicherweise offenes Tutorial-Fenster.
  	 */
  	public static void closeTutorialWindow() {
  		if (currentTutorialWindow!=null) currentTutorialWindow.close();
  	}
  
  	/**
  	 * In dieser Methode mssen alle Seiten, die im Rahmen des Tutorials
  	 * angezeigt werden sollen, registriert werden.<br>
  	 * Die erste hier registrierte Seite fungiert dabei automatisch als Startseite.
  	 * @see TutorialPage
  	 */
  	private void buildPagesList() {
  		pages.add(new PageStart());
  		pages.add(new PageOpenTemplates());
  		pages.add(new PageAddSource());
  		pages.add(new PageAddProcess());
  		pages.add(new PageAddDispose());
  		pages.add(new PageOpenConnect());
  		pages.add(new PageConnect1());
  		pages.add(new PageConnect2());
  		pages.add(new PageCloseConnect());
  		pages.add(new PageSetupSource());
  		pages.add(new PageSetupProcess());
  		pages.add(new PageSetupModel());
  		pages.add(new PageDone());
  	}
  
  	/**
  	 * Zeigt eine bestimmte Seite an.<br>
  	 * Es wird die hier angegebene html-Seite angezeigt und gleichzeitig das
  	 * zugehrige <code>TutorialPage</code>-Element aktiviert.
  	 * @param name	Name der anzuzeigenden Seite (ohne Pfad und ohne Extension)
  	 * @see TutorialPage
  	 * @see #buildPagesList()
  	 */
  	private void loadPage(final String name) {
  		if (name.equals("CloseTutorial")) {
  			close();
  			return;
  		}
  
  		final URL url=getClass().getResource("pages_"+language+"/"+name+".html");
  		if (url!=null) browser.showPage(url);
  		TutorialPage current=null;
  		for (TutorialPage page: pages) if (page.getPageName().equalsIgnoreCase(name)) {current=page; break;}
  		if (current!=null) page=current;
  	}
  
  	/**
  	 * Vorverarbeitung der geladenen Seite
  	 * @param root	Wurzelelement der Seite
  	 */
  	private void preprocessPage(final Element root) {
  		final Document doc=root.getDocument();
  		if (!(doc instanceof HTMLDocument)) return;
  		final HTMLDocument html=(HTMLDocument)doc;
  		final StyleSheet styleSheet=html.getStyleSheet();
  
  		/* Hinweise auf Buchkapitel ausblenden, wenn Buch nicht verfgbar ist. */
  		if (!BookData.getInstance().isDataAvailable()) {
  			styleSheet.removeStyle(".bookinfo");
  			styleSheet.removeStyle(".bookinfosmall");
  			styleSheet.addRule(".bookinfo {color: #F0F0FF; font-size: 1%;} .bookinfosmall {color: #F0F0FF; font-size: 1%;} .bookinfo a {color: #F0F0FF; font-size: 1%;} .bookinfosmall a {color: #F0F0FF; font-size: 1%;}");
  		}
  
  		/* Anpassungen fr FlatLaF-Dark-Mode */
  		if (FlatLaFHelper.isDark()) {
  			styleSheet.addRule("body {color: #c0c0c0;} a {color: #8080FF;} a.box {background-color: #505050;} div.menu, div.model, div.plaininfo {background-color: #404040;} .bookinfo {background-color: #505050;} .bookinfosmall {background-color: #505050;}");
  		}
  	}
  }