package de.duehl.basics.datetime;

/*
 * Copyright 2017 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.util.regex.Matcher;
import java.util.regex.Pattern;

import de.duehl.basics.datetime.date.DateHelper;
import de.duehl.basics.datetime.date.ImmutualDate;
import de.duehl.basics.datetime.time.ImmutualTime;
import de.duehl.basics.datetime.time.TimeHelper;

/**
 * Diese Klasse erzeugt Timestamps und ähnliches.
 *
 * @version 1.01     2017-04-24
 * @author Christian Dühl
 */

public class Timestamp {

    public static final Pattern STANDARD_TIMESTAMP_PATTERN = Pattern.compile("\\d{8}_\\d{6}");
    public static final String STANDARD_DELIMITER = "_";

    /** Eine Instanz soll hiervon nicht angelegt werden! */
    private Timestamp() {}

    /**
     * Ermittelt das aktuelle Datum und die aktuelle Uhrzeit und gibt sie in der Form
     * JJJJMMTT_HHMMSS zurück.
     *
     * @return Aktuelle Datum und aktuelle Uhrzeit in der Form JJJJMMTT_HHMMSS.
     */
    public static String fullTimestamp() {
        return fullTimestamp(STANDARD_DELIMITER);
    }

    /**
     * Ermittelt das aktuelle Datum und die aktuelle Uhrzeit und gibt sie in der Form
     * JJJJMMTT#HHMMSS zurück, wobei # für den übergebenen Trenner steht.
     *
     * @param delimiter
     *            Trenner zwischen Datum und Uhrzeit.
     * @return Aktuelle Datum und aktuelle Uhrzeit in der Form JJJJMMTT_HHMMSS.
     */
    public static String fullTimestamp(String delimiter) {
        DateAndTime now = new DateAndTime();

        ImmutualTime time = now.getTime();
        String actualTime = time.asHhMmSs();

        ImmutualDate date = now.getDate();
        String actualDate = date.asYyyyMmDd();

        return actualDate + delimiter + actualTime;
    }

    /** Ermittelt das aktuelle Datum im Format TT.MM.JJJJ. */
    public static String actualDate() {
        return DateHelper.actualDateAsString();
    }

    /** Ermittelt die aktuelle Zeit im Format HH:MM:SS. */
    public static String actualTime() {
        return TimeHelper.actualTimeAsString();
    }

    /** Ermittelt das aktuelle Datum und Zeit im Format "TT.MM.JJJJ" + delimiter + "TT.MM.YYYY". */
    public static String actualDateAndTime(String delimiter) {
        DateAndTime now = new DateAndTime();

        ImmutualTime time = now.getTime();
        String actualTime = time.toString();

        ImmutualDate date = now.getDate();
        String actualDate = date.toString();

        return actualDate + delimiter + actualTime;
    }

    /**
     * Vergleicht zwei Timestamps.
     *
     * @param timeStamp1
     *            Erster zu vergleichender Timestamp.
     * @param timeStamp2
     *            Zweiter zu vergleichender Timestamp.
     * @return Vergleichswert: 0 bedeutet Gleichheit, bei Werten kleiner als null ist der
     *         timestamp1 vor dem timestamp2, bei Werten größer als 0 ist der
     *         timestamp1 nach dem timestamp2.
     */
    public static int compareTimestamps(String timestamp1, String timestamp2) {
        return timestamp1.compareTo(timestamp2);
    }

    /**
     * Testet, ob ein Timestamp zeitlich vor einem anderen Timestamp liegt.
     *
     * @param timeStamp1
     *            Erster zu vergleichender Timestamp.
     * @param timeStamp2
     *            Zweiter zu vergleichender Timestamp.
     * @return Wahrheitswert.
     */
    public static boolean firstTimestampIsNewer(String timeStamp1, String timeStamp2) {
        return timeStamp1.compareTo(timeStamp2) > 0;
    }

    /**
     * Testet, ob ein Timestamp zeitlich nach einem anderen Timestamp liegt.
     *
     * @param timeStamp1
     *            Erster zu vergleichender Timestamp.
     * @param timeStamp2
     *            Zweiter zu vergleichender Timestamp.
     * @return Wahrheitswert.
     */
    public static boolean firstTimestampIsOlder(String timeStamp1, String timeStamp2) {
        return timeStamp1.compareTo(timeStamp2) < 0;
    }

    /**
     * Tauscht den Timestamp im Dateinamen gegen den von jetzt aus. Der Timestamp muss in der Form
     * JJJJMMTT_HHMMSS vorliegen, wie ihn fullTimestamp() erzeugt!
     *
     * @param fileName
     *            Aktueller Logname.
     * @param newContents
     *            Neuer Inhalt, der an der Stelle des Timestamps eingefügt werden soll.
     * @return Neuer Logname.
     */
    public static String switchDateTimePartInName(String fileName, String newContents) {
        Matcher matcher = STANDARD_TIMESTAMP_PATTERN.matcher(fileName);
        if (matcher.find()) {
            String front = fileName.substring(0, matcher.start());
            String rear = fileName.substring(matcher.end(), fileName.length());
            return front + newContents + rear;
        }
        else {
            throw new RuntimeException("Es wurde kein Timestamp-Part im Format JJJJMMTT_HHMMSS im "
                    + "Dateinamen '" + fileName + "' gefunden!");
        }
    }

