/**================================================ 
 * DateFormat version 1.1 (Standard Version)
 * Created: 01 December 2008
 * Created by: Zaenal - http://www.lokamaya.net
 * ================================================
 * Copyright (c) 2008 Zaenal - http://www.lokamaya.net 
 * Some rights reserved. This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 Unported License.
 * 
 * You are free:
 * ----------------------------------------------------------
 * - to Share your copy, distribute and transmit the work
 * - to Remix to adapt the work
 *
 * Under the following conditions:
 * - Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
 * - Noncommercial. You may not use this work for commercial purposes.
 * - Your project (commercial or non-commercial)
 *
 * For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
 * Any of the above conditions can be waived if you get permission from the copyright holder.
 * Nothing in this license impairs or restricts the author's moral rights.
 * 
 * And not free for:
 * ----------------------------------------------------------
 * - Selling package (included in your selling product)
 *
 * If you want to include this work in a selling package, mail me : public AT lokamaya DOT com        
 *
 * ================================================
 * Demo: http://code.lokamaya.net/dateformat/
 * Blog: http://blog.lokamaya.net
 * ================================================
 *
 * Requirement: -
 * 
 * PHP#strftime FORMAT CONVERSION Support:
 * %a, %A, %b or %h, %B, %C, %d, %e, %H, %I, %j, %m, %M, %n, %p, %r, %S, %u, %w, %y, %Y or %G, %Z or %z
 * and I add:
 * %F for calculating the week of month (not supported in PHP#strftime)
**/

