package de.duehl.swing.ui.text.html;

/*
 * Copyright 2022 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.net.URL;

import javax.swing.JPanel;
import javax.swing.JViewport;

import de.duehl.basics.text.html.HtmlTool;
import de.duehl.swing.ui.colors.Colorizer;
import de.duehl.swing.ui.text.TextPanel;

/**
 * Diese Klasse stellt ein Panel zur Verfügung, das Html darstellt. Man kann es umschalten, um den
 * Quellcode zu sehen.
 *
 * @version 1.01     2022-08-04
 * @author Christian Dühl
 */

public class HtmlCardPanel {

    private static final Dimension PANEL_DIMENSION = new Dimension(1000, 750);

    /**
     * Der Haupt-Panel dieses Objekts mit dem CardLayout, welches den Editor und den Quellcode
     * beinhaltet.
     *
     * Wird auch beim Weiterschalten der Karten benötigt.
     */
    private final JPanel cardPanel;

    /** Das CardLayout, wird beim Weiterschalten benötigt. */
    private final CardLayout cardLayout;

    /** Aktuell angezeigte Karte im CardLayout. */
    private HtmlPanelCard currentCard;

    /** Komponente zur Darstellung des HTML. */
    private final HtmlPanel htmlPanel;

    /** Bereich zur Darstellung des Sourcecodes. */
    private final TextPanel sourceCodePanel;

    /** Komponente. */
    public HtmlCardPanel() {
        htmlPanel = new HtmlPanel();
        sourceCodePanel = new TextPanel();

        cardPanel = new JPanel();
        cardLayout = new CardLayout();

        initShowPartsAndScrolls();

        fillThePanel();
    }

    private void initShowPartsAndScrolls() {
        initSourceCodeTextArea();
        setPreferredSize(PANEL_DIMENSION);
    }

    private void initSourceCodeTextArea() {
        sourceCodePanel.biggerFont(3);
        sourceCodePanel.useMonoscpacedText();
    }

    /** Erstellt den Panel. */
    private void fillThePanel() {
        cardPanel.setLayout(cardLayout);

        cardPanel.add(htmlPanel.getComponent(), HtmlPanelCard.HTML.name());
        cardPanel.add(sourceCodePanel.getComponent(), HtmlPanelCard.SOURCE_CODE.name());

        currentCard = HtmlPanelCard.HTML;
    }

    /** Schaltet zur nächsten Karte weiter. */
    public void switchCard() {
        currentCard = currentCard.getNext();
        cardLayout.show(cardPanel, currentCard.name());
        cardPanel.validate();
    }

    /** Getter für die aktuell angezeigte Karte im CardLayout. */
    public HtmlPanelCard getCurrentCard() {
        return currentCard;
    }

    /**
     * Schreibt den Text der Seite hinter der URL in den Hauptteil des Dialogs und setzt den
     * Textcursor auf den Anfang des Dokuments.
     *
     * @param url
     *            URL, aus der der Inhalt gelesen wird.
     */
    public void showHtml(URL url) {
        htmlPanel.showHtml(url);
        sourceCodePanel.setText(HtmlTool.createContentFromUrl(url));
    }

    /** Setzt die Farben, falls ein Colorizer übergeben wird. */
    public void setColors(Colorizer colorizer) {
        if (null != colorizer) {
            htmlPanel.setColors(colorizer);
            sourceCodePanel.setColors(colorizer);
            colorizer.setColors(cardPanel);
        }
    }

    /**
     * Setzt den Text des Editors mit Scrollbalken.
     *
     * @param text
     *            Zu setzender Text.
     */
    public void setText(String text) {
        htmlPanel.setText(text);
        sourceCodePanel.setText(text);
    }

    /**
     * Setzt den Text des Editors mit Scrollbalken und scrollt hinterher den Sichtbaren Bereich des
     * Textes zum Anfang des Textes.
     *
     * @param text
     *            Zu setzender Text.
     */
    public void setTextAndScrollToTop(String text) {
        setText(text);
        scrollScrollbarToMinimumLater();
    }

    /** Getter für den Haupt-Panel in dem HTML und der zugehörige Quellcode dargestellt wird. */
    public JPanel getCardPanel() {
        return cardPanel;
    }

