package de.duehl.swing.ui.layout.card;

/*
 * Copyright 2016 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.Component;

import static de.duehl.swing.ui.layout.card.CardDebug.say;

/**
 * Diese Klasse stellt eine Karte dar und hält deren Namen, deren grafische Oberfläche und deren
 * Logik.
 *
 * @version 1.01     2016-12-07
 * @author Christian Dühl
 */

public class Card {

    private static final long NO_TIME_YET = Long.MIN_VALUE;

    /** Eindeutiger Name der Karte zur Verwendung im CardLayout. */
    private final String name;

    /** Zur Karte gehörige grafische Oberfläche. */
    private final CardGui gui;

    /** Zur Karte gehörige Logik. */
    private final CardLogic logic;

    /** Nummer des Schritts (1-basiert). */
    private final int stepNumber;

    /** Name des Schrittes, wie er in der Oberfläche angezeigt werden soll. */
    private final String nameForGui;

    /** Laufzeit in Sekunden oder NO_TIME_YET, falls diese Information nicht vorliegt. */
    private long timeUsedInSeconds;

    /** Laufzeit im Format HH:MM:SS oder der leere String, falls diese Information nicht vorliegt. */
    private String timeUsedHumanReadable;

    /**
     * Konstruktor.
     *
     * @param name
     *            Eindeutiger Name der Karte zur Verwendung im CardLayout.
     * @param gui
     *            Zur Karte gehörige grafische Oberfläche.
     * @param logic
     *            Zur Karte gehörige Logik.
     * @param stepNumber
     *            Nummer des Schritts (1-basiert).
     * @param nameForGui
     *            Name des Schrittes, wie er in der Oberfläche angezeigt werden soll.
     */
    public Card(String name, CardGui gui, CardLogic logic, int stepNumber, String nameForGui) {
        this.name = name;
        this.gui = gui;
        this.logic = logic;
        this.stepNumber = stepNumber;
        this.nameForGui = nameForGui;
        timeUsedInSeconds = NO_TIME_YET;
        timeUsedHumanReadable = "";

        logic.setGui(gui);
        logic.setCard(this);
        gui.setLogic(logic);
    }

    /** Setter für alle Karten. */
    public final void setCards(Cards cards) {
        logic.setCards(cards);
    }

    /** Getter für den eindeutigen Namen der Karte zur Verwendung im CardLayout. */
    String getName() {
        return name;
    }

    /** Getter für die Nummer des Schritts (1-basiert). */
    public int getStepNumber() {
        return stepNumber;
    }

    /** Getter für den Namen des Schrittes, wie er in der Oberfläche angezeigt werden soll. */
    public String getNameForGui() {
        return nameForGui;
    }

    /** Gibt an, ob Informationen zur Laufzeit vorliegen. */
    public boolean isTimeAccessible() {
        return timeUsedInSeconds != NO_TIME_YET && !timeUsedHumanReadable.isEmpty();
    }

    /**
     * Getter für die Laufzeit in Sekunden oder NO_TIME_YET, falls diese Information nicht
     * vorliegt.
     */
    public long getTimeUsedInSeconds() {
        return timeUsedInSeconds;
    }

    /**
     * Setter für die Laufzeit in Sekunden oder NO_TIME_YET, falls diese Information nicht
     * vorliegt.
     */
    public void setTimeUsedInSeconds(long timeUsedInSeconds) {
        if (timeUsedInSeconds < 0) {
            throw new IllegalArgumentException("Laufzeit " + timeUsedInSeconds + " ist unzulässig!");
        }
        this.timeUsedInSeconds = timeUsedInSeconds;
    }

    /** Getter für die Laufzeit im Format HH:MM:SS. */
    public String getTimeUsedHumanReadable() {
        return timeUsedHumanReadable;
    }

    /** Setter für die Laufzeit im Format HH:MM:SS. */
    public void setTimeUsedHumanReadable(String timeUsedHumanReadable) {
        if (!timeUsedHumanReadable.matches("\\d{2,}:\\d{2}:\\d{2}")) {
            throw new IllegalArgumentException("Laufzeit '" + timeUsedHumanReadable
                    + "' ist unzulässig!");
        }
        this.timeUsedHumanReadable = timeUsedHumanReadable;
    }

    /**
     * Erstellt die grafische Oberfläche dieser Karte.
     *
     * @param switcher
     *            Objekt zum Weiterschalten auf die nächste Karte bzw. zum Beenden des Programms.
     * @return Grafische Oberfläche der Karte.
     */
    Component createCardGui(CardSwitcher switcher) {
        return gui.createGui(switcher);
    }

    /**
     * Wird ausgeführt, wenn die Karte in der grafischen Oberfläche angezeigt wird.
     *
     * @param previousCard
     *            Die im Schritt zuvor gezeigte Karte.
     */
    void runWhenShown(Card previousCard) {
        say("called");
        CardLogic previousLogic = previousCard.logic;
        CardResult result = previousLogic.getResult();
        logic.setResultFromPreviousCard(result);
        logic.runWhenShown();
    }

    /** Räumt auf, wenn die Karte nicht mehr angezeigt wird. */
    void cleanUp() {
        gui.cleanUp();
    }

    /** Beendet auf Wunsch des Benutzers die Aktivitäten dieser Karte. */
    public void quit() {
        say("called");
        logic.quit();
        cleanUp();
    }

    @Override
    public String toString() {
        return "Card [name=" + name + ", stepNumber=" + stepNumber + ", nameForGui=" + nameForGui
                + ", timeUsedInSeconds=" + timeUsedInSeconds + ", timeUsedHumanReadable="
                + timeUsedHumanReadable + "]";
    }

    /** Zur Karte gehörige Logik. */
    public CardLogic getLogic() {
        return logic;
    }

}
