var processedFormat;
document.getElementById('format-tester').style.display='block';
updateFormat();

setInterval(updateResult,1000);

function setDefaultFormat() {
  if (document.getElementById('format-type').value == 'date') {
    document.getElementById('format').value = 'Day Month Dth, YYYY';
  } else {
    document.getElementById('format').value = 'Day, H:MM:SS A.M.';
  }
  updateFormat();
}

function updateFormat() {
  if (document.getElementById('format-type').value == 'date') {
    processedFormat = preProcessDateFormat(document.getElementById('format').value);
  } else {
    processedFormat = preProcessTimeFormat(document.getElementById('format').value);
  }
  updateResult();
}

function updateResult() {
  var result;
  if (document.getElementById('format-type').value == 'date') {
    result = formatDate(new Date(),processedFormat);
  } else {
    result = formatTime(new Date(),processedFormat);
  }
  document.getElementById('result').innerHTML = 'Result: <strong>' + result + '</strong>';
}

function stripEscapedChars(format, chars) {  var pos = 0;  while (true) {    pos = format.indexOf('\\',pos);    if (pos == -1) break;
    pos += 2;    var char = format.charAt(pos-1);    chars[chars.length] = char;    format = format.substr(0,pos-2) + '\\\\' + format.substr(pos);  }  return format;
}

function restoreEscapedChars(format, chars) {
  for (var i = 0; i < chars.length; i++) {    var char = chars[i];    if (char == '\\') char = '\\0';    format = format.replace(/\\\\/,char)  }  return format;
}

function preProcessDateFormat(format) {
  var chars = new Array();
  format = stripEscapedChars(format, chars);  format = format.replace(/month/g,"\\1");  format = format.replace(/Month/g,"\\2");  format = format.replace(/MONTH/g,"\\3");  format = format.replace(/mon/g,"\\4");  format = format.replace(/Mon/g,"\\5");  format = format.replace(/MON/g,"\\6");  format = format.replace(/weekday/g,"\\7");  format = format.replace(/Weekday/g,"\\8");  format = format.replace(/WEEKDAY/g,"\\9");  format = format.replace(/day/g,"\\A");  format = format.replace(/Day/g,"\\B");  format = format.replace(/DAY/g,"\\C");  format = format.replace(/da/g,"\\E");  format = format.replace(/Da/g,"\\F");  format = format.replace(/DA/g,"\\G");  format = format.replace(/DD/g,"\\H");  format = format.replace(/D/g,"\\I");  format = format.replace(/YYYY/g,"\\J");  format = format.replace(/YY/g,"\\K");  format = format.replace(/MM/g,"\\L");  format = format.replace(/M/g,"\\M");  format = format.replace(/th/g,"\\N");  format = format.replace(/Th/g,"\\O");  format = format.replace(/TH/g,"\\P");  format = format.replace(/WW/g,"\\Q");  format = format.replace(/W/g,"\\R");  format = format.replace(/ddd/g,"\\S");  format = format.replace(/d/g,"\\T");    return restoreEscapedChars(format,chars);
}

function preProcessTimeFormat(format) {
  var chars = new Array();
  format = stripEscapedChars(format, chars);  format = format.replace(/24/g,"\\1");  format = format.replace(/2/g,"\\2");  format = format.replace(/am/g,"\\3");  format = format.replace(/pm/g,"\\3");  format = format.replace(/AM/g,"\\4");  format = format.replace(/PM/g,"\\4");  format = format.replace(/a.m./g,"\\5");  format = format.replace(/p.m./g,"\\5");  format = format.replace(/A.M./g,"\\6");  format = format.replace(/P.M./g,"\\6");  format = format.replace(/HH/g,"\\7");  format = format.replace(/H/g,"\\8");  format = format.replace(/MM/g,"\\9");  format = format.replace(/M/g,"\\A");  format = format.replace(/SS/g,"\\B");  format = format.replace(/S/g,"\\C");  format = format.replace(/weekday/g,"\\D");  format = format.replace(/Weekday/g,"\\E");  format = format.replace(/WEEKDAY/g,"\\F");  format = format.replace(/day/g,"\\G");  format = format.replace(/Day/g,"\\H");  format = format.replace(/DAY/g,"\\I");  format = format.replace(/da/g,"\\J");  format = format.replace(/Da/g,"\\K");  format = format.replace(/DA/g,"\\L");  format = format.replace(/fuzzy/g,"\\M");  format = format.replace(/Fuzzy/g,"\\N");  format = format.replace(/FUZZY/g,"\\O");    return restoreEscapedChars(format,chars);
}

