
var core = {
	get: function(id) {
		return typeof id == 'string' && id.length ? document.getElementById(id) : null
	}, 
	stopevent: function(event) {
		if (!(event = event || window.event)) return null
		event.cancelBubble = true
		if (event.stopPropagation) event.stopPropagation()
		return event
	},
	onclick: function(event) {
		var el = event.srcElement || event.target
		if (el.tagName == 'BODY' || el.tagName == 'IMG') return
		//core.debug.debug('click on &lt;' + el.tagName + ' ' + el.className + '&gt;' + (el.href ? ' ' + el.href : ''), 'ajax')
		try {
			if (el.onload) {
				if (typeof el.onload == 'string') eval("(function() { " + el.onload + " }).apply(el, [event])")
				else el.onload()
			} else if (el.href && el.href.length && !el.className.match(/filelink/)) ajax.request(el.href)
			else return true
			core.stopevent(event = event || window.event)
		} catch (e) {
			core.debug.debug("core.onclick(): error in " + (el.onload ? "onload()" : "loading") + 
				" &lt;" + el.tagName + (el.id ? " id='" + el.id + "'" : "") + " class='" + el.className + "'&gt;", 'ajax')
		}
	}, 
	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
	}, 
	remove: function(el) {
		return el && el.parentNode ? el.parentNode.removeChild(el) : null
	}, 
	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(' ')
	}, 
	toggleclass: function(el, cl) {
		if (!el.classes) core.initclasses(el)
		if (el.classes[cl]) delete el.classes[cl]
		else el.classes[cl] = 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( Element.hasClassName( el, "nocheck" ) ) return true;
		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 = Form.serializeElements(Form.getElements(el), 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)
	}, 
	submit: function(form, url) {
		if (typeof form == 'string') form = core.get(form)
		var tries = 4
		while (form && form.tagName != 'FORM' && form.parentNode && tries--) form = form.parentNode
		if (form && form.tagName === 'FORM') {
			if (typeof url == 'string') form.action = url
			if (form.onsubmit == undefined || form.onsubmit()) form.submit()
		}
		return false
	}, 
	change_params: function(url, params) {
		if (typeof params == 'string') {
			var tmp = params.split("=", 2)
			params = { }
			params[tmp[0]] = tmp[1]
		}
		var val
		for (var key in params) {
			val = key + '=' + params[key]
			url = url.indexOf(key) == -1 ? 
				url + (url.indexOf('?') == -1 ? '?' : '&') + val : 
				url.replace(new RegExp(key + "=[^&]*"), val)
		}
		return url
	}, 
	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 + '}'
		}
	}, 
	debug: {
		debug: function(stuff, type, ret) {
			if (type && !this.settings[type]) return
			if (typeof stuff == 'object') {
				var s = ''
				for (var k in stuff)
					s += '' + k + ': ' + (typeof stuff[k] == 'function' ? '(function)' : this.debug(stuff[k], type, 1)) + ', '
				stuff = '{ ' + s.slice(0, -2) + ' }'
			}
			if (ret > 0 || stuff == undefined) return stuff
			var x = document.getElementById('debug');
			if (!x) {
				x = core.makenode("<div id='debug' class='core_debugger' ondblclick='this.parentNode.removeChild(this);'><span onclick='biggerCoreDebug(1);'>[+]</span> <span onclick='biggerCoreDebug(0);'>[-]</span><br>---- debug messages -- doubleclick to hide ----<br /><br /></div>")
				if (core.browser.slice(0, 2) == 'ie') x.style.position = 'absolute'
				document.body.appendChild(x)
			} else if (ret < 0) x.innerHTML = ''
			x.style.display = 'block'
			x.innerHTML += stuff + (stuff.length > 120 ? '<br />' : '') + '<br />';
			x.scrollTop = x.scrollHeight;
		}
	}
}

function biggerCoreDebug(direction) {
	var change_size = 200;

	if (direction == 1) {
		$("debug").setStyle({width: ($("debug").getWidth() + change_size) + 'px'});
	}
	
	if (direction == 0) {
		if ($("debug").getWidth() <= change_size+40) {
			$("debug").setStyle({width: ($("debug").getWidth() - change_size + 40) + 'px'});
		} else if ($("debug").getWidth() <= 51) {
			//too small
		} else {
			$("debug").setStyle({width: ($("debug").getWidth() - change_size) + 'px'});
		}
	}

}

