
var core = {
	get: function(id) {
		return document.getElementById(id)
	}, 
	stopevent: function(event) {
		if (!(event = event || window.event)) return null
		event.cancelBubble = true
		if (event.stopPropagation) event.stopPropagation()
		return event
	},
	getchild: function(el, num) {
		if (!el) return null
		for (var k = 0; k < el.childNodes.length; k++)
			if (el.childNodes[k].nodeType != 3 && num-- == 0)
				return el.childNodes[k]
		return null
	},
	makenode: function(result) {
		holder = document.createElement('div')
		holder.innerHTML = result
		return holder.firstChild // html result in dom
	}, 
	keys: function(el) {
		var keys = []
		for (var k in el) keys.push(k)
		return keys
	},
	values: function(el) {
		var values = []
		for (var k in el) values.push(el[k]);
		return values
	},
	initclasses: function(el) {
		if (el && !el.classes) {
			el.classes = { }
			if (el.className.length) {
				var cl = el.className.split(' ')
				for (var k = 0; k < cl.length; k++)
					if (cl[k].length) el.classes[cl[k]] = cl[k]
			}
		}
	}, 
	addclass: function(el, cl) {
		if (!el.classes) core.initclasses(el)
		el.classes[cl] = cl
		el.className = this.keys(el.classes).join(' ')
	}, 
	delclass: function(el, cl) {
		if (!el.classes) core.initclasses(el)
		if (!el.classes[cl]) return
		delete el.classes[cl]
		el.className = this.keys(el.classes).join(' ')
	}, 
	coords: function(ob) {
		if (!ob) return { x: 0, y: 0 }
		else if (ob.offsetLeft == undefined) {
			if (ob.pageX || ob.pageY) return { x: ob.pageX, y: ob.pageY }
			else if (ob.clientX || ob.clientY) return {
				x: ob.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
				y: ob.clientY + document.body.scrollTop + document.documentElement.scrollTop
			}
			else return { x: 0, y: 0 }
		} else {
			var left = ob.offsetLeft - parseInt(ob.style.marginLeft || 0)
			var top = ob.offsetTop - parseInt(ob.style.marginTop || 0)
			while (ob = ob.offsetParent) {
				left += ob.offsetLeft
				top += ob.offsetTop
			}
			return { x: left, y: top }
		}
	}, 
	dom_id_counter: 0, 
	checkinput: function(el, reg, callerror) {
		if (!el) return false
		if (!el.onkeyup) {
			if (!reg) return false
			el.onkeyup = el.onfocus
			if (!el.custom) el.custom = { }
			el.custom.value = el.value
			el.custom.regexp = new RegExp(reg)
			el.custom.inputerror = callerror
			reg = 1
		}
		return core.oninput(el, reg)
	}, 
	oninput: function(el, runcallback) {
		if (!el) return false
		if (!el.custom || !el.custom.regexp) return true
		el.custom.valid = el.custom.regexp.test(el.value)
		el.custom.valid ? core.delclass(el, 'invalid') : core.addclass(el, 'invalid')
		if (0 && el.custom.inputerror && (!el.custom.lastinput || el.custom.lastinput != el.value)) {
			el.custom.lastinput = el.value
			////if (runcallback) el.custom.inputerror(el, el.custom.valid)
		}
		return true
	}, 
	checkform: function(el, runcallback) {
		if (!el) return false
		var values = el.serialize(true)
		var val, str = ''
		for (var k in values) {
			if (!el[k].onfocus) continue
			val = el[k].onfocus()
			//str += k + ': ' + el[k].value + ' -> ' + val + ' -> '
			if (el[k].custom == undefined || el[k].custom.valid == undefined) {
				str += 'no custom or valid found\n'
				continue
			}
			//str += 'valid: ' + el[k].custom.valid + '\n'
			if (!el[k].custom.valid) return false
		}
		//return str
		return true
	}, 
	onchange: function(el, cont, callback) {
		if (!el) return
		if (!el.onkeyup) el.onkeyup = el.onfocus
		if (el.original == undefined) {
			el.dom_id = ++this.dom_id_counter
			return el.original = el.value
		}
		el.style.backgroundColor = el.value == el.original ? '#ffffff' : '#ffff99'
		if (!cont.inputs) cont.inputs = { count: 0 }
		if (el.value == el.original) {
			if (cont.inputs[el.dom_id]) {
				delete cont.inputs[el.dom_id]
				cont.inputs.count--
			}
		} else {
			if (!cont.inputs[el.dom_id]) {
				cont.inputs[el.dom_id] = el
				cont.inputs.count++
			}
		}
		if (callback) callback(cont)
	}, 
	catch_error: function(func, args) {
		try {
			func.apply(this, args)
		} catch(err) {
			var str = ''
			if (!err) return alert('trace_error() -- got empty error object')
			str = 'Catched a ' + err.name + ': "' + err.message + '"\n' + 
				'Line ' + err.lineNumber + ' in ' + err.fileName + '\n\n' + err.stack
			alert(str)
		}		
	}, 
	trace: function(what, level) {
		if (level == undefined) level = 1
		switch (typeof what) {
			case 'undefined': return 'undefined'
			case 'function': return '[function]'
			case 'number':
			case 'string': return '' + what
			case 'boolean': return what ? 'true' : 'false'
			case 'object':
				if (level > 10) return '[nested level > 10]'
				var str = ''
				var pad = new Array(level + 1).join('  ')
				for (var k in what)
					if (k == 'value' || k == 'name' || k == 'tagName' || (what[k] && (typeof what[k] == 'object') && what[k].tagName && what[k].tagName == 'INPUT'))
						str += pad + k + ': ' + core.trace(what[k], level + 1) + '\n'
				var pad = new Array(level).join('  ')
				return '{\n' + str + pad + '}'
		}
	}
}