function formatDate(d, format) {
  format = format.replace(/\\1/g,getMonth(d.getMonth()).toLowerCase());  format = format.replace(/\\2/g,getMonth(d.getMonth()).toTitleCase());  format = format.replace(/\\3/g,getMonth(d.getMonth()).toUpperCase());    format = format.replace(/\\4/g,getTruncatedMonth(d.getMonth(),3).toLowerCase());  format = format.replace(/\\5/g,getTruncatedMonth(d.getMonth(),3).toTitleCase());  format = format.replace(/\\6/g,getTruncatedMonth(d.getMonth(),3).toUpperCase());    format = format.replace(/\\7/g,getWeekday(d.getDay()).toLowerCase());  format = format.replace(/\\8/g,getWeekday(d.getDay()).toTitleCase());  format = format.replace(/\\9/g,getWeekday(d.getDay()).toUpperCase());    format = format.replace(/\\A/g,getWeekday(d.getDay()).substr(0,3).toLowerCase());  format = format.replace(/\\B/g,getWeekday(d.getDay()).substr(0,3).toTitleCase());  format = format.replace(/\\C/g,getWeekday(d.getDay()).substr(0,3).toUpperCase());    format = format.replace(/\\E/g,getWeekday(d.getDay()).substr(0,2).toLowerCase());  format = format.replace(/\\F/g,getWeekday(d.getDay()).substr(0,2).toTitleCase());  format = format.replace(/\\G/g,getWeekday(d.getDay()).substr(0,2).toUpperCase());    format = format.replace(/\\H/g,formatNumber(d.getDate(),2));  format = format.replace(/\\I/g,formatNumber(d.getDate(),1));    format = format.replace(/\\J/g,formatNumber(d.getFullYear(),4));  format = format.replace(/\\K/g,formatNumber(d.getFullYear() % 100,2));
                format = format.replace(/\\L/g,formatNumber(d.getMonth(),2));  format = format.replace(/\\M/g,formatNumber(d.getMonth(),1));    format = format.replace(/\\N/g,getDayUnit(d.getDate()).toLowerCase());  format = format.replace(/\\O/g,getDayUnit(d.getDate()).toTitleCase());  format = format.replace(/\\P/g,getDayUnit(d.getDate()).toUpperCase());    format = format.replace(/\\Q/g,formatNumber(d.getCalendarWeek(),2));  format = format.replace(/\\R/g,formatNumber(d.getCalendarWeek(),1));    format = format.replace(/\\S/g,formatNumber(d.getDayOfYear(),3));  format = format.replace(/\\T/g,formatNumber(d.getDayOfYear(),1));    //must appear last  format = format.replace(/\\0/g,'\\');    return format;
}

