/*
 * Copyright 2005 Open Source Applications Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview JavaScript implementation of strftime function
 * @author Matthew Eernisse mailto:mde@osafoundation.org
 * @license Apache License 2.0
 * @version 0.1
 */

Date.formats = [];
Date.formats['a'] = 'Date.abbrWeekday[dt.getDay()]';
Date.formats['A'] = 'Date.fullWeekday[dt.getDay()]';
Date.formats['b'] = 'Date.abbrMonth[dt.getMonth()]';
Date.formats['B'] = 'Date.fullMonth[dt.getMonth()]';
Date.formats['c'] = 'Date.abbrWeekday[dt.getDay()] + \' \' + Date.abbrMonth[dt.getMonth()] + \' \' + leftPadString(dt.getDate(), 2) + \' \' + ' +
    'leftPadString(dt.getHours(), 2) + \':\' + leftPadString(dt.getMinutes(), 2) + \':\' + leftPadString(dt.getSeconds(), 2) + \' \' + ' +
    'dt.getFullYear()';
Date.formats['C'] = 'calcCentury(dt.getFullYear());';
Date.formats['d'] = 'leftPadString(dt.getDate(), 2)'
Date.formats['D'] = 'leftPadString((dt.getMonth()+1), 2) + \'/\' + leftPadString(dt.getDate(), 2) + \'/\' + yearTwoDigits(dt.getFullYear())';
Date.formats['e'] = 'leftPadString(dt.getDate(), 2, \' \')';
Date.formats['h'] = 'Date.abbrMonth[dt.getMonth()]';
Date.formats['H'] = 'leftPadString(dt.getHours(), 2)';
Date.formats['I'] = 'leftPadString(hourMilitary2Standard(dt.getHours()), 2)';
Date.formats['j'] = 'leftPadString(calcDays(dt), 3)';
Date.formats['k'] = 'leftPadString(dt.getHours(), 2, \' \')';
Date.formats['l'] = 'leftPadString(hourMilitary2Standard(dt.getHours()), 2, \' \')';
Date.formats['m'] = 'leftPadString((dt.getMonth()+1), 2)';
Date.formats['M'] = 'leftPadString(dt.getMinutes(), 2)';
Date.formats['p'] = 'meridian(dt.getHours())';
Date.formats['r'] = 'leftPadString(hourMilitary2Standard(dt.getHours()), 2) + \':\' + leftPadString(dt.getMinutes(), 2)  + \':\'' +
    ' + leftPadString(dt.getSeconds(), 2) + \' \' + meridian(dt.getHours())';
Date.formats['R'] = 'leftPadString(dt.getHours(), 2) + \':\' + leftPadString(dt.getMinutes(), 2)';
Date.formats['S'] = 'leftPadString(dt.getSeconds(), 2)';
Date.formats['T'] = 'leftPadString(dt.getHours(), 2) + \':\' + leftPadString(dt.getMinutes(), 2)  + \':\' + leftPadString(dt.getSeconds(), 2)';
Date.formats['u'] = 'adjustSun(dt.getDay())';
Date.formats['w'] = 'dt.getDay()';
Date.formats['x'] = 'leftPadString((dt.getMonth()+1), 2) + \'/\' + leftPadString(dt.getDate(), 2) + \'/\' + yearTwoDigits(dt.getFullYear())';
Date.formats['X'] = 'leftPadString(hourMilitary2Standard(dt.getHours()), 2) + \':\' + leftPadString(dt.getMinutes(), 2)  + \':\' + leftPadString(dt.getSeconds(), 2)';
Date.formats['y'] = 'yearTwoDigits(dt.getFullYear())';
Date.formats['Y'] = 'leftPadString(dt.getFullYear(), 4)';
Date.formats['%'] = '\'%\'';

Date.fullWeekday = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
Date.abbrWeekday = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
Date.fullMonth = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
Date.abbrMonth = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
Date.meridian = [];
Date.meridian['AM'] = 'AM';
Date.meridian['PM'] = 'PM';

/**
 * Format a JavaScript Unix timestamp as a string 
 * @param format Indicates format or formats to return
 * @param dtparam Unix timestamp to format (optional) -- also accepts JS Date obj. 
 * If param is not passed, the current datetime is used.
 * @return A string formatted according to the givent format, using the given
 * timestamp, or the current datetime if no timestamp is given. 
 * This naive implementation uses only English/US-formats for the locale.
 */