function fillSelect( data ) {
	var selectEl = core.get( data.selectId );
	if( ( selectEl == null ) || ( selectEl.tagName.toLowerCase() != 'select' ) ) return;

	for( var i = 0 ; i < selectEl.options.length ; i++ ) selectEl.options[ i ] = null;
	selectEl.options.length = 0;
	
	i = 0;
	for( key in data.list ) {
		if( !isNaN( parseInt( key ) ) ) {
			selectEl.options[ i ] = new Option( data.list[ key ] , key );
			i++;
		}
	}
	
	selectEl.selectedIndex = 0;
}

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 = {
	targets: [], 
	requests: { count: 0 }, 
	counter: 0, 
	preload: function(hash, type, callback) {
		//core.debug.debug('preload: ' + hash, 'ajax')
		//core.debug.debug(this.requests)
		if (!this.requests.count) this.show_preload()
		if (type == 'auto' && this.requests.hash && this.requests[this.requests.hash]) delete this.requests[this.requests.hash]
		else this.requests.count++
		if (type == 'auto') this.requests.hash = hash
		this.requests[hash] = { num: this.counter++, type: type, callback: callback }
		//core.debug.debug(this.requests)
	}, 
	loaded: function(hash) {
		//core.debug.debug('loaded: ' + hash, 'ajax')
		//core.debug.debug(this.requests)
		if (this.requests[hash] == undefined) return 0
		delete this.requests[hash]
		this.requests.count--
		if (this.requests.count < 0) this.requests.count = 0
		//core.debug.debug(this.requests)
		if (!this.requests.count) this.remove_preload()
		return 1
	}, 
	show_preload: function() { }, 
	remove_preload: function() { }, 
	onstart: function(url, param) { }, 
	onresponse: function(url, trans, json) { }, 
	oncomplete: function(url, trans, json) { }, 
	show: function(hash) { return AjaxHistory.updateUrl(hash, 0, 0, 1) }, 
	go: function(url, param, callback) { return this.request(url, param, callback, 'post', 'auto') }, 
	load: function(url, param, callback) { return this.request(url, param, callback, 'post', 'json') }, 
	get: function(url, param, callback) { return this.request(url, param, callback, 'get') }, 
	post: function(url, param, callback) { return this.request(url, param, callback, 'post') }, 
	request: function(url, param, callback, method, response) {
		if (typeof url == 'object') url = url.href
		// strip the url if needed: http(s)://x.com/baseurl/requested/page -> requested/page
		if (url.slice(0, 7) == 'http://' || url.slice(0, 8) == 'https://') url = url.slice(url.indexOf('/', 9) + core.baseurl.length)
		if (!response) response = url.slice(0, 1) == '#' ? 'auto' : 'json'
		//core.debug.debug(url)
		if (url.slice(0, 1) == '#') url = url.slice(1)
		if (url.slice(0, 2) == '~/') url = url.slice(2)
		// TODO: remove this later
		url = url.split('|').shift()
		if (response && response == 'auto') AjaxHistory.updateUrl(url, 0, 0, 1)
		//core.debug.debug(url)
		if (url.slice(0, 1) != '/') url = core.baseurl + url

		if (this.requests[url] != undefined) {
			core.debug.debug("ignoring pending request: '" + url + "'", 'ajax')
			return false // request already underway
		}

		if( typeof( _gaq ) == 'object' ) {		// for google analytics, only with ajax.go
			if( response && ( response == 'auto' ) ) _gaq.push( [ '_trackPageview' , url ] );
			else if( response && ( url.indexOf( '/public/order/send' ) != -1 ) ) _gaq.push( [ '_trackPageview' , url ] );
		}

		// params
		if (!param) param = { }
		else if (typeof param == 'string') param = get(param) || { }
		else if (typeof param == 'object' && param.tagName == 'FORM')
			param = Form.serializeElements(Form.getElements(param), true); // IE: serialize() not defined
		if (param.response == undefined) param.response = response

		if (this.onstart) this.onstart(url, param)

		// setup prototype ajax request
		vars = typeof callback == 'function' ? { onComplete: callback } : (typeof callback == 'object' ? callback : { })
		this.preload(url, response, typeof vars.onComplete == 'function' ? vars.onComplete : null)
		vars.onComplete = function(trans, json) { ajax.process.apply(ajax, [trans, json]) }

		vars.method = method || 'post'
		vars.parameters = param
		core.debug.debug('<br />++ ajax.' + vars.method + ': ' + decodeURIComponent(url), 'ajax')
		new Ajax.Request(url, vars)
		return false
	}, 
	process: function(trans, json) {
		var hash = trans.request.url, callback
		if (!this.requests[hash]) return
		var callback = this.requests[hash].callback
		this.loaded(hash)
		if (this.onresponse) this.onresponse(hash, trans, json)
		try {
			if (typeof callback == 'function') callback.apply(null, [trans, json]);
			else this.exec(trans, json);
		} catch (e) {
			core.debug.debug('&nbsp; -- ajax.process: catched ' + e.name + ' in ' + e.fileName.split('/').pop() + ':' + e.lineNumber + ': <b>' + e.message + '</b>', 'ajax')
		}
		if (this.oncomplete) this.oncomplete(hash, trans, json)
	}, 
	checkinnerhtml: function(el) {
		var res = !el || typeof el != 'object' || el.tagName == 'INPUT' || el.tagName == 'IMG'
		if (res) core.debug.debug("&nbsp; ?? cannot change innerHTML in " + el.tagName + "#" + el.id, 'ajax')
		return res
	}, 
	exec: function(trans, json, subaction) {
		var result = json || { }
		if (json == undefined) {
			json = typeof trans == 'string' ? trans : (trans.responseText || "{ }")
			result = json = eval('(' + json + ')')
		}
		target = get(result.id)
		// trace this action
		var s = subaction == undefined ? '&nbsp; -- ajax.exec: ' + (trans && trans.request ? decodeURIComponent(trans.request.url) : '(url?)') + (result.action == 'execute' ? '' : '<br />') : ''
		if (result.action != 'execute' && result.action != 'debug') {
			var tmp = result.value && result.value.length ? result.value.split('>').shift().replace('\t', '') : "''"
			if (result.value && result.value.length > 60) tmp = tmp.slice(0, 60) + '... [' + result.value.length + ']'
			tmp = tmp.replace('<', '&lt;')
			s += '&nbsp; -- ' + (result.id || '') + (result.id && !target ? '(??)' : '') + '.' + result.action + (result.key ? '.' + result.key : '') + ' = ' + tmp
		}
		if (s.length) core.debug.debug(s, 'ajax')
		// run this action
		switch (result.action) {
			case 'inner': if (target && !this.checkinnerhtml(target)) target.innerHTML = result.value; break;
			case 'insert': if (target && !this.checkinnerhtml(target)) target.innerHTML += result.value; break;
			case 'clear': if (target && !this.checkinnerhtml(target)) target.innerHTML = ''; break;
			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 'append': if (target) target.appendChild(core.makenode(result.value)); 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 'property': if (target) target[result.key] = result.value; break;
			case 'style': if (target) target.style[result.key] = result.value; break;
			case 'class': if (target) target.className = result.value; break;
			case 'addclass': if (target) core.addclass( target, result.value ); break;
			case 'delclass': if (target) core.delclass( target, result.value ); break;
			case 'focus': if (target) target.focus(); break;
			case 'blur': if (target) target.blur(); break;
			case 'alert': alert(result.value); break;
			case 'confirm': choice = confirm(result.value); this.post(result.url, { confirm: choice ? 1 : 0 }); break;
			case 'debug': core.debug.debug( result.value, result.id ); break;
			case 'reload': window.location.reload(); break;
			case 'title': document.title = result.value; break;
			case 'redirect':
				if (result.value.slice(0, 1) == '#') this.go(result.value.slice(1));
				else window.location.href = result.value;
				break;
			case 'run': eval(result.value); break;
			case 'set': eval( result.id + " = result.value;" ); break;
			case 'pass': break;
			case 'fill_select': fillSelect( eval( '(' + result.value + ')' ) ); break;
			case 'execute':
				for (var k = 0; k < result.value.length; k++)
					if (result.value[k].action != 'pass')
						this.exec(null, result.value[k], 1)
				break;
			default: core.debug.debug('-- unknown action', 'ajax')
		}
		return result
	}
}


