/*********************************************************************************
	Mika - javascript library for UI Components riding on prototype.js (1.6 or above)
	note: important the latest prototype.js available from http://www.prototypejs.org
	
	2007 Green Tomato Ltd. All Copyright Reserved.
	
************************************************************************************/

// defining the namespace
if (typeof mika == "undefined") {
	// define mika
	var mika = {
		version: "0.1",
		namespace: function() {
			var a=arguments, o=null, i, j, d;
			for (i=0; i<a.length; i=i+1) {
				d=a[i].split(".");
				o=mika;
		
				for (j=(d[0] == "mika") ? 1 : 0; j<d.length; j=j+1) {
					o[d[j]]=o[d[j]] || {};
					o=o[d[j]];
				}
			}
		
			return o;
		}
	};
}

// packages: mika.visual
mika.namespace('visual');
mika.namespace('util');

// visual Element - base class

mika.visual.Element = Class.create({
	instance: null,
	initialize: function(id) {
		this.id = id;
		this.instance = $(this.id);
	},
	show: function() { $(this.id).show(); },
	hide: function() { $(this.id).hide(); }
});


// textarea - represents textarea Object
mika.visual.Textarea = Class.create(mika.visual.Element, {
	adjustHeight: function(lineheight, offset) {
		if (offset === undefined) offset = 8;
		var lines = $(this.id).value.split("\n");
		var count = lines.length;
		lines.each(function(line) { count += parseInt(line.length / 70); });
		var rows = parseInt($(this.id).getHeight() / lineheight);
		if (count > rows - offset) { // too many words -> extend
			$(this.id).style.height = ($(this.id).getHeight() + offset * lineheight) + 'px';
		}
		if (count < rows - 2 * offset) {
			$(this.id).style.height = ($(this.id).getHeight() - offset * lineheight) + 'px';
		}
	}
});

// Button - represents normal button, clickable object
mika.visual.Button = Class.create(mika.visual.Element, {
	isSelected: false,
	select: function() {
		this.isSelected = true;
		$(this.id).addClassName('selected');
		if (this.onSelect) { this.onSelect(); }
	},
	deSelect: function() {
		this.isSelected = false;
		$(this.id).removeClassName('selected');
		if (this.onDeSelect) { this.onDeSelect(); }
	}	
});


// Flip - represents a flip of content
mika.visual.Flip = Class.create(mika.visual.Element, {
	isSelected: false,
	select: function() {
		this.isSelected = true;
		this.show();
		if (this.onSelect) { this.onSelect(); }
	},
	deSelect: function() {
		this.isSelected = false;
		this.hide();
		if (this.onDeSelect) { this.onDeSelect(); }
	}	
});


// Tab - represents list of buttons and flips, which establishes a tab.
// Require: Button, Flip
mika.visual.Tab = Class.create(mika.visual.Element, {
	buttons: [],
	flips: [],
	initialize: function($super, id, buttons, flips) {
		$super(id);
		this.buttons = buttons;
		this.flips = flips;
	},
	select: function(btn_id) {
		var b = this.buttons, f = this.flips;
		// do deselect first, then select
		if (this.preSelect) { this.preSelect(btn_id); }
		for (i=0; i<b.length; i++) {
			if (b[i].id != btn_id) {
				b[i].deSelect();
				if (f[i]) f[i].deSelect();
			}
		}
		for (i=0; i<b.length; i++) {
			if (b[i].id == btn_id) {
				b[i].select();
				if (f[i]) f[i].select();
				break;
			}
		}
		if (this.onSelect) { this.onSelect(btn_id); }
	},
	getSelectedFlip: function() {
		var f = this.flips;
		for (i=0;i<f.length;i++) {
			if (f[i].isSelected) return f[i];
		}
		return undefined;
	}
});

