/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

function Day(date, yyyy, mm, dd, day, time) {
    this.yyyy = yyyy || 0;
    this.mm = mm || 0;
    this.dd = dd || 0;
    this.date = date || '';
    this.wday = day || '';
    this.time = time || 0;
}

const MILLIS_PER_SECOND     = exports.MILLS_PER_SECOND = 1000;
const MILLIS_PER_MINUTE     = 60 * MILLIS_PER_SECOND;
const MILLIS_PER_HOUR       = 60 * MILLIS_PER_MINUTE;
const MILLIS_PER_DAY        = 24 * MILLIS_PER_HOUR;
const MILLIS_PER_TEN_MINUTE = 10 * MILLIS_PER_MINUTE;
const MILLIS_PER_FIVE_MINUTE = 5 * 60 * MILLIS_PER_SECOND;

const wday = ["Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun" ];
const mdayLen = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

function DateTimeHelper() {

    this.BASE_TIME = new Date('01/01/2000').getTime();
    this.table = new Array(100) /*[][][]*/;
    this.dateTable = new Array(40000);
    this.LAST_DATE = 0;

    this.open();
}

DateTimeHelper.prototype.getBaseTime = function () {
    return this.BASE_TIME;
};
DateTimeHelper.prototype.open = function () {
    var mtime = this.BASE_TIME;
    var seq = 0;
    var wdayIdx = 5; // 20000101:Saturday

    for(var year = 0; year < 100; year++) {
        var isYun = _isYun(year);
        this.table[year] = new Array(12);
        for(var mm = 0; mm < 12;  mm++) {
            var monLen = mdayLen[mm];
            if(mm ===1 && isYun) {
                monLen++;
            }
            this.table[year][mm] = new Array(monLen);
            for(var dd = 0; dd < monLen; dd++) {
                var yyyyMMdd = (year + 2000) + '' + zeroPad((mm + 1), 10) + '' + zeroPad((dd + 1), 10) + '';
                this.dateTable[seq] = new Day(yyyyMMdd, (year + 2000), mm + 1 , dd + 1, wday[wdayIdx], mtime);
                this.table[year][mm][dd] = this.dateTable[seq];
                wdayIdx = (wdayIdx === 6 ? 0 : wdayIdx + 1);
                seq++;
                mtime += MILLIS_PER_DAY;
            }
        }
    }
    this.LAST_DATE = seq - 1;
};
DateTimeHelper.prototype.yyyymmdd = function(yyyyMMdd) {
    if(typeof yyyyMMdd === 'string') {
        var year = parseInt(yyyyMMdd.substr(0, 4));
        var mm = parseInt(yyyyMMdd.substr(4, 2));
        var dd = parseInt(yyyyMMdd.substr(6, 2));

        if(year >= 2100) {
            return this.table[99][11][30].time + MILLIS_PER_DAY;
        }

        if(year < 2000) {
            return this.BASE_TIME;
        }
        return this.table[year - 2000][mm-1][dd-1].time;
    } else if(typeof yyyyMMdd === 'number') {
        var time = yyyyMMdd;
        var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
        if(idx < 0)
            idx = 0;
        return this.dateTable[idx].date;
    }
};
DateTimeHelper.prototype.hhmm = function (date) {
    if(date == null) {
        return 0;
    }
    if(typeof date === 'string') {
        var h = parseInt(date.substr(0, 2));
        var m = parseInt(date.substr(2, 2));
        return h * MILLIS_PER_HOUR + m * MILLIS_PER_MINUTE;
    } else if(typeof date === 'number') {
        var time = date;
        if(time < this.BASE_TIME) {
            return "0000";
        }
        var dtime = (time - this.BASE_TIME) % MILLIS_PER_DAY;
        var hh = parseInt(dtime / MILLIS_PER_HOUR);
        dtime = parseInt(dtime % MILLIS_PER_HOUR);
        var mm = parseInt(dtime / MILLIS_PER_MINUTE);
        return zeroPad(hh, 10) + '' + zeroPad(mm, 10);
    }

    return 0;
};
DateTimeHelper.prototype.yyyymmddhh = function (time) {
    var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
    if(idx < 0)
        idx = 0;
    var dtime = (time - this.BASE_TIME) % MILLIS_PER_DAY;
    var hh = parseInt(dtime / MILLIS_PER_HOUR);
    return this.dateTable[idx].date + zeroPad(hh, 10);
}
DateTimeHelper.prototype.weekday = function (time) {
    var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
    if(idx < 0)
        idx = 0;
    return this.dateTable[idx].wday;
};
DateTimeHelper.prototype.getYear = function (time, delta) {

    if(time < this.BASE_TIME) {
        return this.BASE_TIME;
    }

    var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
    var year = this.dateTable[idx].yyyy + delta;
    var mm = this.dateTable[idx].mm;
    var dd = this.dateTable[idx].dd;

    if(year < 2000) {
        return this.BASE_TIME;
    }
    if(year > 2100) {
        return this.dateTable[this.LAST_DATE].time;
    }
    var dtime = (time - this.BASE_TIME) % MILLIS_PER_DAY;
    return this.table[year - 2000][mm - 1][dd - 1].time + dtime;
};
DateTimeHelper.prototype.getMonth = function (time, delta) {
    if(time < this.BASE_TIME) {
        return this.BASE_TIME;
    }

    var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
    var year = this.dateTable[idx].yyyy;
    var mm = this.dateTable[idx].mm;
    var dd = this.dateTable[idx].dd;
    delta = delta + mm - 1;

    var deltaYear = Math.floor(delta / 12);
    var deltaMM = delta % 12;
    if(deltaMM < 0) {
        deltaYear--;
        deltaMM = 12 + deltaMM;
    }
    year += deltaYear;
    mm = deltaMM + 1;
    if(year < 2000) {
        return this.BASE_TIME;
    }

    if(year > 2100) {
        return this.dateTable[this.LAST_DATE].time;
    }

    var dtime = (time - this.BASE_TIME) % MILLIS_PER_DAY;
    return this.table[year - 2000][mm - 1][dd - 1].time + dtime;
};
DateTimeHelper.prototype.getDate = function (time, delta) {
    if(time < this.BASE_TIME) {
        return this.BASE_TIME;
    }
    var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
    var dtime = (time - this.BASE_TIME) % MILLIS_PER_DAY;

    idx += delta;
    if(idx < 0) {
        return this.BASE_TIME;
    }
    if(idx >= this.LAST_DATE) {
        return this.dateTable[this.LAST_DATE].time;
    }
    return this.dateTable[idx].time + dtime;
};
DateTimeHelper.prototype.logtime = function (time) {
    if(time < this.BASE_TIME) {
        return "00:00:00.000";
    }
    var dtime = (time - this.BASE_TIME) % MILLIS_PER_DAY;
    var hh = parseInt(dtime / MILLIS_PER_HOUR);
    dtime = parseInt(dtime % MILLIS_PER_HOUR);
    var mm = parseInt(dtime / MILLIS_PER_MINUTE);
    dtime = parseInt(dtime % MILLIS_PER_MINUTE);
    var ss = parseInt(dtime / MILLIS_PER_SECOND);
    var sss = parseInt(dtime % 1000);
    var string = zeroPad(hh, 10) + ":" + zeroPad(mm, 10) + ":" + zeroPad(ss, 10) + "." + zeroPad(sss, 1000);
    return string;
}
DateTimeHelper.prototype.datetime = function (time) {
    if(time < this.BASE_TIME) {
        return "20000101 00:00:00";
    }
    var idx = parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY);
    var dtime = parseInt((time - this.BASE_TIME) % MILLIS_PER_DAY);
    var hh = parseInt(dtime / MILLIS_PER_HOUR);
    dtime = parseInt(dtime % MILLIS_PER_HOUR);
    var mm = parseInt(dtime / MILLIS_PER_MINUTE);
    dtime = parseInt(dtime % MILLIS_PER_MINUTE);
    var ss = parseInt(dtime / MILLIS_PER_SECOND);
    var sb = this.dateTable[idx].date;
    sb += " ";
    sb += zeroPad(hh, 10);
    sb += ":";
    sb += zeroPad(mm, 10);
    sb += ":";
    sb += zeroPad(ss, 10);
    return sb;
};
DateTimeHelper.prototype.getDateUnit = function (time) {
    return parseInt((time - this.BASE_TIME) / MILLIS_PER_DAY)
};

function _isYun(year) {
    if ((year % 4 === 0 && year % 100 != 0) || year % 400 === 0)
        return true;
    else
        return false;
};
function zeroPad(nr,base){
    var  len = (String(base).length - String(nr).length)+1;
    return len > 0? new Array(len).join('0')+nr : nr;
};

module.exports = DateTimeHelper;