/*
# DHTML Spinbox Control version 1.0
# Copyright (C) Tomas Larsson 2006
# All Rights Reserved
# http://tomas.epineer.se/

# Licence:
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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.mozilla.org/MPL/
# 
# Software distributed under this License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
*/
var sb_imgpath = "javimages";

var img1 = new Image(11,11);
img1.src = sb_imgpath + '/a_d_p.gif';
var img2 = new Image(11,11);
img2.src = sb_imgpath + '/a_d_r.gif';
var img3 = new Image(11,11);
img3.src = sb_imgpath + '/a_d_r_l.gif';
var img4 = new Image(11,11);
img4.src = sb_imgpath + '/a_u_p.gif';
var img5 = new Image(11,11);
img5.src = sb_imgpath + '/a_u_r.gif';
var img6 = new Image(11,11);
img6.src = sb_imgpath + '/a_u_r_l.gif';

PeriodicalExecuter.prototype.registerCallback = function() {
	this.intervalID = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
}

PeriodicalExecuter.prototype.stop = function() {
	clearInterval(this.intervalID);
}

var SpinBox = Class.create();
SpinBox.prototype = {
	//Constructor: turn textbox into spinbox
	initialize: function(id,min,max,paddedlen) {
		this.id = id;
		this.min = min;
		this.max = max;
		this.paddedlen = paddedlen?paddedlen:0;
		var txtbox = $(id);
		
		var dim = Element.getDimensions(txtbox);
		if(!dim.height) {
			// If height is zero (or null) it's probably because the element isn't
			// on screen
			var cp = txtbox.cloneNode(true);
			cp.style.visibility = 'hidden';
			document.body.appendChild(cp);
			dim = Element.getDimensions(cp);
			document.body.removeChild(cp);
		}
		if(txtbox.value.length>0) {
				//Remove characters that aren't digits
				txtbox.value = this.pad(txtbox.value.replace(/[^\d]+/g, '')); 
		}
		//Validate keypresses
		var spin = this;
		Event.observe(txtbox,'keypress', function(evt){spin.changeTextBox(evt,min,max);});
		var up = this.createArrowPic('a_u',txtbox,dim.height/2);
		var down = this.createArrowPic('a_d',txtbox,dim.height/2);
		var sib = txtbox.nextSibling;
		var parent = txtbox.parentNode;
		Element.remove(txtbox);
		txtbox.style.padding = '0';
		txtbox.style.margin = '0';
		var table = this.createUnformattedElement('table');
		table.cellPadding = 0;
		table.cellSpacing = 0;
		tbody = this.createUnformattedElement('tbody');
		var tr = this.createUnformattedElement('tr');
		var td = this.createUnformattedElement('td');
		td.rowSpan = '2';
		td.appendChild(txtbox);
		tr.appendChild(td);
		td = this.createUnformattedElement('td');
		td.style.verticalAlign = 'bottom';
		td.appendChild(up);
		tr.appendChild(td);
		tbody.appendChild(tr);
		tr = this.createUnformattedElement('tr');
		td = this.createUnformattedElement('td');
		td.appendChild(down);
		tr.appendChild(td);
		tbody.appendChild(tr);
		table.appendChild(tbody);
		// Safari & Opera needs inline-table which IE & FF don't understand
		table.style.display='inline';
		try {
			table.style.display = 'inline-table';
		} catch(e) {}
		if(sib) {
			sib.parentNode.insertBefore(table,sib);
		} else {
			parent.appendChild(table);
		}
	},
	//Create an element with no formatting
	createUnformattedElement: function(type) {
		el = document.createElement(type);
		el.style.margin = '0';
		el.style.padding = '0';
		el.style.border = '0';
		return el;
	},
	//Return one of the img elements (up or down arrow)
	createArrowPic: function(name,box,size) {
		var img = this.createUnformattedElement("img");
		//Mouse events
		var spin = this;
		Event.observe(img,'mouseover',function(evt){spin.setArrowImg(img,'r_l');});
		Event.observe(img,'mouseout',function(evt){spin.setArrowImg(img,'r');});
		Event.observe(img,'mousedown',function(evt){spin.mouseDownArrow(img,box);});
		Event.observe(img,'mouseup',function(evt){spin.mouseUpArrow(img,box);});
		//Disable contextmenu from popping up when holding down mouse in Mac version of FF
		Event.observe(img,'contextmenu',function(evt){Event.stop(evt);});
		img.style.width = size + "px";
		img.style.height = size + "px";
		img.id = name;
		this.setArrowImg(img,'r');
		return img;
	},
	//Set the src of one of the arrow imgs
	setArrowImg: function(img,type) {
		img.src = sb_imgpath + '/' + img.id + '_' + type + '.gif'; 
	},
	//zero-pad a number to a certain length
	pad: function(num) {
		if(this.paddedlen < 2) return num;
		for(var i=0;i<this.paddedlen-String(num).length;i++) {
			num = '0' + num;
		}
		return num;
	},
	//Called when the user tries to change the text in the spinbox
	changeTextBox: function(evt) {
		var val = parseInt(Event.element(evt).value,10);
		var charCode = (evt.which) ? evt.which : evt.keyCode;
		//Stop letter from being entered if it's not a digit
		if (charCode > 31 && (charCode < 48 || charCode > 57)) {
			//If it's up or down arrow, increase or decreause value in textbox
			if(charCode == Event.KEY_UP || charCode == Event.KEY_DOWN) {
				var diff = (charCode==Event.KEY_UP)?1:-1;
				this.updateVal(Event.element(evt),diff);
			}
			Event.stop(evt);
		} else if (charCode > 47 && charCode < 58) {
			var newVal = parseInt('' + val + String.fromCharCode(charCode),10);
			if(newVal < this.min || newVal > this.max) {
				//Also stop if we're going over the max value or below min value
				Event.stop(evt);
			}
		}
		return true;
	},
	//Called when the mouse button is pressed
	mouseDownArrow: function(img,box) {
		this.setArrowImg(img,'p');
		var diff;
		diff = (img.id=="a_d")?-1:1;
		this.updateVal(box,diff);
		//Value should increase while holding down mousebutton
		var spin = this;
		this.pe = new PeriodicalExecuter(function(){spin.executeUpdateVal(box,diff)}, 0.5);
	},
	//Called when the mouse button is released
	mouseUpArrow: function(img,box) {
		this.setArrowImg(img,'r');
		//Stop increasing value
		if(this.pe) {
			this.pe.stop();
		}
	},
	//Called periodically until the mouse button is released
	executeUpdateVal: function(box,diff) {
		this.updateVal(box,diff);
		//Increase speed of valuchanges, until a certain point
		if(this.pe.frequency > 0.05) {
			this.pe.frequency = this.pe.frequency * 0.5
			this.pe.stop();
			this.pe.registerCallback();
		}
	},
	//Changes the value in the spinbox
	updateVal: function(box,diff) {
		if(!box.value) box.value = 0;
		var newVal = parseInt(box.value,10) + diff;
		if(newVal >= this.min && newVal <= this.max) {
			box.value = this.pad(newVal);
		}
	}
}

