/**
* Helper-Script, fuer Daten und Zeiten
**/
(function() {
// Inet-Library-"package" holen
var iLibs = window.iLibs;
if (typeof(iLibs) == "undefined" || iLibs == null) {
    iLibs = {};
    window.iLibs = iLibs;
}
// Die urspruengliche "$D"-Variable sichern
if (window.$D)
    var _$D = window.$D;

var DateHelper = {
    id:             "DateHelper",                                   // Die eindeutige Id, dieser Library
    dependencies:   [                                               // Abhaengigkeiten mit anderen Libraries
                        "DependencyHandler",
                        "JSUtils"
                    ],

    DateFormat: {
        OFFSET:     "Offset",
        DD_MM_YYYY: "dd_mm_yyyy",
        YYYY_MM_DD: "yyyy_mm_dd",
        DD_MM_YY: "dd_mm_yy",
        DDMM: "ddmm",
        DDMMYY: "ddmmyy",
        DDMMYYYY: "ddmmyyyy"
    },

    DAY_MILLISECONDS:   1000 * 3600 * 24,

    DATE_FORMAT:        "dateFormat",
    ALLOWED_SEPARATORS: "allowedSeparators",

    DEFAULT_DATE_SEPARATORS: [".", ",", "-", "/"],
    DEFAULT_TIME_SEPARATORS: [".", ",", ":", "-", "/"],

    /**
    * Wenn keine globale Variable "$D" gesetzt werden soll und die urspruengliche Variable wiederhergestellt werden soll
    * (falls andere Libraries verwendet werden, welche dieselbe Variable verwenden), kann mit dieser Methode der
    * Ursprungszustand hergestellt werden und man bekommt dadurch die Moeglichkeit, einen eigenen Variablennamen zu
    * vergeben.
    * @return this
    **/
    noConflict: function noConflict() {
        window.$D = _$D;
        return this;
    },

    /**
    * Parst das uebergebene Datum und liefert das entsprechende Date-Objekt zurueck.
    * @param sDate          Das zu parsende Datum
    * @param jOptions       Optionen in Form einer JSON-Expression (optional). Moegliche Werte:
    *                       dateFormat:         Das Dateformat, welches versucht werden soll zu parsen. Erlaubte Werte
    *                                           siehe this.DateFormat. Default: Es wird automatisch versucht, das
    *                                           Datumsformat zu erkennen (ueber die recognize DateFormat-Methode)
    *                       allowedSeparators:  Erlaubte Separatoren. Dies kann ein einzelnes Zeichen sein (zb. ".")
    *                                           oder ein Array von erlaubten Separatoren. Allerdings muessen alle
    *                                           Separatoren im Datum vom selben Typ sein.
    *                                           Default: this.DEFAULT_DATE_SEPARATORS
    * @return Das geparste Date-Objekt. null, wenn es nicht geparst werden konnte.
    **/
    getDate: function getDate(sDate, jOptions) {
        if (!$U.$S(sDate))
            return null;
        var sFormat = $U.$P(jOptions, this.DATE_FORMAT, null);
        sFormat = sFormat != null ? sFormat : this.recognizeDateFormat(sDate);
        if (sFormat === null)
            return null;
        // Datum mit Heute +/- x Tagen, bzw. "0" fuer heute
        if (sFormat == this.DateFormat.OFFSET) {
            if (isNaN(sDate))
                return null;
            return this.addDays(Number(sDate));
        }
        var sSeparator = this.getDateSeparator(sDate, $U.$P(jOptions, this.ALLOWED_SEPARATORS, null));
        var tNewDate = null;
        var iDay;
        var iMonth;
        var asSegs = sDate.split(sSeparator);
        if (asSegs.length != 1 && asSegs.length != 3) {
            return null;
        }
        for (var i = 0; i< asSegs.length; i++) {
            if (isNaN(asSegs[i]))
                return null;
        }
        // dd_mm_yyyy
        if (sFormat == this.DateFormat.DD_MM_YYYY) {
            iDay = Number(asSegs[0]);
            iMonth = Number(asSegs[1]) - 1;
            tNewDate = new Date(Number(asSegs[2]), iMonth, iDay);
        }
        // yyyy_mm_dd
        else if (sFormat == this.DateFormat.YYYY_MM_DD) {
            iDay = Number(asSegs[2]);
            iMonth = Number(asSegs[1]) - 1;
            tNewDate = new Date(Number(asSegs[0]), iMonth, iDay);
        }
        // dd_mm_yy
        else if (sFormat == this.DateFormat.DD_MM_YY) {
            iDay = Number(asSegs[0]);
            iMonth = Number(asSegs[1]) - 1;
            tNewDate = new Date(Number("20" + asSegs[2]), iMonth, iDay);
        }
        // ddmm
        else if (sFormat == this.DateFormat.DDMM) {
            iDay = Number(sDate.substring(0, 2));
            iMonth = Number(sDate.substring(2, 4)) - 1;
            tNewDate = new Date(Number(new Date().getFullYear()), iMonth, iDay);
        }
        // ddmmyy
        else if (sFormat == this.DateFormat.DDMMYY) {
            iDay = Number(sDate.substring(0, 2));
            iMonth = Number(sDate.substring(2, 4)) - 1;
            tNewDate = new Date(Number("20" + sDate.substring(4, 6)), iMonth, iDay);
        }
        // ddmmyyyy
        else if (sFormat == this.DateFormat.DDMMYYYY) {
            iDay = Number(sDate.substring(0, 2));
            iMonth = Number(sDate.substring(2, 4)) - 1;
            tNewDate = new Date(Number(sDate.substring(4)), iMonth, iDay);
        }

        // Javascript akzeptiert Tage, bzw. Monate ausserhalb der gueltigen Bereiche und rechnet damit einfach
        // weiter in die Zukunft. Dh. der 33.1.2000 waere dann der 2.2.2000, bzw. der 1.15.2000 waere dann der
        // 1.4.2001. Das wollen wir aber nicht, sondern wir erwarten uns ein "gueltiges" Datum
        if ($U.$S(tNewDate) && (tNewDate.getDate() != iDay || tNewDate.getMonth() != iMonth))
            return null;

        return tNewDate;
    },

    /**
    * Diese Methode versucht, anhand des uebergebenen Datums, das Datumsformat zu erkennen
    * @param sDate  Das Datum, anhand dessen das Datumsformat erkannt werden soll.
    * @return Das erkannte Datumsformat (Element des DateFormat-Objekts). null, wenn es nicht erkannt werden konnte
    **/
    recognizeDateFormat: function recognizeDateFormat(sDate) {
        if (!$U.$S(sDate))
            return null;
        // Offset-Format, wenn +/- an erster Stelle steht, bzw. wenn nur 0 angegeben wurde
        if (sDate.indexOf("+") == 0 || sDate.indexOf("-") == 0 || sDate == "0")
            return this.DateFormat.OFFSET;
        // dd_mm_yyyy oder yyyy_mm_dd oder dd_mm_yy - Format. Wobei mit den DEFAULT_DATE_SEPARATORS verglichen wird
        var asSegments = [];
        for (var i = 0; i < this.DEFAULT_DATE_SEPARATORS.length; i++) {
            asSegments = sDate.split(this.DEFAULT_DATE_SEPARATORS[i]);
            if (asSegments.length == 3) {
                // dd_mm_yyyy
                if (asSegments[0].length <= 2
                && asSegments[1].length <= 2
                && asSegments[2].length == 4)
                    return this.DateFormat.DD_MM_YYYY;
                // yyyy_mm_dd
                else if (asSegments[0].length == 4
                && asSegments[1].length <= 2
                && asSegments[2].length <= 2)
                    return this.DateFormat.YYYY_MM_DD;
                // dd_mm_yy
                else if (asSegments[0].length <= 2
                && asSegments[1].length <= 2
                && asSegments[2].length == 2)
                    return this.DateFormat.DD_MM_YY;
            }
        }
        if (asSegments.length == 1) {
            // ddmm
            if (sDate.length == 4)
                return this.DateFormat.DDMM;
            // ddmmyy
            else if (sDate.length == 6)
                return this.DateFormat.DDMMYY;
            // ddmmyyyy
            else if (sDate.length == 8)
                return this.DateFormat.DDMMYYYY;
        }

        return null;
    },

    /**
    * Liefert das uebergebene Datum, ohne Uhrzeit.
    * @param tDate Das Date-Objekt, dessen Zeit entfernt werden soll.
    * @return Das uebergebene Datum, ohne Uhrzeit. null, wenn tDate null oder undefined ist
    **/
    truncTime: function truncTime(tDate) {
        if (!$U.$S(tDate))
            return null;
        return new Date(tDate.getFullYear(), tDate.getMonth(), tDate.getDate());
    },

    /**
    * Liefert das (tDate + iDays) - Datum zurueck. Wenn tDate nicht uebergeben wird, bzw. null ist, wird als
    * Referenz-Datum das heutige Datum verwendet. iDays kann auch negativ sein (wenn Tage abgezogen werden sollen).
    * Die Uhrzeit bleibt dabei erhalten.
    * @param iDays  Tage die zum Referenzdatum hinzugezaehlt / abgezogen werden sollen.
    * @param tDate  Das Referenzdatum (optional). Wenn das Datum nicht mituebergeben wird, wird das heutige Datum als
    *               Referenzdatum verwendet
    * @return Das neue Date-Objekt. null, wenn iDays nicht gesetzt oder keine Zahl ist
    **/
    addDays: function addDays(iDays, tDate) {
        var tReference = $U.$S(tDate) ? tDate : new Date();
        if (!$U.$S(iDays) || isNaN(iDays))
            return null;
        tReference.setDate(tReference.getDate() + iDays);
        return tReference;
    },

    /**
    * Versucht den Separator, im uebergebenen Datum, zu erkennen.
    * @param sDate          Der Datumstring, anhand dessen der Separator erkannt werden soll.
    * @param asSeparator    Die Liste der erlaubten Separatoren (optional). Kann auch nur ein einzelnes Zeichen sein.
    *                       Wenn dieser Parameter nicht uebergeben wird, wird die Default-Liste der moeglichen
    *                       Separatoren fuer die Ermittlung verwendet (this.DEFAULT_DATE_SEPARATORS)
    * @return Der Separator, welcher gefunden wurde, bzw. null, wenn sDate undefined oder null ist, bzw. der Separator
    *                       nicht ermittelt werden konnte
    **/
    getDateSeparator: function getDateSeparator(sDate, asSeparator) {
        if (!$U.$S(sDate) || ($U.$S(asSeparator) && asSeparator === ""))
            return null;
        // Wenn kein Separator, bzw. Array von Separatoren uebergeben wurden, werden die Default-Separatoren verwendet
        var asSeps = $U.$S(asSeparator) ? asSeparator instanceof Array ? asSeparator : [asSeparator]
            : this.DEFAULT_DATE_SEPARATORS;
        for (var i = 0; i < asSeps.length; i++) {
            if (sDate.indexOf(asSeps[i]) != -1)
                return asSeps[i];
        }
        return null;
    },

    /**
    * Liefert die geparste Uhrzeit als Date-Objekt (mit new Date(0, 0, 0) als Datum).
    * @param sTime          Die zu parsende Zeit
    * @param jOptions       Optionen in Form einer JSON-Expression (optional). Moegliche Werte:
    *                       allowedSeparators:  Erlaubte Separatoren. Dies kann ein einzelnes Zeichen sein (zb. ".")
    *                                           oder ein Array von erlaubten Separatoren. Allerdings muessen alle
    *                                           Separatoren im Datum vom selben Typ sein.
    *                                           Default: this.DEFAULT_DATE_SEPARATORS
    * @return Die geparste Uhrzeit, als Date-Objekt. null, wenn die Uhrzeit nicht geparst werden konnte
    **/
    getTime: function getTime(sTime, jOptions) {
        var tTime = null;
        if (!$U.$S(sTime))
            return null;
        var sSeparator = this.getTimeSeparator(sTime, $U.$P(jOptions, this.ALLOWED_SEPARATORS, null));
        var asSegments = sTime.split(sSeparator);
        if (asSegments.length > 3)
            return null;
        for (var i = 0; i < asSegments.length; i++) {
            if (isNaN(asSegments[i]))
                return null;
        }
        var iHours = null;
        var iMinutes = null;
        var iSeconds = null;
        if (asSegments.length == 1 && asSegments[0] != "") {
            iHours = sTime.substring(0,2);
            iMinutes = sTime.substring(2,4);
            iSeconds = sTime.substring(4,6) != null ? sTime.substring(4,6) : "0";
        } else {
            iHours = $U.$P(asSegments, 0);
            iMinutes = $U.$P(asSegments, 1);
            iSeconds = $U.$P(asSegments, 2, 0); // Wenn die Sekunden nicht gesetzt sind, werden 0 Sekunden verwendet
        }
        var tNewDate = new Date(0, 0, 0, iHours, iMinutes, iSeconds);
        if (tNewDate.getHours() != iHours || tNewDate.getMinutes() != iMinutes || tNewDate.getSeconds() != iSeconds)
            return null;
        return tNewDate;
    },

    /**
    * Versucht den Separator, in der uebergebenen Zeit, zu erkennen.
    * @param sTime          Der Zeitstring, anhand dessen der Separator erkannt werden soll.
    * @param asSeparator    Die Liste der erlaubten Separatoren (optional). Kann auch nur ein einzelnes Zeichen sein.
    *                       Wenn dieser Parameter nicht uebergeben wird, wird die Default-Liste der moeglichen
    *                       Separatoren fuer die Ermittlung verwendet (this.DEFAULT_TIME_SEPARATORS)
    * @return Der Separator, welcher gefunden wurde, bzw. null, wenn sTime undefined oder null ist, bzw. der Separator
    *                       nicht ermittelt werden konnte
    **/
    getTimeSeparator: function getTimeSeparator(sTime, asSeparator) {
        if (!$U.$S(sTime) || ($U.$S(asSeparator) && asSeparator === ""))
            return null;
        // Wenn kein Separator, bzw. Array von Separatoren uebergeben wurden, werden die Default-Separatoren verwendet
        var asSeps = $U.$S(asSeparator) ? asSeparator instanceof Array ? asSeparator : [asSeparator]
            : this.DEFAULT_TIME_SEPARATORS;
        for (var i = 0; i < asSeps.length; i++) {
            if (sTime.indexOf(asSeps[i]) != -1)
                return asSeps[i];
        }
        return null;
    },

    /**
    * Liefert das Ende des angegebenen Tages (Datum + 23:59:59:999). Wenn kein Datum uebergeben wurde, wird das Ende des
    * heutigen Tages geliefert.
    * @param tDate  Das Datum, dessen Ende zurueckgeliefert werden soll (optional)
    * @return Das Datum mit der End-Uhrzeit. null, wenn tDate kein Date-Objekt ist
    **/
    getEndOfDay: function getEndOfDay(tDate) {
        var tTemp = $U.$S(tDate) ? tDate : new Date();
        if (!(tTemp instanceof Date))
            return null;
        return new Date(this.addDays(1, this.truncTime(tTemp)).getTime() - 1);
    },

    /**
    * Liefert die Zeit, als String, im Format HH:MM
    * @param tDate  Die Uhrzeit, welches als String ausgegeben werden soll
    * @return Die Uhrzeit, als String
    **/
    getTimeString: function getTimeString(tDate) {
        if (tDate === null)
            return "";
        var sResult = "";
        var sTemp = new String(tDate.getHours());
        sTemp = sTemp.length == 2 ? sTemp : "0" + sTemp;
        sResult += sTemp + ":";
        sTemp = new String(tDate.getMinutes());
        sTemp = sTemp.length == 2 ? sTemp : "0" + sTemp;
        return sResult + sTemp;
    },

    /**
    * Liefert das Datum, als String, im Format dd.mm.yyyy
    * @param tDate  Das Datum, welches als String ausgegeben werden soll
    * @return Das Datum, als String
    **/
    getDateString: function getDateString(tDate) {
        if (tDate === null)
            return "";
        var sDate = "";
        var sTmp = new String(tDate.getDate());
        sTmp = sTmp.length == 1 ? "0" + sTmp : sTmp;
        sDate += sTmp + ".";
        sTmp = new String(tDate.getMonth() + 1);
        sTmp = sTmp.length == 1 ? "0" + sTmp : sTmp;
        sDate += sTmp + ".";
        sTmp = tDate.getYear();
        sTmp = sTmp <= 1000 ? sTmp + 1900 : sTmp;
        sDate += sTmp;
        return sDate;
    }

};

// Den DateHelper im inet-Library-Package als globale Variable zur Verfuegung stellen
iLibs["DateHelper"] = DateHelper;
// Den DateHelper, als globale $D-Variable zuer Verfuegung stellen
window.$D = DateHelper;
// Den DateHelper in die Liste der geladenen Libraries aufnehmen
var _aoLoadedLibs = window.$LoadedLibs;
if (typeof(_aoLoadedLibs) == "undefined" || _aoLoadedLibs == null) {
    _aoLoadedLibs = [];
    window.$LoadedLibs = _aoLoadedLibs;
}
_aoLoadedLibs[_aoLoadedLibs.length] = DateHelper;
})();