Array.prototype.indexOf = function(item) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == item) {
            return i;
        }
    }
    return -1;
};
/* Returns an array of items judged 'true' by the passed in test function */
Array.prototype.filter = function(test) {
    var matches = [];
    for (var i = 0; i < this.length; i++) {
        if (test(this[i])) {
            matches[matches.length] = this[i];
        }
    }
    return matches;
};

var monthNames = new Array();
var weekdayNames = new Array();

monthNames['ENG'] = "January February March April May June July August September October November December".split(" ");
weekdayNames['ENG'] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ");
monthNames['DEU'] = "Januar Februar Marz April Mai Juni Juli August September Oktober November Dezember".split(" ");
weekdayNames['DEU'] = "Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag".split(" ");
monthNames['SU2'] = "Januar Februar März April Mai Juni Juli August September Oktober November Dezember".split(" ");
weekdayNames['SU2'] = "Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag".split(" ");
monthNames['ITA'] = "Gennaio febbraio Marzo Aprile Maggio Giugno Luglio Agosto Settembre Ottobre Novembre Dicembre".split(" ");
weekdayNames['ITA'] = "Domenica Lunedì Martedì Mercoledì Giovedì Venerdì Sabato ".split(" ");
monthNames['SU1'] = "Gennaio febbraio Marzo Aprile Maggio Giugno Luglio Agosto Settembre Ottobre Novembre Dicembre".split(" ");
weekdayNames['SU1'] = "Domenica Lunedì Martedì Mercoledì Giovedì Venerdì Sabato ".split(" ");
monthNames['FRA'] = "Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre".split(" ");
weekdayNames['FRA'] = "Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi".split(" ");
monthNames['SU3'] = "Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre".split(" ");
weekdayNames['SU3'] = "Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi".split(" ");

/* Takes a string, returns the index of the month matching that string, throws
   an error if 0 or more than 1 matches
*/
function datetime_parseMonth(month, lang) {
    var matches = monthNames[lang].filter(function(item) { 
        return new RegExp("^" + month, "i").test(item);
    });
    if (matches.length == 0) {
        throw new Error("Invalid month string");
    }
    if (matches.length > 1) {
        throw new Error("Ambiguous month");
    }
    return monthNames[lang].indexOf(matches[0]);
}
/* Same as parseMonth but for days of the week */
function datetime_parseWeekday(weekday, lang) {
    var matches = weekdayNames[lang].filter(function(item) {
        return new RegExp("^" + weekday, "i").test(item);
    });
    if (matches.length == 0) {
        throw new Error("Invalid day string");
    }
    if (matches.length > 1) {
        throw new Error("Ambiguous weekday");
    }
    return weekdayNames[lang].indexOf(matches[0]);
}

/* Array of objects, each has 're', a regular expression and 'handler', a 
   function for creating a date from something that matches the regular 
   expression. Handlers may throw errors if string is unparseable. 
*/
var datetime_patterns = [
    // Today
    {   re: /^(tod|ogg|auj|heu)/i,
        handler: function(bits, lang) { 
            return new Date();
        } 
    },
    // Tomorrow
    {   re: /^(tom|doma|dema|morg)/i,
        handler: function(bits, lang) {
            var d = new Date(); 
            d.setDate(d.getDate() + 1); 
            return d;
        }
    },
    // Yesterday
    {   re: /^(yes|ieri|hier|ges)/i,
        handler: function(bits, lang) {
            var d = new Date();
            d.setDate(d.getDate() - 1);
            return d;
        }
    },
    // 4th
    {   re: /^(\d{1,2})(st|nd|rd|th)?$/i, 
        handler: function(bits, lang) {
            var d = new Date();
            d.setDate(parseInt(bits[1], 10));
            return d;
        }
    },
    // 4th Jan
    {   re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+)$/i, 
        handler: function(bits, lang) {
            var d = new Date();
            d.setDate(parseInt(bits[1], 10));
            d.setMonth(datetime_parseMonth(bits[2], lang));
            return d;
        }
    },
    // 4th Jan 2003
    {   re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+),? (\d{4})$/i,
        handler: function(bits, lang) {
            var d = new Date();
            d.setDate(parseInt(bits[1], 10));
            d.setMonth(datetime_parseMonth(bits[2], lang));
            d.setYear(bits[3]);
            return d;
        }
    },
    // Jan 4th
    {   re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i, 
        handler: function(bits, lang) {
            var d = new Date();
            d.setDate(parseInt(bits[2], 10));
            d.setMonth(datetime_parseMonth(bits[1], lang));
            return d;
        }
    },
    // Jan 4th 2003
    {   re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i,
        handler: function(bits, lang) {
            var d = new Date();
            d.setDate(parseInt(bits[2], 10));
            d.setMonth(datetime_parseMonth(bits[1], lang));
            d.setYear(bits[3]);
            return d;
        }
    },
    // next Tuesday - this is suspect due to weird meaning of "next"
    {   re: /^next (\w+)$/i,
        handler: function(bits, lang) {
            var d = new Date();
            var day = d.getDay();
            var newDay = datetime_parseWeekday(bits[1], lang);
            var addDays = newDay - day;
            if (newDay <= day) {
                addDays += 7;
            }
            d.setDate(d.getDate() + addDays);
            return d;
        }
    },
    // dd/mm/yyyy
    {   re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/,
        handler: function(bits, lang) {
            var d = new Date();
            d.setYear(bits[3]);
            d.setMonth(parseInt(bits[2], 10) - 1); // Because months indexed from 0
            d.setDate(parseInt(bits[1], 10));
            return d;
        }
    },
    // yyyy-mm-dd (ISO style)
    {   re: /(\d{4})-(\d{1,2})-(\d{1,2})/,
        handler: function(bits, lang) {
            var d = new Date();
            d.setYear(parseInt(bits[1]));
            d.setDate(parseInt(bits[3], 10));
            d.setMonth(parseInt(bits[2], 10) - 1);
            return d;
        }
    },
];

function datetime_parse(s, lang) {
    for (var i = 0; i < datetime_patterns.length; i++) 
	{
        var re = datetime_patterns[i].re;
        var handler = datetime_patterns[i].handler;
        var bits = re.exec(s);

        if (bits)
            return handler(bits, lang);
    }
    throw new Error("Invalid date string");
}

function datetime_format(input, lang) 
{
    var erroricon = document.getElementById('IMG' + input.id);
	
    try
	{
        if(input.value!='')
        {
			var d = datetime_parse(input.value, lang);
			var day = ('0' + d.getDate());
			day = day.substr(day.length-2, 2);
			var month = ('0' + (d.getMonth() + 1));
			month = month.substr(month.length-2, 2);
			input.value = day + '/' + month + '/' + d.getFullYear();
			erroricon.style.display = 'none';
			erroricon.title = '';
		}
    }
    catch (e) 
	{
    	var message = e.message;
        // Fix for IE6 bug
        if (message.indexOf('is null or not an object') > -1)
            message = 'Invalid date string';

		erroricon.title = '';
		erroricon.style.display = '';
    }
}

function datetime_clearerror(input)
{
	var erroricon = document.getElementById('IMG' + input.id);
	
	erroricon.style.display = 'none';
	erroricon.title = '';
}
