var makeClass = function(prototypeObj,superClass) {
    var madeClass = function(o) {
        if (o!=false) this.initialize(o);
    };
    if (typeof superClass == 'function') {
        var superClassObj = new superClass(false);
        for(var method in superClassObj)
            prototypeObj[(prototypeObj[method])?'super_'+method:method] = superClassObj[method];
    };
    madeClass.prototype=prototypeObj;
    return madeClass;
};
var objEval = function(template,params,subFunc) {
    var subFunc = subFunc || function(str){
		with(params){
			try{return eval('('+(str+'').replace(/,/g,'.')+')');}
			catch(e){return '';}
		}
	};
    var match;var compiled = [];
    while (template.length > 0) {
        if (match = template.match(/(^|.|\r|\n)(#\{(.*?)\})/)) {
            compiled.push(template.slice(0, match.index));
            compiled.push(match[1] || '');
            var list = match[3].split(/\.|\[|\]\[|\]\.|\]/);
            if (!list[list.length-1]) list.pop();
			
			if(params[list]){
				if (typeof params[list]=='function') {
                	compiled.push(params[list](list[0]));
            	}else{
					compiled.push(params[list]);
				}
			}else{
				compiled.push(subFunc(list));
			}
			/*
            if (typeof params[list]=='function') {
                compiled.push(params[list](list[0]));
            }else if (!params[list]) {
                compiled.push(subFunc(list));
            }else{
                compiled.push(params[list]);
            }*/
            template = template.slice(match.index + match[0].length);
        } else {
            compiled.push(template), template = '';
        }
    }
    return compiled.join("");
};
var outerHTML = function(node) {
    var parent = node.parentNode;
    var el = document.createElement(parent.tagName);
    el.appendChild(node);
    var shtml = el.innerHTML;
    parent.appendChild(node);
    return shtml;
};
var html2el = function(html) {
	// trim whitespace
	html=html.trimSpaces();
    var div = document.createElement('div');
    div.innerHTML=html;
    return div.firstChild;
};
var obj2el = function(template,obj,subFunc) {
	//var subFunc = subFunc || function(){return ''};
	var obj = obj || {};
    return html2el(objEval(template,obj,subFunc))
};
var getTemplate = function(name) {
    if(typeof window[name]=='undefined'){
        if(document.getElementById(name)){
            var el = document.getElementById(name);
            window[name] = el.innerHTML.replace(/%7D/g,'}').replace(/%7B/g,'{').trimSpaces();
            el.parentNode.removeChild(el);
            return window[name];
        }else{
            return '';
        }    
    }else{
        return window[name];
    }
};
var getTemplateOuter = function(name) {
    if(typeof window[name]=='undefined'){
        if(document.getElementById(name)){
            var el = document.getElementById(name);
            window[name] = outerHTML(el).replace(/%7D/g,'}').replace(/%7B/g,'{').trimSpaces();
            el.parentNode.removeChild(el);
            return window[name];
        }else{
            return '';
        }    
    }else{
        return window[name];
    }
};

var appendScript = function(url){
	if(typeof Jaxer!='undefined' && Jaxer.isOnServer){
		Jaxer.load(url);
		//return;
	}
	var script = extendObj(
			document.createElement('script'),
			{src:url,type:"text/javascript"}
		); 
	document.getElementsByTagName('head')[0].appendChild(script);
};
var appendLink = function(url){
	var link = extendObj(
			document.createElement('link'),
			{href:url,rel:'stylesheet',type:'text/css',media:'screen'}
	);
    document.getElementsByTagName('head')[0].appendChild(link);
};
var loadJSandCSS = function(arg){
	var toLoad = (typeof arg =='object')?arg:[arg];
	for(var i=0;i<toLoad.length;i++){
		if(toLoad[i].match('css')) appendLink  (arg[i]);
		if(toLoad[i].match('js'))  appendScript(arg[i]);
	}
};
var addLoad = function(func) {
    var oldLoad = window.onload || function() {};
    window.onload = function() {
        oldLoad();
        func();
    };
};
var _$ = function(id) {
    if (typeof id =='string') {
        return document.getElementById(id);
    }else{
        return id;
    }
    
};
var $ = $ || _$;

Function.prototype.bind = function() {
    if (arguments.length < 2 && (typeof arguments[0]=='undefined')) return this;
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
      return __method.apply(object, args.concat($A(arguments)));
    }
};
String.prototype.stripTags = function () {
      return this.replace(/<\/?[^>]+>/gi, ' ');
}
String.prototype.trimSpaces = function () {
      return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '').replace(/\n/,'');
}
String.prototype.unescape = function () {
      return unescape(this);
}
String.prototype.gup = function (name) {
        return gup(name,this);
}
String.prototype.objEval = function (params,subfunc) {
      return objEval(this,params,subfunc);
}
String.prototype.obj2el = function (params,subfunc) {
      return obj2el(this,params,subfunc);
}
function $A(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
};
var getHashFromURL = function() {
    var r = window.location.href;
    var i = r.indexOf("#");
    return (i >= 0 ? r.substr(i+1) : "");
};
var setURLHash = function(newhash) {
    var url = window.location.href;
    url = (!url.match('#'))?url+'#':url.substr(0,url.indexOf('#')+1);
    window.location.href = url+newhash;
};

var tryThese = function(){
	var funcs = $A(arguments);
	for(i=0;i<funcs.length;i++){
		var res = funcs[i]();
		if(res)return res;
	}
};
var range = function(start,end){
    var a = [];
    for (var i=start; i <= end; i++) {a.push(i)};
    return a;
}

