var IE = (!window.getComputedStyle && !!document.getElementById);
var IE6 = IE && navigator.appVersion.indexOf("MSIE 7") == -1;

function $A(obj, iterator){
	var arr = [];
	for(var i = 0; i < obj.length; i++){
		arr.push(iterator ? iterator(obj[i]) : obj[i]);
	}
	return arr;
}
function $O(item, index){
	return {item: item, index: index};
}
var $break = new Object();
var $continue = new Object();
//Object functions
Object.copy = function(obj){
	var obj_c = {};
	for(var i in obj){
		obj_c[i] = obj[i];
	}
	return obj_c;
}
function MergeObjects(obj1, obj2){
	for(var i in obj2){
		obj1[i] = obj2[i];
	}
	return obj1;
}
Object.extend = MergeObjects;
function undefined(obj){
	return (typeof obj == "undefined");
}

var __toString = function(){
	var str = __toString.bounds.left + "object " + this.__name + __toString.bounds.right;
	return str;
};
__toString.bounds = {
	left: "[[",
	right: "]]"
};

function $(id, doc){
	return $Node((doc || document).getElementById(id));
}
function $T(tName, parent, FIRST){
	var arr = $A((parent || document).getElementsByTagName(tName), $Node);
	return FIRST ? arr[0] : arr;
}
function $C(className, parent, tagName, FIRST){
	var detected = (parent && parent.IS_ARRAY ? parent : ($T(tagName || "*", parent) || [])).detects(detectFuncs.className.bind(className));
	return detected.length ? (FIRST ? detected[0] : detected) : null;
}
function $C_arr(arr_classNames, parent, tagName, iterator){
	var ret_arr = [];
	parent = parent ? _elem(parent) : document.body;
	tagName = tagName ? tagName : "*" ;
	iterator = iterator ? iterator : function(val){return val;};
	var collection = $T(tagName, parent);
	collection.each(function(col, c_ind){
		arr_classNames.each(function(cName, ind){
			if(col.className.has_separated_value(cName)){
				ret_arr[ind] = 	iterator(col);
				throw $continue;
			}
		});
	});
	return ret_arr;
}
function $I(type, parent, FIRST){
	var detected = (parent && parent.IS_ARRAY ? parent : ($T("INPUT", parent) || [])).detects(detectFuncs.type.bind(type));
	return detected.length ? (FIRST ? detected[0] : detected) : null;
}
function $Node(elem){//extend node with usefull functions
	if(!elem){
		return null;
	}
	for(var i in Node_extendFucntions){
		if(typeof elem[i] == 'undefined'){
			elem[i] = Node_extendFucntions[i];
		}
	}
	return elem;
}
function $F(form){//getFormElements
	var detected = ($T("INPUT", form) || []).concat($T("SELECT", form) || []).concat($T("TEXTAREA", form) || []);
	return detected.length ? detected : null;
}
function $N(name, parent, FIRST){//getFormElementByName
	var detected = (parent && parent.IS_ARRAY ? parent :  ($F(parent) || [])).detects(detectFuncs.name.bind(name));
	return detected.length ? (FIRST ? detected[0] : detected) : null;
}
var detectFuncs = {
	name: function(el){
		return el.name.toLowerCase() == this.toLowerCase();
	},
	className: function(el){
		return el.hasClass(this);
	},
	type: function(el){
		return el.type.toLowerCase() == this.toLowerCase();
	},
	value: function(el){
		return el.value == this;	
	}
}
var Node_extendFucntions = {
	addClass: function(c){
		if(this.hasClass(c)){
			return false;
		}
		this.className = this.className.split(" ").add(c).join(" ");
		return true;
	},
	removeClass: function(c){
		if(!this.hasClass(c)){
			return false;
		}
		this.className = this.className.split(" ").remove_v(c).join(" ");
		return true;
	},
	setClass: function(c){
		this.className = c;
	},
	replaceClass: function(old_c, c){
		this.className = this.className.replace(old_c, c);
	},	
	hasClass: function(className){
		return this.className.split(" ")._indexOf(className) != -1;
	},
	app: function(elem){
		if(!elem || !elem.nodeType){
			return false;
		}
		this.appendChild(elem);
		return true;
	},
	prep: function(elem){
		if(!elem || !elem.nodeType){
			return false;
		}
		if(!this.firstChild){
			this.app(elem)
		}else{
			this.insertBefore(elem, this.firstChild);
		}
		return true;
	},
	remove: function(elem){
		if(!elem || !elem.nodeType || elem.parentNode != this){
			return false;
		}
		this.removeChild(elem);
		return true;
	}
};