/* LANGUAGE HANDLER */
/* You can edit or populate as many language as needed */
var DateFormatLang = new Array();
DateFormatLang.Populate = function(lang, defaultFormat, arrayMonths, arrayMonthsAbbr, arrayDays, arrayDaysAbbr) {
    DateFormatLang[lang] = DateFormatLang.Populate.arguments;
};
//Populate English language
DateFormatLang.Populate('en', 
    '%m/%d/%Y',
    ['January','February','March','April','May','June','July','August','September','October','November','December'],
    ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
    ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
    ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']);
//Populate Indonesia language
DateFormatLang.Populate('id', 
    '%d/%m/%Y',
    ['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','Nopember','Desember'],
    ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'],
    ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'],
    ['Ming','Sen','Sel','Rab','Kam','Jum','Sab']);

/**================================================
Do not edit anything below this line, 
except you know what you are doing
***================================================*/

/* EXTEND DEFAULT DATE OBJECT */
Date.prototype.getDayOfYear = function() {
    var firstyear = new Date(this.getFullYear(),0,1);
    return Math.ceil((this - firstyear) / 86400000);
}
Date.prototype.getWeekOfYear = function() {
    var firstyear = new Date(this.getFullYear(),0,1);
    return Math.ceil((((this - firstyear) / 86400000) + firstyear.getDay())/7);
}
Date.prototype.getWeekOfMonth = function() {
    return Math.ceil((this.getDate() + (6 - this.getDay())) /7);
}
//Extend toJSON taken from prototype.js
Date.prototype.toJSON = function() {
  return '"' + this.getUTCFullYear() + '-' +
    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
    this.getUTCDate().toPaddedString(2) + 'T' +
    this.getUTCHours().toPaddedString(2) + ':' +
    this.getUTCMinutes().toPaddedString(2) + ':' +
    this.getUTCSeconds().toPaddedString(2) + 'Z"';
};

/* DATEFORMAT CLASS */
var DateFormat = function(option) {this.initialize.apply(this, arguments);}
DateFormat.Extend = function(){this.prototype = DateFormatPrototype;};

var DateFormatPrototype = {
        defaultLang: 'en',
        defaultFormat: '%m/%d/%Y',
        property: {
            lang: 'en',
            utc: false,
            format: '%m/%d/%Y',
            months: [],
            monthsAbbr: [],
            days: [],
            daysAbbr: []
        },
        initialize: function(property) {
            var lang = property.lang || this.defaultLang;
            if (typeof DateFormatLang[lang] == 'undefined') {
                alert('Can not find language "'+lang+'" configuration for DateFormat.'+"\n"+'Using default language:"'+this.defaultLang+'"');
                lang = this.defaultLang;
            }
            this.oDate = null;
            this.hDate = null;
            this.property.lang = lang;
            this.property.utc = property.utc || false;
            //this.defaultFormat = DateFormatLang[lang][1];
            this.property.format = property.format || DateFormatLang[lang][1];
            this.property.months = DateFormatLang[lang][2];
            this.property.monthsAbbr = DateFormatLang[lang][3];
            this.property.days = DateFormatLang[lang][4];
            this.property.daysAbbr = DateFormatLang[lang][5];
        },
        valid: function(val, format) {
            return;
        },
        compare: function(options1,options2) {
            return;
        },
        toFormat: function(format) {
            format = format ? format : this.property.format;   
            var rep = '', place = '', that=this;
            var str = format;
            format.scan(/%[a-zA-Z%]/, function(match){
                    rep = that.formatCallback(match[0]);
                    place = new RegExp(match[0]);
                    str = str.replace(place, rep);
            });
            return str;
        },
        getDate: function(options, format) {
            this.setDate(options);
            return this.toFormat(format);
        },
        setUTC: function(utc) {
            return this.property.utc = ((utc===false || utc==0) ? false : true);
        },
        setDate: function(options, retval) {
            if (!options && this.hDate) return;
            var op = {};
            var oD = new Date();
            var oT = false;

            if (options.hour) op.hours = options.hour;
            if (options.minute) op.minutes = options.minute;
            if (options.second) op.seconds = options.second;
            
            if (options.format) {
                this.property.format = options.format;
            }
            if (options.time && options.time > 0) {
                oD.setTime(options.time);
                oT = true;
            } else {
                op.time = oD.getTime();
            }
            if (options.year && options.year > 0) {
                oD.setFullYear(options.year);
            } else {
                op.year = oD.getFullYear();
            }
            if (options.month && options.month > 0) {
                oD.setMonth(this.unTZ(options.month) -1);
            }
            op.month = oD.getMonth();
            
            if (options.Date && options.Date > 0) {
                oD.setDate(options.Date);
            } else {
                op.date = oD.getDate();
            }
            if (options.hours && options.hours > 0) {
                oD.setHours(this.unTZ(options.hours));
            } else {
                op.hours = oD.getHours();
            }
            if (options.minutes && options.minutes > 0) {
                oD.setMinutes(this.unTZ(options.minutes));
            } else {
                op.minutes = oD.getMinutes();
            }
            if (options.seconds && options.seconds > 0) {
                oD.setSeconds(this.unTZ(options.seconds));
            } else {
                op.seconds = oD.getSeconds();
            }
            if (options.milliseconds && options.milliseconds > 0) {
                oD.setMilliseconds(this.unTZ(options.milliseconds));
            } else {
                op.milliseconds = oD.getMilliseconds();
            }
            op.dayofweek = oD.getDay();
            this.oDate = oD;
            this.hDate = op;

            if (retval=='hash') return op;
            else if (retval=='object') return oD;
            else return;
        },
        toLocaleDateString: function(options) {
            this.setDate(options);
            //default javascript Date.toLocaleDateString
            return this.oDate.toLocaleDateString();
        },
        toString: function(options) {
            this.setDate(options);
            //default javascript Date.toString
            return this.oDate.toString();
        },
        toJSON: function(options) {
            this.setDate(options);
            return this.oDate.toJSON();
        },
        toObject: function(options) {
            this.setDate(options);
            return this.oDate;
        },
        toDate: function(val,format) {
            return;
        },
        formatCallback: function(x) {
            var oD = this.oDate;
            var tP = this.property;
            var utc = tP.utc && tP.utc===true ? true : false;
            if (!oD) return x;
            
            switch(x) {
                case '%a' :
                    return (utc ? tP.daysAbbr[oD.getUTCDay()] : tP.daysAbbr[oD.getDay()]);
                case '%A' :
                    return (utc ? tP.days[oD.getUTCDay()] : tP.days[oD.getDay()]);
                case '%b' : case '%h' :
                    return (utc ? tP.monthsAbbr[oD.getUTCMonth()] : tP.monthsAbbr[oD.getMonth()]);
                case '%B' :
                    return (utc ? tP.months[oD.getUTCMonth()] : tP.months[oD.getMonth()]);
                case '%d' :
                    return this.TZ(utc ? oD.getUTCDate() : oD.getDate());
                case '%e' :
                    return (utc ? oD.getUTCDate() : oD.getDate());
                case '%F' :
                    return oD.getWeekOfMonth();
                case '%H' :
                    return this.TZ(utc ? oD.getUTCHours() : oD.getHours());
                case '%I' : case '%p' :
                    var h = (utc ? oD.getUTCHours() : oD.getHours());
                    if (x=='%p') return (h >= 12 ? 'PM' : 'AM');
                    var hMod = this.TZ(h % 12);
                    if (hMod == '00') hMod = 12;
                    return hMod;
                case '%j' :
                    return oD.getDayOfYear();
                case '%m' :
                    return this.TZ(utc ? oD.getUTCMonth() + 1 : oD.getMonth() + 1);
                case '%M' :
                    return this.TZ(utc ? oD.getUTCMinutes() : oD.getMinutes());
                case '%n' :
                    return '<br />';
                case '%S' :
                    return this.TZ(utc ? oD.getUTCSeconds() : oD.getSeconds());
                case '%u' : case '%w' :
                    var d = (utc ? oD.getUTCDay() : oD.getDay());
                    if (x=='%u' && d==0) d=7;
                    return d;
                case '%U' : case '%W' : case '%V' :
                    if (x=='%U') return oD.getWeekOfYear() - 1;
                    return oD.getWeekOfYear();
                case '%y' : case '%Y' : case '%G' : case '%C' : case '%g' :
                    var y = (utc ? oD.getUTCFullYear() : oD.getFullYear()) + "";
                    if (x==='%y' || x==='%g') return y.substr(2,2);
                    if (x=='%C') return this.TZ(Math.ceil(y/100) + "");
                    return y;
                case '%Z' :
                    var s = (oD.toString()).split(':');
                    var s = (oD.toString().split(':'));
                    if (s[2]) {
                        s = s[2].split(' ');
                        s = s[1] ? s[1] : false; 
                    } else {
                        s = false;
                    }
                    return (s ? s : 'TZ:' + oD.getTimezoneOffset());
                case '%z' :
                    return oD.getTimezoneOffset();
                case '%%' :
                    return '&#37;';
                default :
                    return x;
            }
        },
        TZ: function(x) {
            return(x<0||x>9?"":"0")+x;
        },
        unTZ: function(x) {
            return parseInt(x);
        }
};
DateFormat.Extend();