// Textbox - represents normal textbox
mika.visual.Textbox = Class.create(mika.visual.Element, {
	maxWidth: 0,
	initialize: function($super,id,maxWidth) {
		$super(id);
		this.maxWidth = maxWidth;
		this.addListener();
	},
	addListener: function() {
		Event.observe(this.id,'keypress',function() {
			this.adjustWidth(8,4);
		}.bindAsEventListener(this));
	},
	adjustWidth: function(charwidth, offset) {
		if (offset === undefined) offset = 8;
		var chars = $(this.id).value;
		var count = chars.length;
		var width = parseInt($(this.id).getWidth() / charwidth);
		if (count > width - offset) { // too many words -> extend
			var expectWidth = $(this.id).getWidth() + offset * charwidth;
			if (this.maxWidth > 0) expectWidth = (expectWidth < this.maxWidth) ? expectWidth:this.maxWidth;
			$(this.id).style.width = expectWidth + 'px';
		}
		if (count < width - 2 * offset) {
			$(this.id).style.width = ($(this.id).getWidth() - offset * charwidth) + 'px';
		}
	}	
});

// TokenizedTextBox - a text input box, which support tokenization
mika.visual.TokenizedTextBox = Class.create(mika.visual.Element, {
	maxExtendableWidth: 0,
	mode: 'standby',
	entries: {},
	initialize: function($super,id,objVarName) {
		$super(id);
		this.objVarName = objVarName;
		this.addListener();
		this.ttpInputId = this.id + '_ttb_input';
	},
	addListener: function() {
		Event.observe(this.id,'click',function(evt) {
			if (evt.target.id == this.id && this.mode == 'standby') this.newTtbBox();
		}.bindAsEventListener(this));
/*		
		Event.observe(this.id,'keypress',function(e) {
		YAHOO.log(this.id + " listener: (keypress) " + this.mode);
			if (this.mode == 'standby') {
				keynum=e.keyCode;
				YAHOO.log('keycode:' + keynum)
				if (keynum==8||keynum==46) {try{this.removeToken();}catch(exp){}};
			}
		}.bindAsEventListener(this));
*/		
	},
	newTtbBox: function() {
		this.mode = 'edit';
//		this.deSelectToken();
		var ttpInputId = this.ttpInputId;
		// dismiss any current input ttb-box
		if (document.getElementById(ttpInputId) != undefined) {
			document.getElementById(ttpInputId).parentNode.removeChild(document.getElementById(ttpInputId));
		}
		$(this.id).appendChild(new Element('input',{'id': ttpInputId,'size':'1'}));
		this.ttpInput = new mika.visual.Textbox(ttpInputId,this.maxExtendableWidth);
		$(ttpInputId).focus();
		Event.observe(ttpInputId, 'keypress', function(e) {	
			keynum = e.keyCode;
			if (keynum == 0) keynum = e.which;
			if (keynum == 13 || keynum == 44) {
				this.release();
			} else if (keynum == 8 && $(this.ttpInputId).value=='') {
				var pe = e.target.previous('a.entry',0);
				if (pe) this.selectToken(pe);
			} else if (keynum == 38 || keynum == 40 || keynum==63232 || keynum==63233) {
				this.onKeyPress(e);
			}
		}.bindAsEventListener(this));
		Event.observe(ttpInputId, 'keyup', function(e) {
			if(window.event) { keynum = e.keyCode; }
			else { keynum = e.which; }
			if (keynum == 188) { 
				this.release(); 
			} else if (!(keynum == 0 || keynum == 13 || keynum == 44 || keynum == 38 || keynum == 40 || keynum == 63232 || keynum==63233)) {
				this.onKeyPress(e);
			}
			
/*
			if (evt.which == 13 || evt.which == 44) {
				var ebox = new Element('span',{'class':'entry'});
			};

*/		}.bindAsEventListener(this));
		Event.observe(ttpInputId, 'blur', function(e) {
			this.dismiss();
		}.bindAsEventListener(this));
		
		
/*
		Event.observe(ttpInputId, 'blur', function() {
			this.mode = 'standby';
		}.bindAsEventListener(this));

*/	},
	setMaxExtendableWidth: function(w) {
		this.maxExtendableWidth = w;
	},
	dismiss: function() {
		this.mode = 'standby';
		this.reset();
		if (this.onDismiss) this.onDismiss();

	},
	release: function() {
//	YAHOO.log('release: ' + this.objVarName);
//	alert('release ' + this.objVarName);
//		var ebox = new Element('a',{'class':'entry','onClick':this.objVarName+'.selectToken(this)','onkeypress':'YAHOO.log("keyevent!!!!!!");'+this.objVarName + '.onTokenKeyPress(event,this)'});
		var ebox = new Element('a',{'href':'#','class':'entry','onClick':this.objVarName+'.selectToken(this);return false;','tabindex':'-1','onblur':this.objVarName+'.deSelectToken()','onkeypress':this.objVarName+'.onTokenKeyPress(event)'});
		var fired = this.onRelease(ebox,$(this.ttpInputId).value);
		if (fired) {
			$(this.id).appendChild(ebox);
		}
		this.newTtbBox();
	},
	reset: function() {
		$(this.ttpInputId).value = '';
		if (this.onReset) this.onReset();
	},
	removeToken: function(obj) {
		if(obj) {
			Element.extend(obj).remove();
		} else {
			$(this.id).down("a.selected",0).remove();
		}
		this.newTtbBox();
	},
	selectToken: function(obj) {
		var eobj = Element.extend(obj)
		eobj.addClassName("selected");
		eobj.focus();
//		eobj.down('input',0).focus();
//		this.dismiss();
	},
	deSelectToken: function() {
		try {
			$(this.id).down("a.selected",0).removeClassName("selected");
		} catch (e) {};
	},
	onTokenKeyPress: function(e) {
		keynum=e.keyCode;
		if (keynum==8||keynum==46||keynum==63272) {try{this.removeToken();}catch(exp){}};		
	}
	
});