//Function.prototype
Function.prototype.bind = function(){
	var _args = [];
	var _method = this;
	var _object = arguments[0];
	for(var i = 1; i < arguments.length; i++){
		_args.push(arguments[i]);
	}
	var retfunc = function(){
		return _method.apply(_object, $A(arguments).concat(_args));
	};
	retfunc.bound = $A(arguments);
	return retfunc;
};
Function.prototype.bindAvoidingEvent = function(){
	var _args = [];
	var _method = this;
	var _object = arguments[0];
	for(var i = 1; i < arguments.length; i++){
		_args.push(arguments[i]);
	}
	return function(){
		return _method.apply(_object, $A(_args).concat(arguments));
	}	
};
function _isChild(elem, parent){
	if(!elem)
		return false;
	var par = elem.parentNode;
	try{
		while(par && par != parent && par.nodeType != 9){
			par = par.parentNode;
		}
	}catch(e){
		alert(alert(par.nodeType));
	}
	return !par ? false : (par == parent);
}
function clearElem(elem){
	elem = _elem(elem);
	while(elem.firstChild){
		elem.removeChild(elem.firstChild);
	}
}
function _elem(obj){
	if(obj.nodeName){
		return obj;
	}else{
		if(obj.elem){
			return obj.elem;
		}
		if(obj.moveable){
			return _elem(obj.moveable);
		}
		if(obj.resizeable){
			return _elem(obj.resizeable);		
		}
	}
}

//Boolean.prototype
Boolean.prototype.each = function(){
	return false;
};

//Array.prototype
Array.prototype.each = function(iterator){
	try{
		for(var i = 0; i < this.length; i++){
			try{
				var ret = iterator(this[i], i);
				if(ret != null){
					this[i] = ret;
				}
			}catch(e){
				if(e != $continue)
					throw e;
			}
		}
	}catch(e){
		if(e != $break)
			throw e;
	}
	return this;
};
Array.prototype.clone = function(){
	var arr = [];
	this.each(function(item){
		arr.push(item);
	});
	return arr;
};
Array.prototype._indexOf = function(item){
	var index = -1;
	this.each(function(it, ind){
		if(it == item){
			index = ind;
			throw $break;
		}
	});
	return index;
}
if(undefined(Array.prototype.indexOf)){
	Array.prototype.indexOf = Array.prototype._indexOf;
};
Array.prototype.random = function(REM){
	var ind = Math.round(Math.random() * (this.length - 1));
	var item = this[ind];
	if(REM){
		this.remove(ind);
	}
	return item;
};
Array.prototype.last = function(){
	return this[this.length - 1];
};
Array.prototype.invert = Array.prototype.reverse;
Array.prototype.detect = function(iterator, obj){
	var ret;
	this.each(function(item, index){
		if((iterator || _eF)(item, index)){
			ret = obj ? $O(item, index) : item;
			throw $break;
		}
	});
	return ret;
};
Array.prototype.detects = function(iterator, obj){
	var ret = [];
	this.each(function(item, index){
		if((iterator || _eF)(item, index)){
			ret.push(obj ? $O(item, index) : item);
		}
	});
	return ret;
};
Array.prototype.remove = function(num){
	if(num >= this.length || num < 0){
		return;
	}
	var ret = this[num];
	for(var i = num; i < this.length - 1; i++){
		this[i] = this[i+1];
	}
	this.pop();
	return ret;
};
Array.prototype.insert = function(value, position){
	position = (position && position > 0) ? position : 0;
	if(position >= this.length){
		this.push(value);
		return;
	}
	for(var i = this.length - 1; i >= position; i--){
		this[i+1] = this[i];
	}
	this[position] = value;
};
Array.prototype.add = function(v){
	this.push(v);
	return this;
};
Array.prototype.remove_v = function(v){
	this.remove(this.indexOf(v));
	return this;
}
Array.prototype.has = function(val){
	return (this.indexOf(val) != -1);
}
Array.prototype.IS_ARRAY = true;
function toConsole(what, console){
	if(undefined(what)){
		what = "[undefined]";
	}
	console = console ? console : !undefined(document.body) ? document.body : null;
	if(!console){
		document.write(what);
	}
	var oDiv = document.createElement('DIV');
	oDiv.className = toConsole.defaultElemClassName;
	oDiv.appendChild(document.createTextNode(what));
	console.appendChild(oDiv);
	if(console.onprint){
		console.onprint.fire();
	}
}
toConsole.defaultElemClassName = "printed-elem";
var print = toConsole;
String.prototype.print = Array.prototype.print = Number.prototype.print = Boolean.prototype.print = Function.prototype.print = function(console){
	print(this, console);
};
function printObject(o, parent){
	for(var i in o){
		print(i + " => " + o[i], parent);
	}
}
var print_r = printObject;
function __init_settings(settings){
	var obj = Object.extend(Object.copy(this.constructor.__default), settings || {});
	return obj;
}
function __init_iterators(iterators){
	return Object.extend(this.constructor.__iterators, iterators || {});
}