function get(id) { return core.get(id) }

var mouse = {
	dragged: { target: null }, 
	// drag a target
	drag: function(target, ev) {
		this.dragged = {
			target: target, 
			zIndex: target.style.zIndex, 
			position: target.style.position, 
			display: target.style.display
		}
		target.style.zIndex = 1000
		target.style.position = 'absolute'
		target.style.display = 'block'
		document.onmousemove = this.ondrag
		this.ondrag(ev || window.event)
	}, 
	// release a dragged target
	release: function() {
		document.onmousemove = null
		if (!mouse.dragged.target) return
		mouse.dragged.target.style.zIndex = mouse.dragged.zIndex
		mouse.dragged.target.style.position = mouse.dragged.position
		mouse.dragged.target.style.display = mouse.dragged.display
		mouse.dragged.target = null
	}, 
	// drop a dragged target (onto something)
	drop: function() {
	}, 
	ondrag: function(e) {
	    if (!mouse.dragged.target) return mouse.release()
		pos = core.coords(e || window.event)
		mouse.dragged.target.style.left = '' + (pos.x + 5) + 'px'
		mouse.dragged.target.style.top = '' + (pos.y + 5) + 'px'
	}
}


var ajax = {
	requests: [], 
	request: function(method, url, param, callback) {
		if (!param) param = { }
		else if (typeof param == 'string') param = get(param) || { }
		else if (typeof param == 'object' && param.tagName == 'FORM') {
			//param = param.serialize(true) // IE: serialize not defined
			param = Form.serializeElements(Form.getElements(param), true);
		}
		vars = callback == undefined || typeof callback == 'function' ? 
			{ onSuccess: callback || this.exec } : 
			(typeof callback == 'object' ? callback : this.exec)
		vars.method = 'post'
		vars.parameters = param
		new Ajax.Request(url, vars)
	}, 
	get: function(url, param, callback) { return this.request('get', url, param, callback) }, 
	post: function(url, param, callback) { return this.request('post', url, param, callback) }, 
	exec: function(trans, json) {
		var result = { }
		if (json == undefined) {
			var response = typeof trans == 'string' ? trans : (trans.responseText || "{ }");
			result = eval('(' + response + ')')
		} else result = json
		target = get(result.id)
		switch (result.action) {
			case 'update': if (target) target.parentNode.replaceChild(core.makenode(result.value), target); break;
			case 'before':
			case 'insert_before': if (target) target.parentNode.insertBefore(core.makenode(result.value), target); break;
			case 'insert': if (target) target.innerHTML += result.value; break;
			case 'inner': if (target) target.innerHTML = result.value; break;
			case 'clear': if (target) target.innerHTML = ''; break;
			case 'remove': if (target) target.parentNode.removeChild(target); break;
			case 'value': if (target) target.value = result.value; break;
			case 'reset': if (target) target.reset(); break;
			case 'style': if (target) target.style[result.key] = result.value; break;
			case 'class': if (target) target.className = result.value; break;
			case 'alert': alert(result.value); break;
			case 'confirm': choice = confirm(result.value); ajax.post(result.url, { confirm: choice ? 1 : 0 }); break;
			case 'redirect': window.location.href = result.value; break;
			case 'pass': break;
			case 'execute':
				for (var k = 0; k < result.value.length; k++)
					ajax.exec(null, result.value[k])
				break;
			default: alert('unhandled response: ' + response);
		}
		return result
	}
}

