/******************************************************************************
 ** $Id: Eigenschaften.java 1271 2017-05-26 23:44:14Z wmh $
 ** Diese Datei ist Bestandteil der Java-Quelltexte des Würfelspiels JaFuffy.
 ** Lauffähig ab Java 7.
 ******************************************************************************
 ** Copyright (C) Wolfgang Hauck <wolfgang.hauck@3kelvin.de>
 ******************************************************************************
 ** This program is free software: you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** the Free Software Foundation, either version 3 of the License, or
 ** (at your option) any later version.
 **
 ** This program is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 **
 ** You should have received a copy of the GNU General Public License
 ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************
 ** Die aktuellste Version von JaFuffy findet sich im Internet unter
 ** <http://jafuffy.3kelvin.de>.
 **
 ** Kommentare, Fehler oder Erweiterungswünsche bitte per E-Mail senden an
 ** <jafuffy@3kelvin.de>.
 ******************************************************************************/
package jafuffy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

import jafuffy.Eigenschaften.Status;
import jafuffy.bedienung.Oberflaeche;
import jafuffy.logik.Beginner;
import jafuffy.logik.Bot;
import jafuffy.logik.Spieler;
import jafuffy.logik.Variante;

/** Umfasst Programm- und Turniereigenschaften; inklusive erstmalige Pfadeinstellung. */
@SuppressWarnings("serial")
public final class Eigenschaften extends Properties {

    /** Aktivitätszustände eines Schlüssels. */
    public enum Status {
        /** Funktion zum Schlüssel ist passiv. */
        PASSIV,
        /** Funktion zum Schlüssel ist aktiv. */
        AKTIV;
    }

    /** Hinweiszeile in der Einstellungsdatei. */
    private static final String HINWEIS = "JaFuffy-Einstellungen (bitte nicht von Hand ändern)";
    /** Name der Einstellungsdatei. */
    private static final String INI = "JaFuffy.ini";
    /** Voreinstellungen der Eigenschaften. */
    private static final Vorbelegung VORBELEGUNG = new Vorbelegung(Ressource.soundsystem());

    /** Die globalen Eigenschaften für ganz JaFuffy. */
    public static final Eigenschaften GLOBAL;
    static {
        File datei = null;
        try {
            final String pfad = System.getProperty("user.home") + File.separator + INI;
            datei = new File(pfad);
        } catch (SecurityException exception) {
            System.out.println("Sicherheitseinstellungen verbieten Zugriff auf Heimverzeichnis: " + exception);
        }
        GLOBAL = new Eigenschaften(datei);
    }

    /** In dieser Datei sind die Einstellungen persistent abgelegt. */
    private final File ablage;

    /**
     * Konstruktor, welcher versucht die Einstellungen aus einer persistenten Datei auszulesen.
     *
     * @param vorgabe
     *            Datei, in der die Eigenschaften persistent abgelegt sind oder werden. Null, wenn keine Datei zur
     *            Verfügung steht, wie z.B. noch nicht vorhandener Datei oder bei eingeschränkten Rechten. Bei
     *            Sicherheitseinschränkungen kann auf persistente Speicherung verzichtet werden, es werden Vorgabewerte
     *            verwendet.
     */
    private Eigenschaften(File vorgabe) {
        super(VORBELEGUNG);
        File datei = vorgabe;
        if (vorgabe != null && vorgabe.exists()) {
            try {
                FileInputStream reader = new FileInputStream(vorgabe);
                load(reader);
                reader.close();
            } catch (IOException exeption) {
                exeption.printStackTrace();
                datei = null;
            } catch (SecurityException exception) {
                System.out.println("Sicherheitseinstellungen verbieten Einlesen der Eigenschaften: " + exception);
                datei = null;
            }
        }
        this.ablage = datei;
    }

    /**
     * Zustand eines Schlüssels erfragen.
     *
     * @param schluessel
     *            Schlüssel der Eigenschaft.
     * @return Gibt an, ob der Wert des Schlüssels aktiv ist.
     */
    public boolean aktiv(String schluessel) {
        return getProperty(schluessel).equals(Status.AKTIV.name());
    }

    /**
     * @return Index des Beginnmodus.
     * @see Beginner
     */
    public int beginnmodus() {
        return Beginner.valueOf(getProperty("Beginnmodus")).ordinal();
    }

    /**
     * Liefert ein File-Objekt zum Dateinamen zurück, zusammengebaut aus dem Speicherverzeichnis und dem Dateinamen.
     *
     * @param name
     *            Der Dateiname, aus dem das File-Objekt erzeugt wird.
     *
     * @return Das File-Objekt zur Datei.
     */
    public File datei(String name) {
        return new File(getProperty("Pfad"), name);
    }

    /**
     * Erststart erfragen.
     *
     * @return Gibt an, ob Erststart erfolgt ist, oder ob davon ausgegangen werden kann.
     */
    public boolean erststart() {
        return ablage != null && getProperty("Starts").equals("0");
    }

    /**
     * @return Gibt an ob im vorhergehenden Programmlauf ein Neustart angefordert wurde, allerdings kein Turnier am
     *         laufen war.
     */
    public boolean kaltstart() {
        return getProperty("Neustart").equals("kalt");
    }