//PageSlider - inherit Tab with page-sliding effect 
mika.visual.PageSlider = Class.create(mika.visual.Tab, {
	sliderCurrentPosition: 0,
	sliderCurrentSection: null,
	isSliding: false,
	toPosition: 0,
	defaultSlidingSpeed: 80,
	slidingSpeed: 80,
	slidingAcce: 10,
	slidingDiv: 'slidingDiv',
	timer: null,
	sliderButtonPrefix: 'btn_',
	sliderHiddenObjectClass: '_hobj',
	sliderHiddenScrollBarClass: '_hsb',
	enable_shadow: true,
	opened_from: null,
	width: 0,
	height: 0,
	offset_x: 0,
	offset_y: 0,
	initialize: function($super,id,buttons,flips) {
		$super(id, buttons, flips);
		this.defineAction();
	},
	defineAction: function() {
		for (i=0;i<this.flips.length;i++) {
			flips[i].select = function(i) {
				this.isSelected = true;
			}.bindAsEventListener(flips[i]);
			flips[i].deSelect = function(i) {
				this.isSelected = false;
			}.bindAsEventListener(flips[i]);
		}
/*		
		for (i=0;i<this.buttons.length;i++) {
			eval("Event.observe(this.buttons[i].id,'click',function(event) { alert('haha');this.select('"+this.buttons[i].id+"')}.bindAsEventListener(this));");
		}
*/		
	},
	select: function(btn_id) {
		var b = this.buttons, f = this.flips;
		for (i=0; i<b.length; i++) {
			if (b[i].id == btn_id) {
				b[i].select();
				if (f[i]) f[i].select();
				if (!this.isSliding) {
					var slided = this.slideTo(f[i].id);
					if (slided) {
						this.sliderCurrentSection = f[i].id;
					}
				}
			} else {
				b[i].deSelect();
				if (f[i]) f[i].deSelect();
			}
		}
		if (this.onSelect) { this.onSelect(); }
	},
	slide: function(pointXY, sliderDiv) {
		if (!this.isSliding) {
			var slided = this.slideToPoint(pointXY);
			return true;
		} else {
			return false;
		}
	},
	slideTo: function(div) {
		_this = this;
		this.toPosition = $(div).positionedOffset();
		if (this.toPosition[0] != this.sliderCurrentPosition[0]) {
			this.beforeSlide(div);
			this.isSliding = true;
			var callback = function() {_this.slideH(div);};
			this.timer = window.setInterval(callback, 15);
		} else {
			return false;
		}
		return true;
	},
	slideToPoint: function(pointXY) {
		_this = this;
		this.toPosition = pointXY;
		if (this.toPosition[0] != this.sliderCurrentPosition[0]) {
			this.isSliding = true;
			var callback = function() { _this.slidH(null); };
			this.timer = window.setInterval(callback, 15);
		} else {
			return false;
		}
		return true;
	},
	beforeSlide: function(div) {
		// set hidden objects hidden
		var hiddenObjects = $$('.' + this.sliderHiddenObjectClass, '.' + this.sliderHiddenScrollBarClass);
		if (hiddenObjects) {
			for (var i = 0; i<hiddenObjects.length; i++) {
				var anyObject = hiddenObjects[i];
				if (!anyObject.descendantOf(div)) {
					if (Element.hasClassName(anyObject,this.sliderHiddenObjectClass))
						anyObject.addClassName('hidden'); 
					if (Element.hasClassName(anyObject,this.sliderHiddenScrollBarClass)) {
						anyObject.addClassName('overflow');
					}
				}
	
			}
		}	
	},
	afterSlide: function(div) {
		// set hidden object visible
		var hiddenObjects = $$('.' + this.sliderHiddenObjectClass, '.' + this.sliderHiddenScrollBarClass);
		if (hiddenObjects) {
			for (var i = 0; i<hiddenObjects.length; i++) {
				var anyObject = hiddenObjects[i];
				if (anyObject.descendantOf(div)) {
					if (Element.hasClassName(anyObject,this.sliderHiddenObjectClass))
						anyObject.removeClassName('hidden'); 
					if (Element.hasClassName(anyObject,this.sliderHiddenScrollBarClass)) {
						anyObject.removeClassName('overflow');
					}
				}
	
			}
		}	
	},
	slideH: function(div) {
		var diff = Math.abs(this.toPosition[0] - this.sliderCurrentPosition[0]);
		if (diff > 0) {
			if (diff > this.slidingSpeed) {
				magnitude = this.slidingSpeed;
			} else {
				magnitude = diff;
			}
			if (this.sliderCurrentPosition[0] < this.toPosition[0]) 
				this.sliderCurrentPosition[0] = this.sliderCurrentPosition[0] + magnitude;
			else
				this.sliderCurrentPosition[0] = this.sliderCurrentPosition[0] - magnitude;
			this.slidingSpeed += this.slidingAcce;
			cpstr = '-' + this.sliderCurrentPosition[0] + 'px';
			Element.setStyle(this.slidingDiv, {'left': cpstr});
			if (this.sliderCurrentPosition[0] == this.toPosition[0]) {
				this.slidingSpeed = this.defaultSlidingSpeed;
				clearInterval(this.timer);
				this.isSliding = false;
				if (div) this.afterSlide(div);
			}
		}	
	}
});