var extendObj = function(destination, source) {
  for (var property in source)
    destination[property] = source[property];
  return destination;
};

// overwrites dest with src, with properties that only exist in dest
var intersect = function(dest,src){
	for(var property in src){
		if(typeof dest[property]!='undefined')
			dest[property]=src[property];
	}
	return dest;
}
var union = function() {
    var finalObj = {};
    for (var i=0; i < arguments.length; i++) 
        extendObj(finalObj,arguments[i]);
    return finalObj;
};

var gup = function( name , scope ) {
	var scope = scope || window.location.href;
    var results = (new RegExp("[\\?&]"+name+"=([^&#]*)")).exec(scope);
    if ( results == null ) {return ""}
    else {return results[1]}
};

var toQueryString = function(queryObj) {
    var params=[];
    for (var property in queryObj){
        if (queryObj[property])
        params.push(property+'='+queryObj[property]);
    };
    return params.join('&');
};

var jsonHandler = makeClass({
    initialize: function(o) {
        // window.funcArray=[];
        this.funcI=0;
        this.o = extendObj({
            callbackKey:'_callback',
            funcPrefix:'jsonHandle'
        },o||{});
    },
    json : function(url,callbackFunc) {
        this.funcI++;
        var name = this.o.funcPrefix+this.funcI;
        window[name]=callbackFunc;
        appendScript(url+'&'+this.o.callbackKey+'='+name);
    }
});

/*
 usage
 var jsonHandle = new jsonHandler({
     callbackKey:'callback'
 });
*/



// TIMER URIL

var startTime = function(name) {
    window[name+'startTime'] = new Date().getTime();
};
var endTime = function(name,logIt) {
	var time = ((new Date().getTime())-window[name+'startTime'])+'ms';
    log(name+' took '+time);
	return time;
};
var timeMe = function(name,func){
	window[name+'startTime'] = new Date().getTime();
	var output = func();
	var time = ((new Date().getTime())-window[name+'startTime'])+'ms';
    log(name+' took '+time);
	return output;
}

var getJSObj = function(url,logjson) {
    var feed = window.ajaxCacheObj.call(url,24);
    var json = xml2json(parseXml(feed),'');
    if (typeof logjson!='undefined' && logjson) {log(json);};
    return eval('('+json+')');
};

var xml2JSO = function(xml,logjson) {
    var json = xml2json(parseXml(xml),'');
    return eval('('+json+')');
};

var getJSONObj = function(key) {
    var result = mapCacheObj.call(key);
    if (result) {
        return eval('('+result+')');
    }else{
        var xml = ajaxCacheObj.call(key);
        var json = xml2json(parseXml(xml),'');
        mapCacheObj.save(key,json,24);
        return eval('('+json+')');
    }
};
var stripTags = function(str,tags){
	tags = (typeof tags=='object')?tags:[tags];
	for (var i=0; i < tags.length; i++) {
		str = str.replace(new RegExp('<'+tags[i]+'[^>]*>([\\S\\s]*?)<\/'+tags[i]+'>', 'img'), '');            
	};
	return str;
}

//doesnt work if script is included in head
if(typeof Jaxer != "undefined"){
	//window.addEventListener("DOMContentLoaded",function(){
	if(document.body && !document.getElementById('log')){
		document.body.appendChild(obj2el('<div style="display:none" id="log"></div>',{}));
	}
	var script = document.createElement('script');
		script.innerHTML='if(window.addEventListener)window.addEventListener("DOMContentLoaded", function(){if (document.querySelectorAll) {var logItems = document.querySelectorAll("#log div.logged");for(var i=0;i<logItems.length;i++){console.log(eval("("+logItems[i].innerHTML+")"));}}}, false);';
		document.getElementsByTagName('head')[0].appendChild(script);

//},false);
	
}

if(typeof console =='undefined'){
    window.console = {};
    window.console.log = function() {};
}



loadedLibs='';
var jsRequireOnce = function(url){
			if(!loadedLibs.match(url)){
			Jaxer.load(url,window,'server');
			loadedLibs+=url;
		}
}

if(typeof console =='undefined'){
    window.console = {};
    window.console.log = function() {};
}

var teleport = function(name,obj) {
    var script = document.createElement('script');
		script.innerHTML='window.#{name} = #{json};'.objEval({name:name,json:JSON.encode(obj)});
        // Jaxer.Log.info(script.innerHTML);
		document.getElementsByTagName('head')[0].appendChild(script);
};
var passToClientFunction = function(name,obj) {
    var script = document.createElement('script');
		script.innerHTML='#{name}(#{json});'.objEval({name:name,json:JSON.encode(obj)});
		document.getElementsByTagName('head')[0].appendChild(script);
};

var log = function(n) {
	if(!n) return;
	if(n.nodeName){
		 var debug = '"<'+n.nodeName;
		 $A(n.attributes).forEach(function(n){if(n.specified) debug+=" "+n.name+'="'+n.value+'"'});
         debug+='>'+n.innerHTML+'</'+n.nodeName+'>"';
	}else{
		//var debug = (typeof n =='object')?JSON.encode(n):n+'';
		var debug = JSON.encode(n);
	}
	if (typeof Jaxer != 'undefined' && Jaxer.isOnServer)Jaxer.Log.info(debug);
	if(Jaxer.Config.DEV_MODE){passToClientFunction('console.log',n)};
	//if (document.getElementById('log'))document.getElementById('log').appendChild(obj2el('<div class="logged">' + debug + '</div>'));
};