function $Radios(tpl_collection, label_settings, iterators){
	this.collection = tpl_collection;
	this.radios = this.elems = [];
	this.labels = [];
	this.disabled = [];
	this.onchange = new DOMEvent(this);
	this.ondisable = new DOMEvent(this);
	this.onenable = new DOMEvent(this);
	this.onadd = new DOMEvent(this);
	this.onremove = new DOMEvent(this);
	this.settings = this.init_settings(label_settings);
	this.iterators = this.init_iterators(iterators);
	this.init();
}
$Radios.prototype.init_settings = __init_settings;
$Radios.prototype.init_iterators = __init_iterators;
$Radios.prototype.init = function(){
	this.collection.each(function(item, ind){
		this.init_radio(item, ind);
		this.init_label(item, ind);
	}.bind(this));
	if(this.collection.length){
		this.pattern = this.collection[0].cloneNode(true);
		this.parent = this.collection[0].parentNode;
	}
};
$Radios.prototype.init_radio = function(item, ind){
	var rad = $I("radio", item, 1);
	this.radios.push(rad);
	if(rad.checked){
		this.checked = rad;
		this.value = rad.value;
	}
	if(rad.disabled){
		this.disabled.push(rad);
	}
	rad.model = this;
	rad.root = item;
	item._radio = rad;
	rad.onclick = this.click;
	this.iterators.radio.each(function(iter){
		rad = iter(rad);
	});
};
$Radios.prototype.init_label = function(item, ind){
	var lab = this.find_label(item);
	this.labels.push(lab);
	if(!lab){
		return null;
	}
	lab.radio = item._radio;
	lab.model = this;
	lab.root = item;
	lab.value = lab.firstChild.nodeValue;
	lab.onclick = this.click.bind(lab.radio);	
	item._label = lab;
	item._radio.label = lab;
	this.iterators.label.each(function(iter){
		lab = iter(lab);
	});
};
$Radios.prototype.find_label = function(item){
	var detected = $T(this.settings.labelTag, item);
	if(!detected){
		return null;
	}
	if(this.settings.labelClass){
		return $C(this.settings.labelClass, detected, null, 1);
	}else{
		return detected[0];
	}	
};
$Radios.prototype.check = function(rad){
	if(rad.disabled){
		return false;
	}
	var old_checked = this.checked;
	rad.checked = true;
	this.checked = rad;
	this.value = rad.value;
	this.onchange.fire(rad, old_checked);
	return true;
};
$Radios.prototype.click = function(){

	this.model.check(this);
};
$Radios.prototype.remove = function(rad){
	var ind = this.elems.indexOf(rad);
	var item = this.collection[ind];
	var lab = this.labels[ind];

	this.parent.remove(item);
	this.collection.remove(ind)
	this.elems.remove(ind);
	this.labels.remove(ind);
	this.onremove.fire(rad, rad.label, rad.root);
};
$Radios.prototype.change_label = function(lab, val){
	clearElem(lab);
	lab.app(Text(val));
	lab.value = val;
}
$Radios.prototype.add = function(rad_val, label_val){
	var item = this.pattern.cloneNode(true);
	this.collection.push(item);
	var ind = this.collection.length - 1;
	this.parent.app(item);
	this.init_radio(item, ind);
	this.init_label(item, ind);
	if(item._label){
		this.change_label(item._label, label_val);
	}
	item._radio.value = rad_val;
	
	this.onadd.fire(item._radio, item._label, item);
};
$Radios.prototype.disable = function(rad){
	if(rad.disabled){
		return false;
	}
	rad.disabled = 1;
	this.disabled.push(rad);
	this.ondisable.fire(rad);
	return true;
};
$Radios.prototype.enable = function(rad){
	if(!rad.disabled){
		return false;
	}
	rad.disabled = 0;
	this.disabled.remove_v(rad);
	this.onenable.fire(rad);
	return true;
};
$Radios.prototype.__name = "radios";
$Radios.prototype.toString = __toString;