// Panel - gather visual objects e.g. windows
mika.visual.Panel = Class.create(mika.visual.Element, {
	elements: [],
	addElement: function(ele) {
		this.elements[this.elements.length] = ele;
	},
	removeElement: function(ele) {
		for (i=0;i<this.elements.length; i++) {
			if (this.elements[i] == ele) {
				this.elements.splice(i,1);
				return;
			}
		}
	}
});

// Window - popup window (div)
mika.visual.Window = Class.create(mika.visual.Element, {
	enable_shadow: true,
	opened_from: null,
	width: 0,
	height: 0,
	offset_x: 0,
	offset_y: 0,
	x: 0,
	y: 0,
	initialize: function($super,id,width, height) {
		$super(id);
		this.width = width;
		this.height = height;
	},
	show: function(fromId, anchorId) {
		var xy = [];
		if (fromId) {
			this.opened_from = $(fromId);
			if (anchorId){
				var anchorXY = $(anchorId).viewportOffset(), fromXY = this.opened_from.viewportOffset();
				xy[0] = fromXY[0] - anchorXY[0];
				xy[1] = fromXY[1] - anchorXY[1];
			} else {
				xy = this.opened_from.positionedOffset();	
			}
			xy[0] += this.opened_from.getWidth() / 2;
			xy[1] += this.opened_from.getHeight() / 2;
		}
		wSize = getInnerWindowSize();
		wParent = this.instance.getOffsetParent();
		while (wParent != document.body && Element.getStyle(wParent, 'position') != 'relative') {
			wParent = wParent.getOffsetParent();

		}
		wParentXY = wParent.viewportOffset();
		wLeft = (wSize[0] - this.width) / 2 - wParentXY[0] + this.offset_x;
		wTop = (wSize[1] - this.height) / 2 - wParentXY[1] + this.offset_y;
		this.x = wLeft;
		this.y = wTop;
		// wLeft = (wSize[0] - this.width) / 2 + this.offset_x;
		// wTop = (wSize[1] - this.height) / 2  + this.offset_y;
		
		if (fromId && YAHOO.util.Anim) {
			// init default location
			this.instance.setStyle({'top': xy[1] + 'px', 'left': xy[0] + 'px'});
			animWindowZoomIn = new YAHOO.util.Anim(this.id, { 'top': { to: wTop } , 'left': { to: wLeft }, 'width': { to: this.width },'height': {to: this.height } }, 0.2, YAHOO.util.Easing.easeOut);
			animWindowZoomIn.onStart.subscribe(this.doWindowOpening,this,true);
			animWindowZoomIn.onComplete.subscribe(this.doWindowOpened,this,true);
			animWindowZoomIn.animate();
		} else {
			this.instance.setStyle({'top': wTop + 'px', 'left': wLeft + 'px', 'width': this.width + 'px', 'height': this.height + 'px'});
			this.doWindowOpening();
			this.doWindowOpened();
		}
	},

	hide: function(toId, anchorId) {
		var to, xy = [];
		if (toId) {
			to = $(toId);
		} else if (this.opened_from) {
			to = this.opened_from;
		}
		if (to) {
			if (anchorId) {
				var anchorXY = $(anchorId).viewportOffset(), toXY = to.viewportOffset();
				xy[0] = toXY[0] - anchorXY[0];
				xy[1] = toXY[1] - anchorXY[1];
			} else {
				xy = to.positionedOffset();
			}
			xy[0] += to.getWidth() / 2;
			xy[1] += to.getHeight() / 2;
 		}
		if (to && YAHOO.util.Anim) {
			animWindowZoomOut = new YAHOO.util.Anim(this.id, { 'top': { to: xy[1] } , 'left': { to: xy[0] }, 'width': { to: 1 },'height': {to: 1 } }, 0.2, YAHOO.util.Easing.easeOut);
			animWindowZoomOut.onStart.subscribe(this.doWindowClosing,this,true);
			animWindowZoomOut.onComplete.subscribe(this.doWindowClosed,this,true);
			animWindowZoomOut.animate();
		} else {
			this.doWindowClosing();
			this.doWindowClosed();		
		}
	},
	doWindowOpening: function() { if (this.onWindowOpening) this.onWindowOpening();},
	doWindowOpened: function() {
		if (this.enable_shadow) this.instance.addClassName('shadow');
		if (this.onWindowOpened) this.onWindowOpened();
	},
	doWindowClosing: function() {
		if (this.enable_shadow) this.instance.removeClassName('shadow');
		if (this.onWindowClosing) this.onWindowClosing();
	},
	doWindowClosed: function() { if (this.onWindowClosed) this.onWindowClosed(); }
});