Date.strftime = function(format, dtparam) {
    var dt = null;
    var pat = /%[aAbBcCdDegGhHIjklmMnprRStTuUVwWxXyYzZ%]{1}/g;
    var patarr = [];
    var dtarr = [];
    var key = '';
    var repl = null;
    var sub = '';
    var str = format;
    
    // Optional date param passed
    if (dtparam) {
        // If the param is not a num, someone might be passing a JS date object
        dt = typeof dtparam == 'number' ? new Date(dtparam) : dtparam;
    }
    // No date passed -- use current datetime
    else {
        dt = new Date();
    }
    
    while (patarr = pat.exec(format)) {
        dtarr.push(patarr[0]);
    }
    
    if (dtarr.length) {
        for (var i = 0; i < dtarr.length; i++) {
            key = dtarr[i].replace(/%/, '');
            repl = Date.formats[key];
            if (repl) {
                sub = eval(repl);
                str = str.replace('%'+key, sub);
            }
            else {
                alert('Format not supported');
                return '';
            }
        }
        return str;
    }
    else {
        return str;
    }
}

/**
 * Avoid the JavaScript 'Year 1000' annoyance by simply truncating getFullYear
 * to get the shortened year number.
 * @param yr Integer year number
 * @return String for last two digits of year (e.g., '07', '02')
 */
function yearTwoDigits(yr) {
    // Add a millenium to take care of years before the year 1000, 
    // since we're only taking the last two digits
    var millenYear = yr + 1000;
    var str = millenYear.toString();
    str = str.substr(2); // Get the last two digits
    return str
}

/**
 * Convert a 24-hour formatted hour to 12-hour format
 * @param hour Integer hour number
 * @return String for hour in 12-hour format -- may be string length of one
 */
function hourMilitary2Standard(hour) {
    var h = typeof hour == 'number' ? hour : parseInt(hour);
    var str = h > 12 ? h - 12 : h;
    str = str == 0 ? 12 : str;
    return str;
}

/**
 * Convert a 12-hour formatted hour with meridian flag to 24-hour format
 * @param hour Integer hour number
 * @param pm Boolean flag, if PM hour then set to true
 * @return String for hour in 24-hour format
 */
function hourStandard2Military(hour, pm) {
    var h = typeof hour == 'number' ? hour : parseInt(hour);
    var str = '';
    // PM
    if (pm) {
        str = h < 12 ? (h+12) : h;
    }
    // AM
    else {
        str = h == 12 ? 0 : h;
    }
    return str;
}

/**
 * Make sure a string is two characters long, appends '0' if not
 * @param instr String, in this case month/day/hour/second
 * @return Two-character-long string with zero appended if original has length
 * of less than two.
 */
function leftPadString(instr, len, spacer) {
    var str = instr.toString();
    var sp = spacer ? spacer : '0'; // Default to padding with zero if nothing passed in
    while (str.length < len) {
        str = sp+str;
    }
    return str;
}

/**
 * Return 'AM' or 'PM' based on hour in 24-hour format
 * @param h Integer for hour in 24-hour format
 * @return String of either 'AM' or 'PM' based on hour number
 */
function meridian(h) {
    return h > 11 ? Date.meridian['PM'] : Date.meridian['AM'];
}

/**
 * Calculate the century to which a particular year belongs
 * @param y Integer year number
 * @return Integer century number
 */
function calcCentury(y) {
    var ret = parseInt(y/100);
    ret = ret.toString();
    return leftPadString(ret);
}

/**
 * Calculate the day number in the year a particular date is on
 * @param dt JavaScript date object
 * @return Integer day number in the year for the given date
 */
function calcDays(dt) {
    var first = new Date(dt.getFullYear(), 0, 1);
    var diff = 0;
    var ret = 0;
    first = first.valueOf();
    diff = (dt.valueOf() - first);
    ret = parseInt(((((diff/1000)/60)/60)/24))+1;
    return ret;
}

function adjustSun(d) {
    return d == 0 ? 7 : d;
}