    /** Scrollt zum Anfang. */
    public void scrollScrollbarToMinimumLater() {
        htmlPanel.scrollScrollbarToMinimumLater();
        sourceCodePanel.scrollScrollbarToMinimumLater();
    }

    /** Scrollt zum Ende. */
    public void scrollScrollbarToMaximumLater() {
        htmlPanel.scrollScrollbarToMaximumLater();
        sourceCodePanel.scrollScrollbarToMaximumLater();
    }

    /** Scrollt weiter nach oben. */
    public void scrollScrollbarToPreviousSectionLater() {
        htmlPanel.scrollScrollbarToPreviousSectionLater();
        sourceCodePanel.scrollScrollbarToPreviousSectionLater();
    }

    /** Scrollt weiter nach unten. */
    public void scrollScrollbarToNextSectionLater() {
        htmlPanel.scrollScrollbarToNextSectionLater();
        sourceCodePanel.scrollScrollbarToNextSectionLater();
    }

    /** Gibt die Länge des Textes zurück. */
    public int getTextLength() {
        return htmlPanel.getTextLength();
    }

    /** Zeichnet den Editor neu. */
    public void repaint() {
        htmlPanel.repaint();
        sourceCodePanel.repaint();
    }

    /**
     * Setzt die bevorzugte Größe des Editors.
     *
     * @param size
     *            Gewünschte Dimension.
     */
    public void setPreferredSize(Dimension size) {
        setPreferredSize(size.width, size.height);
    }

    /**
     * Setzt die bevorzugte Größe des Editors.
     *
     * @param width
     *            Gewünschte Breite.
     * @param height
     *            Gewünschte Höhe.
     */
    public void setPreferredSize(int width, int height) {
        //System.out.println(width + " x " + height);
        htmlPanel.setPreferredSize(width, height);
        sourceCodePanel.setPreferredSize(width, height);
        //cardPanel.setPreferredSize(new Dimension(width, height));
        //repaint();
        //cardPanel.repaint();
    }

    /**
     * Turns on or off automatic drag handling. In order to enable automatic drag handling, this
     * property should be set to {@code true}, and the component's {@code TransferHandler} needs to
     * be {@code non-null}. The default value of the {@code dragEnabled} property is {@code false}.
     * <p>
     * The job of honoring this property, and recognizing a user drag gesture, lies with the look
     * and feel implementation, and in particular, the component's {@code TextUI}. When automatic
     * drag handling is enabled, most look and feels (including those that subclass
     * {@code BasicLookAndFeel}) begin a drag and drop operation whenever the user presses the
     * mouse button over a selection and then moves the mouse a few pixels. Setting this property
     * to {@code true} can therefore have a subtle effect on how selections behave.
     * <p>
     * If a look and feel is used that ignores this property, you can still begin a drag and drop
     * operation by calling {@code exportAsDrag} on the component's {@code TransferHandler}.
     *
     * @param enable
     *            whether or not to enable automatic drag handling
     */
    public void setDragEnabled(boolean enable) {
        htmlPanel.setDragEnabled(enable);
    }

    /**
     * Setzt die Position der Eingabemarke im Editor.
     *
     * @param position
     *            Zu setzende Position der Eingabemarke (0 bis Länge des Textes).
     */
    public void setCaretPosition(int position) {
        htmlPanel.setCaretPosition(position);
    }

    /**
     * Returns the position of the text insertion caret for the text component.
     *
     * @return the position of the text insertion caret for the text component &ge; 0
     */
    public int getCaretPosition() {
        return htmlPanel.getCaretPosition();
    }

    /**
     * Returns the <code>Component</code>'s "visible rectangle" - the intersection of this
     * component's visible rectangle, <code>new Rectangle(0, 0, getWidth(), getHeight())</code>,
     * and all of its ancestors' visible rectangles.
     *
     * @return the visible rectangle
     */
    public Rectangle getVisibleRect() {
        return htmlPanel.getVisibleRect();
    }

    /**
     * Forwards the <code>scrollRectToVisible()</code> message to the <code>JComponent</code>'s
     * parent. Components that can service the request, such as <code>JViewport</code>, override
     * this method and perform the scrolling.
     *
     * @param rectangle
     *            the visible <code>Rectangle</code>
     * @see JViewport
     */
    public void scrollRectToVisible(Rectangle rectangle) {
        htmlPanel.scrollRectToVisible(rectangle);
    }

