//============================================================================
// cbDate.js
//============================================================================
//      Date prototype extensions and DateMgr Object
// ---------------------------------------------------------------------------
//      rg 2010-05-20
// ---------------------------------------------------------------------------

if ( typeof Function.prototype.method !== 'function' ) {
    Function.prototype.method = function( name, func ) {
        if ( ! this.prototype[ name ] ) {
            this.prototype[ name ] = func;
        }
    };
}

Date.prototype.monthNames = [
    "Januar", "Februar", "Maerz", "April", "Mai", "Juni",
    "Juli", "August", "September", "Oktober", "November", "Dezember" ];

Date.prototype.monthNames3 = [
    'Jan', 'Feb', 'Mae', 'Apr', 'Mai', 'Jun',
    'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ];


// Returns the name of the date's month.
Date.method( "getMonthName", function () {
        return this.monthNames[ this.getMonth( ) ];
    } );

// Returns the short form of the date's month.
Date.method( "getMonthName3", function () {
        return this.monthNames3[ this.getMonth( ) ];
    } );

// Returns the name of the date's month.
Date.method( "is_earlier_than", function ( d ) {
        return Number( this ) < Number( d );
    } );


// Returns the number of days in the date's month.
Date.method( "getDays", function () {
        var tDate = new Date( this );
        var m     = tDate.getMonth( );
        var last  = 28;
    
        do {
            tDate.setDate(++last);
        } while( tDate.getMonth() === m );
    
        return last - 1;
    } );

// returns Year of Century --- YY
Date.method( "getYY", function ( ) {
        var YY = String( this.getFullYear( ) % 100 );
        while ( YY.length < 2 ) { YY = "0" + YY; }
        return YY;
    } );

// returns Year of Century --- YY
Date.method( "getYYYYMM", function ( ) {
        var YYYY = String( this.getFullYear() );
        while ( YYYY.length < 4 ) { YYYY = "0" + YYYY; }
        var MM = String( this.getMonth() );
        while ( MM.length < 2 ) { MM = "0" + MM; }
        return YYYY + MM;
    } );

// get Year of Century --- CC
Date.method( "getCentury", function ( ) {
        return String( this.getFullYear( ) ).substr( 0, 2 );
    } );

// normalizes Dates to 12:00:00:000 for numerical compares of Dates
Date.method( "normalize", function () {
        this.setHours( 12 );
        this.setMinutes( 0 );
        this.setSeconds( 0 );
        this.setMilliseconds( 0 );
        return this;
    } );

// Adds the specified number of days to the date.
Date.method( "addDays", function (n) {
        this.setDate( this.getDate() + n );
        // this.savedDate = this.getDate();
    } );

// Adds the specified number of months to the date, adjusting
// the day of the month if necessary.
Date.method( "addMonths", function (n) {
        var sd = this.getDate( );
        this.setDate(1);
        var newm = this.getMonth() + n;
        while ( newm < 0 ) {
            newm += 12;
            this.setFullYear( this.getFullYear() - 1 );
        }
        this.setMonth( newm );
        this.setDate( Math.min( sd, this.getDays() ) );
    } );

// Adds the specified number of years to the date, adjusting the
// day of the month for leap years.
Date.method( "addYears", function (n) {
        var sd = this.getDate( );
        this.setDate( 1 );
        this.setFullYear( this.getFullYear( ) + n );
        this.setDate( Math.min( sd, this.getDays( ) ) );
    } );

// string representation of date: DD. mmm YYYY
Date.method( "toIBEString", function( ) {
        var dd = String(this.getDate());
        while (dd.length < 2) { dd = "0" + dd; }
        return dd + '. ' + this.getMonthName3( ) + ' ' + this.getFullYear( );
    } );

// string representation of Date: 'DD.MM.YY'
Date.method( "toDottedDDMMYY", function (  ) {
        var mm = String( this.getMonth() + 1 );
        while (mm.length < 2) { mm = "0" + mm; }
        var dd = String( this.getDate() );
        while (dd.length < 2) { dd = "0" + dd; }
        return dd + '.' + mm + '.' + this.getYY( );
    } );

// returns object with properties ibe monthyear and day
Date.method( "toIDate", function (  ) {
        return {
            my: 12 * (this.getFullYear() - 1900) + this.getMonth(),
            d: this.getDate()
        };
    } );

// return ymd object
Date.method( "toYMD", function() {
        return {
            y: this.getFullYear(),
            m: this.getMonth() + 1,
            d: this.getDate()
        };
    } );

// set Date object to properties of a ymd object
Date.method( "fromYMD", function( ymd ) {
        this.normalize();
        this.setDate( 1 );
        this.setFullYear( ymd.y );
        this.setMonth( ymd.m - 1 );
        this.setDate( ymd.d );
        return this;
    } );

// return ymd object with string members y: YYYY, m, MM, d: DD

Date.method( "toYMD_s422", function() {
        var p,
            ymd = this.toYMD();
            
        for ( p in ymd ) { ymd[ p ] = "" + ymd[ p ]; }
               
        while ( ymd.y.length < 4 ) { ymd.y = "0" + ymd.y; }
        while ( ymd.m.length < 2 ) { ymd.m = "0" + ymd.m; }
        while ( ymd.d.length < 2 ) { ymd.d = "0" + ymd.d; }
        return ymd;
    } );

// return number of spanned months
Date.method( "getSpannedMonths", function ( d ) {
        if ( !d || !d.is_earlier_than ) { return 1; }
        var months  = 0,
            earlier = this.is_earlier_than( d ),
            first   = earlier ? new Date( this ) : new Date( d ),
            last    = earlier ? d : this,
            first_m = first.getYYYYMM( ),
            last_m  = last.getYYYYMM( );
    
        while( first_m <= last_m ) {
            months += 1;
            first.addMonths( 1 );
            first_m = first.getYYYYMM( );
        }
    
        return months;
    } );


// ----------------------------------------------------------------------------
//  cbDateMgr
// ----------------------------------------------------------------------------
//
//  synopsis:
//    
//    var dater = cbDateMgr( {
//        field_ym_id:  "id_of_field_to_write_or_read YearMonth",
//        field_d_id:   "id_of_field_to_write_or_read Day",
//        form_id:      "id_of_form_to_read_into",
//        read_fn:      read_fn, 
//        write_fn:     write_fn 
//    } );
//
//    field_ids:    mandatory
//                  field to read and write the datestring from
//                  If it exists, it is used, if not, it will be created.
//    form_id:      optional
//                  form to containing the field with field_id
//                  If it is defined and exists, the field will
//                  be searched/created inside of the form.
//    read_fn:      optional
//                  function to read the datestring and convert it into
//                  a Javascript date
//    write_fn:     optional
//                  Function to convert the Javascript Date into a 
//                  date string and write it into the field
//
// ----------------------------------------------------------------------------

function getDateMgr( cfg ) {
        
    // --------------------------------------------------------------------------
    // ... create hidden fields, if necessary
    // --------------------------------------------------------------------------
    
    var create_hidden_input = function create_hidden_input( id ) {
        var el = window.document.createElement( "INPUT" );
        el.setAttribute( "type", "HIDDEN" );
        el.setAttribute( "id", id );
        return el;
    };

    var provideElem = function provideElem( container, id ) {
        var el = xGetElementById( id );
        if ( !el ) {
            el = create_hidden_input( id );
            container.appendChild( el );
        }
        return el;
    };


    // ------------------------------------------------------------------------
    // ... read form content into Date object and write Date into form
    // ------------------------------------------------------------------------
    
    var default_read = function ( ) {
        var y, m, d, a, ym, ymd;

        if (el_ymd) {
            ymd = el_ymd.value;
            a  = ymd.split( '-' );
            if ( a.length !== 3 ) { return undefined; }
            y = a[0];
            m = a[1];
            d  = a[2];
        } else {
            ym = el_ym.value;
            a  = ym.split( '-' );
            if ( a.length !== 2 ) { return undefined; }
            y = a[0];
            m = a[1];
            d  = el_d.value;
        }
        var dt =  new Date();
        return dt.fromYMD( { y: y, m: m, d: d } );
    };

    var default_write = function ( d ) {
        var ymd = d.toYMD(),
            p;
        for ( var p in ymd ) {
            ymd[ p ] = "" + ymd[ p ];
        }
        
        while ( ymd.y.length < 4 ) { ymd.y = "0" + ymd.y; }
        while ( ymd.m.length < 2 ) { ymd.m = "0" + ymd.m; }
        while ( ymd.d.length < 2 ) { ymd.d = "0" + ymd.d; }

        if (el_ymd) {
            el_ymd.value = "" + ymd.y + "-" + ymd.m + "-" + ymd.d;
        } else {
            el_ym.value = "" + ymd.y + "-" + ymd.m;
            el_d.value  = "" + ymd.d;
        }
    };

    
    // ------------------------------------------------------------------------
    // ... start of construction
    // ------------------------------------------------------------------------

    if ( !(cfg.field_ymd_id || ( cfg.field_ym_id && cfg.field_d_id ) ) ) {
        alert( "Please provide ymd or ym and d fields for date communication!");
        return undefined;
    }

    // set container element to the form passed or document.body
    var container = cfg.form_id ?
        ( xGetElementById( cfg.form_id ) || document.body ) : document.body;

    if (cfg.field_ymd_id) {
        var el_ymd = provideElem( container, cfg.field_ymd_id );
    } else {
        var el_ym = provideElem( container, cfg.field_ym_id );
        var el_d  = provideElem( container, cfg.field_d_id  );
    }
   
    
    // --------------------------------------------------------------------------
    // ... the returned objjects only needs to be able to read and write
    // --------------------------------------------------------------------------

    return {
        read:   cfg.read_fn  || default_read,
        write:  cfg.write_fn || default_write
    };

}