function formatTime(d, format) {
  format = format.replace(/\\1/g,formatNumber(d.getHours,2))  format = format.replace(/\\2/g,formatNumber(d.getHours,1))    if (d.getHours() >= 12) {    format = format.replace(/\\3/g,'pm')    format = format.replace(/\\4/g,'PM')    format = format.replace(/\\5/g,'p.m.')    format = format.replace(/\\6/g,'P.M.')  } else {    format = format.replace(/\\3/g,'am')    format = format.replace(/\\4/g,'AM')    format = format.replace(/\\5/g,'a.m.')    format = format.replace(/\\6/g,'A.M.')  }    format = format.replace(/\\7/g,formatNumber(to12Hour(d.getHours()),2));  format = format.replace(/\\8/g,formatNumber(to12Hour(d.getHours()),1));    format = format.replace(/\\9/g,formatNumber(d.getMinutes(),2));  format = format.replace(/\\A/g,formatNumber(d.getMinutes(),1));    format = format.replace(/\\B/g,formatNumber(d.getSeconds(),2));  format = format.replace(/\\C/g,formatNumber(d.getSeconds(),1));    format = format.replace(/\\D/g,getWeekday(d.getDay()).toLowerCase());  format = format.replace(/\\E/g,getWeekday(d.getDay()).toTitleCase());  format = format.replace(/\\F/g,getWeekday(d.getDay()).toUpperCase());    format = format.replace(/\\G/g,getWeekday(d.getDay()).substr(0,3).toLowerCase());  format = format.replace(/\\H/g,getWeekday(d.getDay()).substr(0,3).toTitleCase());  format = format.replace(/\\I/g,getWeekday(d.getDay()).substr(0,3).toUpperCase());    format = format.replace(/\\J/g,getWeekday(d.getDay()).substr(0,2).toLowerCase());  format = format.replace(/\\K/g,getWeekday(d.getDay()).substr(0,2).toTitleCase());  format = format.replace(/\\L/g,getWeekday(d.getDay()).substr(0,2).toUpperCase());    format = format.replace(/\\M/g,getFuzzyTime(d).toLowerCase());  format = format.replace(/\\N/g,getFuzzyTime(d).toTitleCase());  format = format.replace(/\\O/g,getFuzzyTime(d).toUpperCase());    //must appear last  format = format.replace(/\\0/g,'\\');    return format;
}

function formatNumber(number, width) {
  var result = '' + number;
  while (result.length < width) {
    result = '0' + result;
  }
  return result;
}

function getDayUnit(day) {
  switch(day) {  case 1:
  case 21:
  case 31:    return 'st';  case 2:
  case 22:    return 'nd';  case 3:
  case 23:    return 'rd';  default:    return 'th';
  }
}

function getFuzzyTime(d) {
  var hours = to12Hour(d.getHours());  var hourPlusOne = to12Hour((d.getHours() + 1) % 24);  var minutes = Math.round(d.getMinutes()/5)*5;  if (minutes == 60) {    minutes = 0;    hours = hourPlusOne;    hourPlusOne = to12Hour((hours + 1) % 24);  }      switch(minutes) {  case 0:    if (hours == 12) {      if (d.getHours() > 10 && d.getHours() < 14) {        return 'twelve noon';      } else {        return 'midnight';      }    }    return getNumberText(hours) + ' o\'clock';  case 5:
  case 10:
  case 20:
  case 25:    return getNumberText(minutes) + ' past ' + getNumberText(hours);  case 15:    return 'quarter past ' + getNumberText(hours);  case 30:    return 'half past ' + getNumberText(hours);  case 35:
  case 40:
  case 50:
  case 55:    return getNumberText(60-minutes) + ' to ' + getNumberText(hourPlusOne);  case 45:    return 'quarter to ' + getNumberText(hourPlusOne);  }
}

function getTruncatedMonth(month,length) {
  return getMonth(month).substr(0,length);
}

function getNumberText(number) {
  var units = number % 10;  var tens = Math.floor(number / 10);    var result;  switch(tens) {  case 9:    result = 'ninety';
    break;  case 8:    result = 'eighty';
    break;  case 7:    result = 'seventy';
    break;  case 6:    result = 'sixty';
    break;  case 5:    result = 'fifty';
    break;  case 4:    result = 'forty';
    break;  case 3:    result = 'thirty';
    break;  case 2:    result = 'twenty';
    break;  case 1:    switch(units) {    case 9: return 'nineteen';    case 8: return 'eighteen';    case 7: return 'seventeen';    case 6: return 'sixteen';    case 5: return 'fifteen';    case 4: return 'fourteen';    case 3: return 'thirteen';    case 2: return 'twelve';    case 1: return 'eleven';    case 0: return 'ten';    }
  case 0:
    result = '';  }    if (units == 0) return result;    if (result != '') result += '-';    switch(units) {  case 9: return result + 'nine';  case 8: return result + 'eight';  case 7: return result + 'seven';  case 6: return result + 'six';  case 5: return result + 'five';  case 4: return result + 'four';  case 3: return result + 'three';  case 2: return result + 'two';  case 1: return result + 'one';  }
}

