﻿/*	copyright www.laRouteDuNet.fr 2007

    gestion de dates (ajout de méthodes à l'objet Date, parser, traduction via toString(format)...)
    
    gestion de calendriers
    exemple:
    new Control.Calendar(date,span) affiche un calendrier dans le container span (ou son ID)

	ATTENTION: nécessite prototype.js
*/

if(typeof Prototype == 'undefined')
  throw("controltime.js requires prototype.js library");

if(!Control) var Control = {};

Control.TimeData= {
    language:'fr',
    dateMonths: new Array(),
    dateShortMonths: new Array(),
    dateDays: new Array(),
    dateLongFormat: new Array(),
    dateMidFormat: new Array(),
    dateShortFormat: new Array()
}

with (Control.TimeData) {
    dateMonths['en']=["January","February","March","April","May","June","July","August","September","October","November","December"];
    dateShortMonths['en']=["Jan.","Feb.","Mar.","Apr.","May","June","July","Aug.","Sep.","Oct.","Nov.","Dec."];
    dateDays['en']=['sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
    dateLongFormat['en']='dddd, dd MMMM, yyyy hh:mm:ss tt';
    dateMidFormat['en']='ddd, dd MMM, yyyy hh:mm:ss';
    dateShortFormat['en']='yyyy-MM-dd HH:mm';

    dateMonths['fr']=['Janvier','Février','Mars','Avril','Mai','juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'];
    dateShortMonths['fr']=['Jan.','Fév.','Mars','Avr.','Mai','Juin','Juil.','Août','Sep.','Oct.','Nov.','Déc.'];
    dateDays['fr']=['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'];
    dateLongFormat['fr']='dddd d MMMM yyyy HH:mm:ss';
    dateMidFormat['fr']='ddd dd MMM yyyy HH:mm:ss';
    dateShortFormat['fr']='dd-MM-yyyy HH:mm';
}

///Utility
String.prototype.padLeft=function(c,n){
    var s=this.toString();
    while(s.length < n) s = c + s;
    return s;
}

var iDate = {
    dayNames: function() {
        return Control.TimeData.dateDays[Control.TimeData.language]
    },
    monthNames: function() {
        return Control.TimeData.dateMonths[Control.TimeData.language]
    },
    monthShortNames: function() {
        return Control.TimeData.dateShortMonths[Control.TimeData.language]
    },
    lFormat: function() {
        return Control.TimeData.dateLongFormat[Control.TimeData.language]
    },
    mFormat: function() {
        return Control.TimeData.dateMidFormat[Control.TimeData.language]
    },
    sFormat: function() {
        return Control.TimeData.dateShortFormat[Control.TimeData.language]
    },
    getDayName: function() {
        return this.dayNames()[this.getDay()]
    },
    getDayShortName: function() {
        return this.getDayName().substr(0,3);
    },
    getMonthName: function() {
        return this.monthNames()[this.getMonth()]
    },
    getMonthShortName: function() {
        return this.monthShortNames()[this.getMonth()];
    },
    isLeapYear: function() {
        var y=this.getFullYear();
        return (y%4==0&&y%100!=0)||y%400==0;
    },
    isWeekEnd: function() {
        return this.getDay()==0||this.getDay()==6;
    },
    isWeekDay: function() {
        return !this.isWeekEnd();
    },
    getDaysInMonth: function() {
        return [31,(this.isLeapYear()?29:28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][this.getMonth()];
    },
    addYears: function(n) {
        this.setFullYear(this.getFullYear()+n);
        return this;
    },
    addMonths: function(n) {
        var day = this.getDate();
        this.setMonth(this.getMonth()+n);
        if(day > this.getDate())
            this.addDays(-this.getDate());
        return this;
    },
    addDays: function(n) {
        this.setDate(this.getDate()+n);
        return this;
    },
    addHours: function(n) {
        this.setHours(this.getHours()+n);
        return this;
    },
    addMinutes: function(n) {
        this.setMinutes(this.getMinutes()+n);
        return this;
    },
    addSeconds: function(n) {
        this.setSeconds(this.getSeconds()+n);
        return this;
    },
    longFormat: function() {
        return this.toString(this.lFormat());
    },
    midFormat: function() {
        return this.toString(this.mFormat());
    },
    shortFormat: function() {
        return this.toString(this.sFormat());
    }
}
Object.extend(Date.prototype,iDate)

/**
* Returns string representation of instance using the specified format string.
*
* Overrides native toString() method. Inspired from Microsoft.NET DateTime structure.
*
* @syntax dateObj.toString(formatString)
* @param formatString Format is a combination of following, e.g. "ddd MMM yy" returns "Tue Dec 02".
* hh - 12-hour clock with leading zero if single-digit.
* h - 12-hour clock without leading zero.
* HH - 24-hour clock with leading zero.
* H - 24-hour clock without leading zero.
* mm - Minutes with leading zero.
* m - Minutes without leading zero.
* ss - Seconds with leading zero.
* s - Seconds without leading zero.
* tt - AM/PM designator.
* dddd - Full name of the day of the week.
* ddd - Abbreviated name of the day of the week.
* dd - Day of month with leading zero.
* d - Day of month without leading zero.
* MMMM - Full name of month.
* MMM - Abbreviated name of month.
* MM - Month with leading zero.
* M - Month without leading zero.
* yyyy - Full 4-digit year.
* yy - 2-digit year.
* @return String
*/
Date.prototype.toString = function(s) {
    var self = this;
    return s? s.replace
    (
        /hh|h|HH|H|mm|m|ss|s|yyyy|yy|dddd|ddd|dd|d|MMMM|MMM|MM|M|tt/g,
        function(s) {
            switch(s) {
            case "hh":
                return (self.getHours()<13?self.getHours():(self.getHours()-12)).toString().padLeft('0',2);
            case "h":
                return self.getHours()<13?self.getHours():(self.getHours()-12);
            case "HH":
                return self.getHours().toString().padLeft('0',2);
            case "H":
                return self.getHours();
            case "mm":
                return self.getMinutes().toString().padLeft('0',2);
            case "m":
                return self.getMinutes();
            case "ss":
                return self.getSeconds().toString().padLeft('0',2);
            case "s":
                return self.getSeconds();
            case "yyyy":
                return self.getFullYear();
            case "yy":
                return self.getFullYear().toString().substring(2,4);
            case "dddd":
                return self.getDayName();
            case "ddd":
                return self.getDayShortName();
            case "dd":
                return self.getDate().toString().padLeft('0',2);
            case "d":
                return self.getDate().toString();
            case "MMMM":
                return self.getMonthName();
            case "MMM":
                return self.getMonthShortName();
            case "MM":
                return (self.getMonth()+1).toString().padLeft('0',2);
            case "M":
                return self.getMonth()+1;
            case "tt":
                return self.getHours()<12?'AM':'PM';
            }
        }
    )
    :this.toUTCString();
}

Control.DateParser = function(s) {
    var d=new Date(s);
    if (isNaN(d)) {
        var table=(s+' 0 0 0 0 0 0').split(/\D/)
        if (table[2].length==4) {
            var sw=table[0];
            table[0]=table[2];
            table[2]=sw;
        }
        var s1=table[0]+'/'+table[1]+"/"+table[2];
        var s2=table[3]+':'+table[4]+":"+table[5];
        d=new Date(s1+' '+s2);
    }
    return d;
}

Control.Calendar = Class.create();

Control.Calendar.prototype = {
    initialize: function(date,span) {
        this.pathImg='images/calendar/'
        this.date=date || new Date;
        this.span=$(span);
        if (!this.span) {
            this.span=document.createElement('div');
            this.span.style.border='solid 1px red';
            this.span.style.background='lightgreen';
            document.body.appendChild(this.span);
        }
        this.mode='month'
        this.draw();
    },
    draw: function() {
        switch (this.mode) {
        case 'day':
            this.drawDay();
            break;
        case 'month':
            this.drawMonth();
            break;
        case 'year':
            this.drawYear();
            break;
        }
    },
    drawDay: function() {
        var header=document.createElement('div');
        header.style.textAlign='center';
        this.span.appendChild(header);
        
        this.elmMinus=document.createElement('span');
        Element.setStyle(this.elmMinus,{float:'left'});
        this.elmMinus.innerHTML='<img src="'+this.pathImg+'previous.png" alt="" style="height:1.5em;width:auto" />';
        this.elmMinus.style.cursor='pointer';
        Event.observe(this.elmMinus,'click',this.minus.bind(this));
        header.appendChild(this.elmMinus);

        this.elmPlus=document.createElement('span');
        Element.setStyle(this.elmPlus,{float:'right'});
        this.elmPlus.innerHTML='<img src="'+this.pathImg+'next.png" alt="" style="height:1.5em;width:auto" />';
        this.elmPlus.style.cursor='pointer';
        Event.observe(this.elmPlus,'click',this.plus.bind(this));
        header.appendChild(this.elmPlus);
        
        this.elmTitle=document.createElement('span');
        this.elmTitle.innerHTML=this.date.toString('MMMM yyyy');
        this.elmTitle.style.cursor='pointer';
        Event.observe(this.elmTitle,'click',this.title.bind(this));
        header.appendChild(this.elmTitle);
        
        this.elmBody=document.createElement('div');
        this.elmBody.style.cursor='pointer';
        Event.observe(this.elmBody,'click',this.title.bind(this));
        this.elmBody.style.textAlign='center';
        this.elmBody.style.fontSize='7em';
        this.elmBody.innerHTML=this.date.toString('d')
        this.span.appendChild(this.elmBody);

        var footer=document.createElement('div');
        footer.style.position='relative';
        footer.style.textAlign='center';
        this.span.appendChild(footer);

        this.elmToday=document.createElement('span');
        this.elmToday.style.position='absolute';
        this.elmToday.style.left='0px';
        this.elmToday.innerHTML='<img src="'+this.pathImg+'today.png" alt="" style="height:1.5em;width:auto" />';
        this.elmToday.style.cursor='pointer';
        Event.observe(this.elmToday,'click',this.today.bind(this));
        footer.appendChild(this.elmToday);
        
        var day=document.createElement('span');
        day.innerHTML=this.date.toString('dddd');
        footer.appendChild(day);
    },
    drawMonth: function() {
        var header=document.createElement('div');
        header.style.textAlign='center';
        this.span.appendChild(header);
        
        this.elmMinus=document.createElement('span');
        Element.setStyle(this.elmMinus,{float:'left'});
        this.elmMinus.innerHTML='<img src="'+this.pathImg+'previous.png" alt="" style="height:1.5em;width:auto" />';
        this.elmMinus.style.cursor='pointer';
        Event.observe(this.elmMinus,'click',this.minus.bind(this));
        header.appendChild(this.elmMinus);

        this.elmPlus=document.createElement('span');
        Element.setStyle(this.elmPlus,{float:'right'});
        this.elmPlus.innerHTML='<img src="'+this.pathImg+'next.png" alt="" style="height:1.5em;width:auto" />';
        this.elmPlus.style.cursor='pointer';
        Event.observe(this.elmPlus,'click',this.plus.bind(this));
        header.appendChild(this.elmPlus);
        
        this.elmTitle=document.createElement('span');
        this.elmTitle.innerHTML=this.date.toString('MMMM yyyy');
        this.elmTitle.style.cursor='pointer';
        Event.observe(this.elmTitle,'click',this.title.bind(this));
        header.appendChild(this.elmTitle);
        
        this.elmBody=document.createElement('div');
        this.elmBody.style.textAlign='center';
        var origine=new Date(this.date);
        var origine=origine.addDays(-(origine.getDate()+1))
        while (origine.getDay()!=1)
            origine=origine.addDays(-1);
        var table=document.createElement('table')
        table.style.width='100%';
        this.elmBody.appendChild(table);
        var tbody=document.createElement('tbody')
        table.appendChild(tbody);
        var tr=document.createElement('tr')
        tbody.appendChild(tr);
        var now=(new Date()).toString('dd MM yyyy');
        var selDate=this.date.toString('dd MM yyyy');
        var dateMonth=this.date.getMonth();
        for (var x=0;x<7;x++) {
            var n=new Date(origine);
            var td=document.createElement('th');
            td.innerHTML=n.addDays(x).toString('ddd');
            tr.appendChild(td);
        }
        for (var y=0;y<6;y++) {
            var tr=document.createElement('tr');
            tbody.appendChild(tr);
            for (var x=0;x<7;x++) {
                var n=new Date(origine);
                var td=document.createElement('td');
                td.style.border='solid 1px transparent';
                td.innerHTML=n.addDays((y*7)+x).toString('d');
                if (n.getMonth()!=dateMonth)
                    td.style.color='#666';
                if (n.isWeekEnd())
                    td.style.background='lightyellow';
                var nDate=n.toString('dd MM yyyy');
                if (nDate==now)
                    td.style.borderColor='orange';
                if (nDate==selDate)
                    td.style.background='orange';
                td.id=n.toString('dd MM yyyy HH mm ss').replace(/ /g,'_');
                td.style.cursor='pointer';
                Event.observe(td,'click',this.setDate.bind(this));
                tr.appendChild(td);
            }
        }

        this.span.appendChild(this.elmBody);

        var footer=document.createElement('div');
        this.span.appendChild(footer);

        this.elmToday=document.createElement('span');
        this.elmToday.innerHTML='<img src="'+this.pathImg+'today.png" alt="" style="height:1.5em;width:auto" />';
        this.elmToday.style.cursor='pointer';
        Event.observe(this.elmToday,'click',this.today.bind(this));
        footer.appendChild(this.elmToday);
                
    },
    drawYear: function() {
        var header=document.createElement('div');
        header.style.textAlign='center';
        this.span.appendChild(header);
        
        this.elmMinus=document.createElement('span');
        Element.setStyle(this.elmMinus,{float:'left'});
        this.elmMinus.innerHTML='<img src="'+this.pathImg+'previous.png" alt="" style="height:1.5em;width:auto" />';
        this.elmMinus.style.cursor='pointer';
        Event.observe(this.elmMinus,'click',this.minus.bind(this));
        header.appendChild(this.elmMinus);

        this.elmPlus=document.createElement('span');
        Element.setStyle(this.elmPlus,{float:'right'});
        this.elmPlus.innerHTML='<img src="'+this.pathImg+'next.png" alt="" style="height:1.5em;width:auto" />';
        this.elmPlus.style.cursor='pointer';
        Event.observe(this.elmPlus,'click',this.plus.bind(this));
        header.appendChild(this.elmPlus);
        
        this.elmTitle=document.createElement('span');
        this.elmTitle.innerHTML=this.date.toString('yyyy');
        this.elmTitle.style.cursor='pointer';
        Event.observe(this.elmTitle,'click',this.title.bind(this));
        header.appendChild(this.elmTitle);
        
        this.elmBody=document.createElement('div');
        this.elmBody.style.textAlign='center';
        var table=document.createElement('table')
        table.style.width='100%';
        this.elmBody.appendChild(table);
        var tbody=document.createElement('tbody')
        table.appendChild(tbody);
        for (var y=0;y<3;y++) {
            var tr=document.createElement('tr');
            tbody.appendChild(tr);
            for (var x=0;x<4;x++) {
                var td=document.createElement('td');
                var origine=new Date(this.date);
                origine.setDate(1);
                origine.setMonth((y*4)+x);
                var daysInMonth=origine.getDaysInMonth();
                var svDate=this.date.getDate();
                if (daysInMonth>=svDate)
                    origine.setDate(svDate);
                else
                    origine.setDate(daysInMonth);
                td.innerHTML=origine.toString('MMM');
                td.id=origine.toString('dd MM yyyy HH mm ss').replace(/ /g,'_');
                td.style.cursor='pointer';
                Event.observe(td,'click',this.setMonth.bind(this));
                tr.appendChild(td);
            }
        }

        this.span.appendChild(this.elmBody);

        var footer=document.createElement('div');
        this.span.appendChild(footer);

        this.elmToday=document.createElement('span');
        this.elmToday.innerHTML='<img src="'+this.pathImg+'today.png" alt="" style="height:1.5em;width:auto" />';
        this.elmToday.style.cursor='pointer';
        Event.observe(this.elmToday,'click',this.today.bind(this));
        footer.appendChild(this.elmToday);
        
    },
    dispose: function() {
        Event.stopObserving(this.elmMinus,'click',this.minus.bind(this));
        Event.stopObserving(this.elmPlus,'click',this.plus.bind(this));
        Event.stopObserving(this.elmTitle,'click',this.title.bind(this));
        Event.stopObserving(this.elmToday,'click',this.today.bind(this));
        switch (this.mode) {
        case 'day':
            Event.stopObserving(this.elmBody,'click',this.title.bind(this));
            break;
        case 'month':
            tds=this.elmBody.getElementsByTagName('td');
            for (var x=0;x<tds.length;x++)
                Event.stopObserving(tds[x],'click',this.setDate.bind(this));
            break;
        case 'year':
            tds=this.elmBody.getElementsByTagName('td');
            for (var x=0;x<tds.length;x++)
                Event.stopObserving(tds[x],'click',this.setMonth.bind(this));
            break;
        }
        this.span.innerHTML='';
    },
    minus:   function (e){
        this.dispose();
        switch (this.mode) {
        case 'day':
            this.date=this.date.addDays(-1);
            break;
        case 'month':
            this.date=this.date.addMonths(-1);
            break;
        case 'year':
            this.date=this.date.addYears(-1);
            break;
        }
        this.draw();
    },
    plus:   function (e){
        this.dispose();
        switch (this.mode) {
        case 'day':
            this.date=this.date.addDays(1);
            break;
        case 'month':
            this.date=this.date.addMonths(1);
            break;
        case 'year':
            this.date=this.date.addYears(1);
            break;
        }
        this.draw();
    },
    today:   function (e){
        this.dispose();
        this.date=new Date();
        switch (this.mode) {
        case 'day':
            this.mode='day';
            break;
        case 'month':
            this.mode='month';
            break;
        case 'year':
            this.mode='month';
            break;
        }
        this.draw();
    },
    title:   function (e){
        this.dispose();
        switch (this.mode) {
        case 'day':
            this.mode='month';
            break;
        case 'month':
            this.mode='year';
            break;
        case 'year':
            this.mode='month';
            break;
        }
        this.draw();
    },
    setDate:    function(e) {
        this.dispose();
        var td=Event.element(e);
        this.date=Control.DateParser(td.id);
        this.mode='day';
        this.draw();
    },
    setMonth:    function(e) {
        this.dispose();
        var td=Event.element(e);
        this.date=Control.DateParser(td.id);
        this.mode='month';
        this.draw();
    }
}

