﻿(function () {
    if (typeof (window["util"]) == "undefined") util = {};

    // seeks the first Monday within [-inf, date]
    util.firstDayOfWeek = function (date) {
        if (date && !isNaN(date)) {
            while (date.getDay() != 1) {
                date = new Date(date.valueOf());
                date.setDate(date.getDate() - 1);
            }

            date = util.trimDate(date, "D", "startdate");
        }

        return date;
    };

    // seeks the first Sunday within [date, +inf]
    util.lastDayOfWeek = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setDate(date.getDate() + 7);
            date = util.firstDayOfWeek(date);
            date.setDate(date.getDate() - 1);
            date = util.trimDate(date, "D", "enddate");
        }

        return date;
    };

    util.firstDayOfMonth = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setDate(1);
            date = util.trimDate(date, "D", "startdate");
        }

        return date;
    }

    util.lastDayOfMonth = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setDate(28);

            while (date.getDate() != 1) {
                date = new Date(date.valueOf());
                date.setDate(date.getDate() + 1);
            }

            date.setDate(date.getDate() - 1);
            date = util.trimDate(date, "D", "enddate");
        }

        return date;
    };

    util.firstDayOfQuarter = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setMonth(Math.floor(date.getMonth() / 3) * 3);
            date = util.firstDayOfMonth(date);
        }

        return date;
    }

    util.lastDayOfQuarter = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setMonth(Math.floor(date.getMonth() / 3) * 3 + 2);
            date = util.lastDayOfMonth(date);
        }

        return date;
    };

    util.firstDayOfYear = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setMonth(0);
            date = util.firstDayOfMonth(date);
        }

        return date;
    }

    util.lastDayOfYear = function (date) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
            date.setMonth(11);
            date = util.lastDayOfMonth(date);
        }

        return date;
    };

    util.trimDate = function (date, discrecity, role) {
        if (date && !isNaN(date)) {
            date = new Date(date.valueOf());
        }

        if (discrecity == "D") {
            if (date && !isNaN(date)) {
                if (role == "enddate") date.setHours(23, 59, 59, 999);
                else date.setHours(0, 0, 0, 0);
            }
        } else if (discrecity == "W") {
            if (date && !isNaN(date)) {
                if (role == "enddate") date = util.lastDayOfWeek(date);
                else date = util.firstDayOfWeek(date);
            }
        } else if (discrecity == "M") {
            if (date && !isNaN(date)) {
                if (role == "enddate") date = util.lastDayOfMonth(date);
                else date = util.firstDayOfMonth(date);
            }
        } else if (discrecity == "Q") {
            if (date && !isNaN(date)) {
                if (role == "enddate") date = util.lastDayOfQuarter(date);
                else date = util.firstDayOfQuarter(date);
            }
        } else if (discrecity == "Y") {
            if (date && !isNaN(date)) {
                if (role == "enddate") date = util.lastDayOfYear(date);
                else date = util.firstDayOfYear(date);
            }
        } else if (discrecity == "S") {
            if (date && !isNaN(date)) {
                if (role == "enddate") date.setHours(23, 59, 59, 999);
                else date.setHours(0, 0, 0, 0);
            }
        } else {
            throw "unsupported discrecity " + discrecity;
        }

        return date;
    };

    var months = [];
    months["Январь"] = months["январь"] = 1;
    months["Февраль"] = months["февраль"] = 2;
    months["Март"] = months["март"] = 3;
    months["Апрель"] = months["апрель"] = 4;
    months["Май"] = months["май"] = 5;
    months["Июнь"] = months["июнь"] = 6;
    months["Июль"] = months["июль"] = 7;
    months["Август"] = months["август"] = 8;
    months["Сентябрь"] = months["сентябрь"] = 9;
    months["Октябрь"] = months["октябрь"] = 10;
    months["Ноябрь"] = months["ноябрь"] = 11;
    months["Декабрь"] = months["декабрь"] = 12;

    util.parseDate = function (s, discrecity, role) {
        var full = /^\s*(\d+)\.(\d+)\.(\d+)\s*$/;
        var m_full = s.match(full);

        if (discrecity == "D") {
            if (m_full != null) {
                var day = m_full[1];
                var month = m_full[2] - 1;
                var year = m_full[3];
                var date = new Date(year, month, day);
                if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                return util.trimDate(date, discrecity, role);
            }
        } else if (discrecity == "W") {
            if (m_full != null) {
                var day = m_full[1];
                var month = m_full[2] - 1;
                var year = m_full[3];
                var date = new Date(year, month, day);
                if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                return util.trimDate(date, discrecity, role);
            }
        } else if (discrecity == "M") {
            if (m_full != null) {
                var day = m_full[1];
                var month = m_full[2] - 1;
                var year = m_full[3];
                var date = new Date(year, month, day);
                if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                return util.trimDate(date, discrecity, role);
            } else {
                var short = /^\s*(\d+)\.(\d+)\s*$/;
                var m_short = s.match(short);

                if (m_short != null) {
                    var day = 1;
                    var month = m_short[1] - 1;
                    var year = m_short[2];
                    var date = new Date(year, month, day);
                    if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                    return util.trimDate(date, discrecity, role);
                } else {
                    var iof = s.indexOf(" ");
                    if (iof != -1) {
                        var s_month = $.trim(s.slice(0, iof));
                        var s_year = $.trim(s.slice(iof + 1));

                        var day = 1;
                        var month = months[s_month] ? months[s_month] - 1 : null;
                        var year = !isNan(parseInt(s_year, 10)) ? parseInt(s_year, 10) : null;
                        if (year != null && year.toString() != s_year) year = null;

                        if (month != null && year != null) {
                            var date = new Date(year, month, day);
                            if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                            return util.trimDate(date, discrecity, role);
                        }
                    }
                }
            }
        } else if (discrecity == "Q") {
            if (m_full != null) {
                var day = m_full[1];
                var month = m_full[2] - 1;
                var year = m_full[3];
                var date = new Date(year, month, day);
                if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                return util.trimDate(date, discrecity, role);
            } else {
                var short = /^\s*(\d+)\.(\d+)\s*$/;
                var m_short = s.match(short);

                if (m_short != null) {
                    var day = 1;
                    var month = parseInt(m_short[1], 10) * 3 - 1;
                    var year = m_short[2];
                    var date = new Date(year, month, day);
                    if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                    return util.trimDate(date, discrecity, role);
                }
            }
        } else if (discrecity == "Y") {
            if (m_full != null) {
                var day = m_full[1];
                var month = m_full[2] - 1;
                var year = m_full[3];
                var date = new Date(year, month, day);
                if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                return util.trimDate(date, discrecity, role);
            } else {
                var short = /^\s*(\d+)\s*$/;
                var m_short = s.match(short);

                if (m_short != null) {
                    var day = 1;
                    var month = 1;
                    var year = m_short[1];
                    var date = new Date(year, month, day);
                    if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                    return util.trimDate(date, discrecity, role);
                }
            }
        } else if (discrecity == "S") {
            if (m_full != null) {
                var day = m_full[1];
                var month = m_full[2] - 1;
                var year = m_full[3];
                var date = new Date(year, month, day);
                if (date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) return null;
                return util.trimDate(date, discrecity, role);
            }
        } else {
            throw "unsupported discrecity " + discrecity;
        }
    }
})();