    /**
     * Tauscht den Timestamp im Dateinamen gegen den von jetzt aus. Der Timestamp muss in der Form
     * JJJJMMTT_HHMMSS vorliegen, wie ihn fullTimestamp() erzeugt!
     *
     * @param fileName
     *            Aktueller Logname.
     * @return Neuer Logname.
     */
    public static String switchDateTimePartInName(String fileName) {
        return switchDateTimePartInName(fileName, fullTimestamp());
    }

    /**
     * Verschönert einen Timestamp für die Gui.
     *
     * @param timestamp
     *            Timestamp im Format "JJJJMMDD_HHMMSS".
     * @return Timestamp im Format "DD.MM.JJJJ HH:MM:SS".
     */
    public static String beautifyTimestamp(String timestamp) {
        if (timestamp.matches("\\d{8}_\\d{6}")) {
            String year = timestamp.substring(0, 4);
            String month = timestamp.substring(4, 6);
            String day = timestamp.substring(6, 8);
            String hour = timestamp.substring(9, 11);
            String minute = timestamp.substring(11, 13);
            String second = timestamp.substring(13, 15);
            return day + "." + month + "." + year + ", " + hour + ":" + minute + ":" + second;
        }
        else {
            return timestamp;
        }
    }

    /**
     * Erzeugt aus einem für die Gui verschönerten Timestamp wieder einen Standard-Full_timestamp.
     *
     * @param beautifiedTimestamp
     *            Timestamp im Format "DD.MM.JJJJ HH:MM:SS".
     * @return Timestamp im Format "JJJJMMDD_HHMMSS".
     */
    public static String beautifiedTimestampToFullTimestamp(String beautifiedTimestamp) {
        if (beautifiedTimestamp.matches("\\d{2}\\.\\d{2}\\.\\d{4}, \\d{2}:\\d{2}:\\d{2}")) {
            String day = beautifiedTimestamp.substring(0, 2);
            String month = beautifiedTimestamp.substring(3, 5);
            String year = beautifiedTimestamp.substring(6, 10);
            String hour = beautifiedTimestamp.substring(12, 14);
            String minute = beautifiedTimestamp.substring(15, 17);
            String second = beautifiedTimestamp.substring(18, 20);
            return year + month + day + STANDARD_DELIMITER + hour + minute + second;
        }
        else {
            return beautifiedTimestamp;
        }
    }

    /**
     * Ermittelt das Datum aus einem Timestamp.
     *
     * @param timestamp
     *            Timestamp im Format "JJJJMMDD_HHMMSS" und ggf. noch Zeichen dahinter.
     * @return Datum.
     */
    public static ImmutualDate getDateFromTimestamp(String timestamp) {
        if (!timestamp.matches("\\d{8}_\\d{6}.*")) {
            throw new IllegalArgumentException("Parameter timestamp ist nicht im passenden Format."
                    + "\n\ttimestamp = " + timestamp);
        }
        String datePart = timestamp.substring(0, 8);
        return new ImmutualDate(datePart);
    }

    /**
     * Ermittelt die Uhrzeit aus einem Timestamp.
     *
     * @param timestamp
     *            Timestamp im Format "JJJJMMDD_HHMMSS" und ggf. noch Zeichen dahinter.
     * @return Uhrzeit.
     */
    public static ImmutualTime getTimeFromTimestamp(String timestamp) {
        if (!timestamp.matches("\\d{8}_\\d{6}.*")) {
            throw new IllegalArgumentException("Parameter timestamp ist nicht im passenden Format."
                    + "\n\ttimestamp = " + timestamp);
        }
        String hourString = timestamp.substring(9, 11);
        String minuteString = timestamp.substring(11, 13);
        String secondString = timestamp.substring(13, 15);

        int hour = Integer.parseInt(hourString);
        int minute = Integer.parseInt(minuteString);
        int second = Integer.parseInt(secondString);

        return new ImmutualTime(hour, minute, second);
    }

    /**
     * Ermittelt das Datum und die Uhrzeit aus einem Timestamp.
     *
     * @param timestamp
     *            Timestamp im Format "JJJJMMDD_HHMMSS" und ggf. noch Zeichen dahinter.
     * @return Datum und Uhrzeit.
     */
    public static DateAndTime getDateAndTimeFromTimestamp(String timestamp) {
        ImmutualDate date = getDateFromTimestamp(timestamp);
        ImmutualTime time = getTimeFromTimestamp(timestamp);
        return new DateAndTime(date, time);
    }

    /**
     * Gibt an, ob der übergebene Text dem Standard-Timestamp-Format (acht Ziffer, Unterstrich,
     * sechs Ziffern) entspricht.
     */
    public static boolean isTimestamp(String timestamp) {
        Matcher matcher = STANDARD_TIMESTAMP_PATTERN.matcher(timestamp);
        return matcher.matches();
    }

}