    /**
     * Merkt in den Einstellungen, ob ein Neustart angefordert wurde.
     *
     * @param warm
     *            Ein Turnier ist am laufen.
     */
    public void merkeNeustartAnforderung(boolean warm) {
        setProperty("Neustart", warm ? "warm" : "kalt");
    }

    /** @return Gibt an ob im vohergehenden Programmlauf ein Neustart angefordert wurde. */
    public boolean neustart() {
        return kaltstart() || warmstart();
    }

    /** @return Pfad zum Speicherort der Statistik und den Turnierständen. */
    public String pfad() {
        return getProperty("Pfad");
    }

    /**
     * Setzt den Pfad zum Speicherort der Statistik und den Turnierständen.
     *
     * @param pfad
     *            Der zu setzende Pfad.
     */
    public void pfad(String pfad) {
        setProperty("Pfad", pfad);
    }

    /**
     * Ein Neustart wurde durchgeführt, braucht also beim nächsten Programmstart nicht mehr berücksichtigt werden.
     */
    public void quittiereNeustartAnforderung() {
        setProperty("Neustart", Status.PASSIV.name());
    }

    /**
     * Speichern der Eigenschaften in Datei.
     *
     * @param x
     *            X-Koordinate der linken oberen Ecke des Programmfensters.
     * @param y
     *            Y-Koordinate der linken oberen Ecke des Programmfensters.
     * @param b
     *            Breite des Programmfensters.
     * @param h
     *            Höhe des Programmfensters.
     * @throws IOException
     *             Geworfen, falls Einstellungen nicht gespeichert werden können.
     */
    public void speichere(int x, int y, int b, int h) throws IOException {
        setProperty("X", String.valueOf(x));
        setProperty("Y", String.valueOf(y));
        setProperty("Breite", String.valueOf(b));
        setProperty("Hoehe", String.valueOf(h));
        setProperty("Starts", String.valueOf(Integer.parseInt(getProperty("Starts")) + 1));
        if (ablage != null) {
            FileOutputStream writer = new FileOutputStream(ablage);
            store(writer, HINWEIS);
            writer.close();
        }
    }

    /**
     * @return Index der Spielregelvariante.
     * @see Variante
     */
    public int variante() {
        return Variante.valueOf(getProperty("Variante")).ordinal();
    }

    /**
     * @return Gibt an ob im vohergehenden Programmlauf ein Neustart angefordert wurde, allerdings ein Turnier am laufen
     *         war.
     */
    public boolean warmstart() {
        return getProperty("Neustart").equals("warm");
    }

    /**
     * Eigenschaften umschalten zwischen aktiv und passiv.
     *
     * @param schluessel
     *            Der Schlüssel, dessen boolescher Wert gewechselt werden soll.
     */
    public void wechsle(String schluessel) {
        setProperty(schluessel, aktiv(schluessel) ? Status.PASSIV.name() : Status.AKTIV.name());
    }
}

/** Die Voreinstellungen für die Eigenschaften. */
@SuppressWarnings("serial")
class Vorbelegung extends Properties {

    /**
     * Nimmt die Voreinstellungen vor.
     *
     * @param soundsystem
     *            Gibt an, ob ein Soundsystem vorhanden ist.
     */

    Vorbelegung(boolean soundsystem) {
        setProperty("Geraeusche", soundsystem ? Status.AKTIV.name() : Status.PASSIV.name());
        setProperty("LookAndFeel", Oberflaeche.standardLookAndFeel());
        setProperty("Variante", Variante.KLASSISCH.name());
        setProperty("Beginnmodus", Beginner.VERLIERER.name());
        setProperty("Anzahl", "0");
        setProperty("Einfachklick", Status.PASSIV.name());
        setProperty("Hinweis", Status.AKTIV.name());
        setProperty("Spicker", Status.AKTIV.name());
        setProperty("Erinnerung", Status.AKTIV.name());
        setProperty("Intro", Status.AKTIV.name());
        setProperty("Geraeusche", Status.AKTIV.name());
        setProperty("Breite", "640");
        setProperty("Hoehe", "480");
        setProperty("Nachschauen", Status.PASSIV.name());
        setProperty("Starts", "0");
        setProperty("Zwischenstand", Status.PASSIV.name());
        setProperty("Neustart", Status.PASSIV.name());
        try {
            setProperty("Pfad", System.getProperty("user.home"));
        } catch (SecurityException exception) {
            System.out.println("Sicherheitseinstellungen verbieten Speichern von Einstellungen, Statistiken, Ständen: "
                    + exception);
        }
        for (int i = 0; i < Spieler.SPIELER; i++) {
            setProperty("Spieler" + i, "");
            setProperty("Bot" + i, "");
            setProperty("Botstaerke" + i, Bot.Spielstaerke.STARK.name());
        }
        setProperty("Ueberlegungsdarstellungsbeschleunigung", Status.AKTIV.name());
        setProperty("Aktionsdarstellungsbeschleunigung", Status.PASSIV.name());
    }
}