$Radios.__default = {
	labelClass: "label",
	labelTag: "SPAN"
};
$Radios.__iterators = {
	radio: [], label: []
};

function $Checkbox(checkbox, label){
	this.elem = checkbox;
	this.name = this.elem.name;
	this.label = label || null;
	this.oncheck = new DOMEvent(this);
	this.onuncheck = new DOMEvent(this);
	this.ondisable = new DOMEvent(this);
	this.onenable = new DOMEvent(this);
	this.init();
}
$Checkbox.prototype.init = function(){
	this.init_check();
	this.init_label();
};
$Checkbox.prototype.init_check = function(){
	this.CHECKED = this.elem.checked;
	this.DISABLED = this.elem.disabled;
	this.elem.model = this;
	this.elem.onclick = this.click.bind(this);
};
$Checkbox.prototype.init_label = function(){
	if(!this.label){
		return false;
	}
	this.label.value = this.label.firstChild.nodeValue;
	this.label.model = this;
	this.label.onclick = this.click.bind(this);
};
$Checkbox.prototype.check = function(){
	if(this.CHECKED || this.DISABLED){
		return false;
	}
	this.elem.checked = 1;
	this.CHECKED = true;
	this.oncheck.fire();
	return true;
};
$Checkbox.prototype.uncheck = function(){
	if(!this.CHECKED || this.DISABLED){
		return false;
	}
	this.elem.checked = 0;
	this.CHECKED = false;
	this.onuncheck.fire();
	return true;
};
$Checkbox.prototype.click = function(){
	if(this.CHECKED){
		this.uncheck();
	}else{
		this.check();
	}
};
$Checkbox.prototype.set_name = function(name){
	this.elem.name = name;
	this.name = name;
};
$Checkbox.prototype.set_label = function(val){
	this.label.value = val;
	clearElem(this.label);
	this.label.app(Text(val));
}
$Checkbox.prototype.disable = function(){
	if(this.DISABLED){
		return false;
	}
	this.DISABLED = true;
	this.elem.disabled = 1;
	this.ondisable.fire();
	return true;
};
$Checkbox.prototype.enabel = function(){
	if(!this.DISABLED){
		return false;
	}
	this.DISABLED = false;
	this.elem.disabled = 0;
	this.onenable.fire();
	return true;
};
function $Checkset(checkbox_collection){

}
function _eF(x){
	return x;
}
function clearElem(elem){
	if(!elem){
		return false;
	}
	while(elem.firstChild){
		elem.removeChild(elem.firstChild);
	}
}
function Text(val){
	return document.createTextNode(val);
}
function __init_events(){
	this._events.each(function(obj){
		if(obj.func_name){
			if(obj.type == "before"){
				createBeforeEvent(this, obj.func_name, obj.name)
			}else if(obj.type == "after"){
				createAfterEvent(this, obj.func_name, obj.name);
			}
		}else{
			this["on" + obj.name] = new DOMEvent(this);
		}
	}.bind(this));
}
function Element(tName, attribs){
	var el = document.createElement(tName);
	var obj = attribs || {};
	for(var i in obj){
		el[i] = obj[i]
	}
	return $Node(el);
}