/**
 * @constructor 	DateFormatter
 * @author			stone  [stone58@qq.com,QQ:31474361]
 * @version			1.10
 * @fileoverview	format Date object and output expected string
 * e.g.: 
 * var df = new DateFormatter('现在是:/Y年/m月/j日,/D /0h:/0i:/0s /a');
 * alert( df.format(new Date) ); // output: 现在是2009年5月19日,星期天 09:45:33 AM
 * 
 * @param{String} expect string with symbol format
 * symbols:
 * /Y			// long year 	2009
 * /y			// short year 	09
 * /0m			// fixed month		05
 * /m			// unfixed month 		5
 * /M			// month instance  		五月
 * /D			// weekday instance 	星期天
 * /d			// weekday index(0-6)   start at sunday		
 * /j			// unfixed date			19(8)
 * /0j			// fixed date			19(08)
 * /H			// unfixed 24Hr hours	9
 * /0H			// fixed 24Hr hours		09
 * /h			// unfixed 12Hr hours	9
 * /0h			// fixed 12Hr hours		09
 * /i			// unfixed minutes
 * /0i			// fixed minutes
 * /s			// unfixed seconds
 * /0s			// fixed seconds
 * /e			// unfixed milli-seconds 	65
 * /0e			// fixed milli-seconds		065
 * /a			// am/pm instance		上午
 * //			// the symbol'/'
 * 
 * more extended surport...
 * 
 * methods:
 * 	format()	// format the Date object to string with the formatter
 * 	isUTC()		// UTC getter and setter
 * 	AM()		// AM string instance getter and setter
 * 	PM()		// PM string instance getter and setter
 * 	weekdays()	// weekdays' string instance getter and setter
 *  months()	// months' string instance getter and setter
 */
function DateFormatter(expr){
	var wd 	= [ '星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六' ],
		M	= [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
		utc	= false,
		am	= 'AM',
		pm	= 'PM',
		y,m,j,d,h,i,s,e;
	/**
	 * @param{Date}
	 * @return{String} string that has been formated
	 */
	this.format = function(t){
		if(!t.getTime){ return false; }
		y 	= utc?t.getUTCFullYear():t.getFullYear();
		m	= utc?t.getUTCMonth():t.getMonth();
		j	= utc?t.getUTCDate():t.getDate();
		d	= utc?t.getUTCDay():t.getDay();
		h	= utc?t.getUTCHours():t.getHours();
		i	= utc?t.getUTCMinutes():t.getMinutes();
		s	= utc?t.getUTCSeconds():t.getSeconds();
		e	= utc?t.getUTCMilliseconds():t.getMilliseconds();
		a	= h<12?am:pm;
		return expr.replace(/\{[\w\-]+\}/g, function(){
				switch(arguments[0]){
					case '{year}':
					case '{YYYY}':      return ''+y;
					case '{s-year}':
					case '{YY}':        return (''+y).replace(/\d*(\d{2})/,'$1');
					case '{month}':
					case '{MM}':        return ''+((m<9?'0'+(m+1): (m+1)));
					case '{s-month}':
					case '{M}': 	    return ''+(m+1);
					case '{month-name}':
					case '{MN}':        return M[m];
					case '{day}':
					case '{DD}':        return ''+(j<10?'0'+j: j);
					case '{s-day}':	    
					case '{D}':         return ''+j;
					case '{weekday}':
					case '{W}': 	    return ''+d;
					case '{weekday-name}':
					case '{WN}':	    return wd[d];
					case '{hours}':     
					case '{hh}':        return ''+(h<10?'0'+h: h);
					case '{s-hours}':
					case '{h}':	        return ''+h;
					case '{12-hours}':
					case '{12hh}':      h=h>12?h-12:h; return ''+(h<10?'0'+h: h);
					case '{s-12-hours}':
					case '{12h}':	    return h>12?h-12:h;
					case '{minutes}':
					case '{mm}':        return ''+(i<10?'0'+i: i);
					case '{s-minutes}':
					case '{m}':         return ''+i;
					case '{seconds}':
					case '{ss}':        return ''+(s<10?'0'+s: s);
					case '{s-seconds}':
					case '{s}':         return ''+s;
					case '{milliseconds}':
					case '{mss}':      return '' + (e < 10 ? '00' + e : (e < 100 ? '0' + e : e));
					case '{s-milliseconds}':
					case '{ms}':    return '' + e;
					case '{noon}':	return ''+a;
					default: return arguments[0];
				}
		});
	};
	/**
	 * @type function, UTC getter & setter
	 * @param {Boolean | null} set or get
	 * @return {Boolean}
	 */
	this.isUTC	= function(u){ return typeof(u)=='boolean'? (utc=u): utc; }
	/**
	 * @type function, am,pm geeter & setter
	 * @param {String | null} set or get
	 * @return {String} am/pm string instance
	 */
	this.AM = function(a){ a = ''+a; am = a?a:am; return am;};
	this.PM = function(p){ p = ''+p; pm = p?p:pm; return pm;};
	/**
	 * @type function, weekday/month string instance getter & setter
	 * @param {Mixed} (index)|(String)|(Array)|(String,index)
	 * @return {String | Boolean} string for getter, boolean for setter
	 */
	this.weekdays = function(){ return _confg(arguments, 'wd', 7); };
	this.months	= function(){ return _confg(arguments, 'M', 12); }
	function _confg(args, vrb, s){
		var a1 = args[0], a2 = args[1];
		if(args.length>2){ return false; }
		switch( typeof(a1) ){
			case 'undefined': return eval(vrb);
			case 'object':
				if( a1.length!=s || typeof(a1[0])=='undefined' ){ return false;}
				for(var i=0,l=a1.length; i<l; i++){
					eval(vrb+'[i] = a1[i];');
				}
				break;
			case 'number': return ( typeof(a2)!='undefined'? false:eval(vrb+'[a1]') );
			case 'string':
				if( typeof(a2)!='number' || typeof(eval(vrb+'[a2]'))=='undefined' ) { return false; }
				eval(vrb+'[a2] = a1;');
		}
		return  true;
	}
}