    /**
     * Returns the selected text's start position. Return 0 for an empty document, or the value of
     * dot if no selection.
     *
     * @return the start position &ge; 0
     */
    public int getSelectionStart() {
        return htmlPanel.getSelectionStart();
    }

    /**
     * Returns the selected text's end position. Return 0 if the document is empty, or the value of
     * dot if there is no selection.
     *
     * @return the end position &ge; 0
     */
    public int getSelectionEnd() {
        return htmlPanel.getSelectionEnd();
    }

    /**
     * Sets the selection start to the specified position. The new starting point is constrained to
     * be before or at the current selection end. <p>
     *
     * This is available for backward compatibility to code that called this method on
     * <code>java.awt.TextComponent</code>. This is implemented to forward to the
     * <code>Caret</code> implementation which is where the actual selection is maintained.
     *
     * @param start
     *            the start position of the text &ge; 0
     */
    public void setSelectionStart(int start) {
        htmlPanel.setSelectionStart(start);
    }

    /**
     * Sets the selection end to the specified position. The new end point is constrained to be at
     * or after the current selection start. <p>
     *
     * This is available for backward compatibility to code that called this method on
     * <code>java.awt.TextComponent</code>. This is implemented to forward to the
     * <code>Caret</code> implementation which is where the actual selection is maintained.
     *
     * @param end
     *            the end position of the text &ge; 0
     */
    public void setSelectionEnd(int end) {
        htmlPanel.setSelectionEnd(end);
    }

    /**
     * Gibt den in der text-Komponente selektierten Text zurück.
     *
     * Falls dieser nicht ermittelt werden kann, wird der leere String zurückgegeben.
     */
    public String getSelectedText() {
        return htmlPanel.getSelectedText();
    }

    /** Löscht die Selektion. */
    public void clearSelection() {
        htmlPanel.clearSelection();
    }

    /** Gibt an, ob das Element den Fokus hat. */
    public boolean hasFocus() {
        return htmlPanel.hasFocus();
    }

    /** Setzt die Hintergrundfarben für die Darstellung. */
    public void setBackground(Color backgroundColor) {
        htmlPanel.setBackground(backgroundColor);
        sourceCodePanel.setBackground(backgroundColor);
    }

    /**
     * Lässt die Tastenkombinationen Page-Up und Page-Down an die übergeordnete Komponente
     * weiterreichen.
     */
    public void ignorePageUpAndPageDown() {
        htmlPanel.ignorePageUpAndPageDown();
        sourceCodePanel.ignorePageUpAndPageDown();
    }

    /**
     * Lässt die Tastenkombinationen Pfeiltaste nach oben und Pfeiltaste nach oben in dem Feld für
     * den Namen an die übergeordnete Komponente weiterreichen.
     */
    public void ignoreUpAndDown() {
        htmlPanel.ignoreUpAndDown();
        sourceCodePanel.ignoreUpAndDown();
    }

    /**
     * Lässt die Tastenkombinationen Ctrl-Pos1 und Ctrl-End in dem Feld für den Namen an die
     * übergeordnete Komponente weiterreichen.
     */
    public void ignoreCtrlPos1AndCtrlEnd() {
        htmlPanel.ignoreCtrlPos1AndCtrlEnd();
        sourceCodePanel.ignoreCtrlPos1AndCtrlEnd();
    }

    /** Zeigt den Cursor an (rot und nicht blinkend). */
    public void showCursor() {
        htmlPanel.showCursor();
    }

    /** Speichert die vertikale Position des Textes. */
    public void storeVerticalPosition() {
        htmlPanel.storeVerticalPosition();
    }

    /** Stellt die gespeicherte vertikale Position des Textes wieder her. */
    public void restoreVerticalPosition() {
        htmlPanel.restoreVerticalPosition();
    }

    /** Gibt den HTML-Text zurück. */
    public String getHtmlText() {
        return htmlPanel.getHtmlText();
    }

    /** Vergrößert (oder verkleinert bei negativer Größe) die Schriftgröße des Code-Panels. */
    public void sourceCodePanelBiggerFont(int addSize) {
        sourceCodePanel.biggerFont(addSize);
    }

}