// mika.util - Mika Utilities
// mika.util.fileUploader - incomplete
// TODO: implement the ajax file upload status
mika.util.fileUploader = Class.create({
	formArray: null,
	queue: null,
	index: 0,
	isProcessing: false,
	initialize: function(formArray,setOnChange) {
		this.formArray = formArray;
		if (setOnChange) {
			for (i=0; i< formArray.length; i++) {
				Event.observe($(formArray[i]),"change",this.addJob.bindAsEventListener($(formArray[i])));
			}
		}
		this.queue = new Array();
		setInterval(this.run.bindAsEventListener(this),1000);
	},
	addJob: function(formEle) { this.queue.push(formEle); this.queue = this.queue.uniq(); },
	getCurrentJob: function() { 
		if (this.index < this.queue.length) {
			return this.queue[this.index];
		} else {
			return false;
		}
	},
	run: function() {
		if (!this.isProcessing) {
			var job = this.getCurrentJob();
			if (job) {
				this.isProcessing = true;
				this.processJob(this.index,job);
	//			document.form[job.id].submit();
			}
		}
	},
	processJob: function(jobid,job) {
		
		// implement yourself after creating the instance
	},
	finishJob: function() {
		this.isProcessing = false;
		this.index++;
	},
	jobsDone: function() {
		return (!this.isProcessing && !this.getCurrentJob());
	}
});

