var Class = function(properties){
	var klass = function(){
		return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
	};
	$extend(klass, this);
	klass.prototype = properties;
	klass.constructor = Class;
	return klass;
};
Class.empty = function(){};

Class.prototype = {
	extend: function(properties){
		var proto = new this(null);
		for (var property in properties){
			var pp = proto[property];
			proto[property] = Class.Merge(pp, properties[property]);
		}
		return new Class(proto);
	},

	implement: function(){
		for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);
	}

};
/*
Class: window
	Some properties are attached to the window object by the browser detection.
	
Note:
	browser detection is entirely object-based. We dont sniff.

Properties:
	window.ie - will be set to true if the current browser is internet explorer (any).
	window.ie6 - will be set to true if the current browser is internet explorer 6.
	window.ie7 - will be set to true if the current browser is internet explorer 7.
	window.gecko - will be set to true if the current browser is Mozilla/Gecko.
	window.webkit - will be set to true if the current browser is Safari/Konqueror.
	window.webkit419 - will be set to true if the current browser is Safari2 / webkit till version 419.
	window.webkit420 - will be set to true if the current browser is Safari3 (Webkit SVN Build) / webkit over version 419.
	window.opera - is set to true by opera itself.
*/

window.xpath = !!(document.evaluate);
if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
else if (document.childNodes && !document.all && !navigator.taintEnabled) window.webkit = window[window.xpath ? 'webkit420' : 'webkit419'] = true;
else if (document.getBoxObjectFor != null) window.gecko = true;

/*compatibility*/

window.khtml = window.webkit;

Object.extend = $extend;

/*end compatibility*/

//htmlelement

if (typeof HTMLElement == 'undefined'){
	var HTMLElement = function(){};
	if (window.webkit) document.createElement("iframe"); //fixes safari
	HTMLElement.prototype = (window.webkit) ? window["[[DOMElement.prototype]]"] : {};
}
HTMLElement.prototype.htmlElement = function(){};

//enables background image cache for internet explorer 6

if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};
var $extend = function(){
	var args = arguments;
	if (!args[1]) args = [this, args[0]];
	for (var property in args[1]) args[0][property] = args[1][property];
	return args[0];
};

function $type(obj){
	if (!$defined(obj)) return false;
	if (obj.htmlElement) return 'element';
	var type = typeof obj;
	if (type == 'object' && obj.nodeName){
		switch(obj.nodeType){
			case 1: return 'element';
			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
		}
	}
	if (type == 'object' || type == 'function'){
		switch(obj.constructor){
			case Array: return 'array';
			case RegExp: return 'regexp';
			case Class: return 'class';
		}
		if (typeof obj.length == 'number'){
			if (obj.item) return 'collection';
			if (obj.callee) return 'arguments';
		}
	}
	return type;
};
function $merge(){
	var mix = {};
	for (var i = 0; i < arguments.length; i++){
		for (var property in arguments[i]){
			var ap = arguments[i][property];
			var mp = mix[property];
			if (mp && $type(ap) == 'object' && $type(mp) == 'object') mix[property] = $merge(mp, ap);
			else mix[property] = ap;
		}
	}
	return mix;
};
function $defined(obj){
	return (obj != undefined);
};

Class.Merge = function(previous, current){
	if (previous && previous != current){
		var type = $type(current);
		if (type != $type(previous)) return current;
		switch(type){
			case 'function':
				var merged = function(){
					this.parent = arguments.callee.parent;
					return current.apply(this, arguments);
				};
				merged.parent = previous;
				return merged;
			case 'object': return $merge(previous, current);
		}
	}
	return current;
};
	fw = function(){}
	fw.globals = {};
	fw.helpers = {};
	fw.libraries = {};

function $a(likeArray){
	var arr = [];
	for(var k in likeArray){
		arr.push(likeArray[k]);
	}
	return arr;
}


function $id(el){
	if($type(el)=='element') return el;
	return document.getElementById(el);
}

function $html(el,html){
	if(!html) return $id(el).innerHTML;
	$id(el).innerHTML = html; 
}
function $val(el){
	return $id(el).value;
}

function $each(iterable, fn, bind){
	if (iterable && typeof iterable.length == 'number' && $type(iterable) != 'object'){
		for(var i = 0; i < iterable.length; i++){
			fn.call(bind || iterable, iterable[i], i, iterable);
		}
	} else {
		 for (var name in iterable) fn.call(bind || iterable, iterable[name], name, iterable);
	}
}

function $timer(func, time, args, bind){
	if(arguments.length == 1){
		clearTimeout(func);
		return;
	}
	if($type(args) != 'array'){
		 bind = args;
		 args = [];
	}
	return setTimeout(function(){func.apply(bind || func, args||[])}, time);
}

function $interval(func, time, args, bind){
	if(arguments.length == 1){
		clearInterval(func);
		return;
	}
	if($type(args) != 'array'){
		bind = args;
		args = [];
	}
	return setInterval(function(){func.apply(bind || func, args || [])}, time);
}

 fw.Loader = new Class({
	initialize:function(){},
		
	library: function(library, args){
			if(app.libraries[library]){
				 this._loadClass(library, app.libraries[library], args);
			}else{
				this._loadClass(library, fw.libraries[library], args);
			}
		},

		helper:function(helper){
			if(!this._helpers) this._helpers = {};
			if(app.helpers[helper]){
				helper = app.helpers[helper];
			}else{
				helper = fw.helpers[helper];
			}
			this._loadHelper(helper);
		},

		view: function(view, data, outputInContainer){
			return this._loadView(app.views[view], data, outputInContainer);
		},

		model: function(model){
			var fwi = fw.getInstance();
			fwi[model] = new app.models[model]();
			fwi[model]._assignLibraries();
		},

		_loadClass: function(keyword, className, args){
			var fwi =  fw.getInstance();
			fwi[keyword] = new className(args); 
		},

		_loadView: function(view, data, outputInContainer){
			data = data || {};
			if(this._helpers) data._MODIFIERS = this._helpers;		
			return view.process(data, outputInContainer);
		},

		_loadHelper: function(helper){
			for(func in helper){
				window[func] = helper[func];
				this._helpers[func] = helper[func];
			}
		}
});


fw.Base = fw.Loader.extend({
	initialize:function(){
		this.load = this;
		fw.globals.obj = {};
		for(prop in this.load){
			fw.globals.obj[prop] = this.load[prop];
		} 
	}
		
});


fw.Controller = fw.Base.extend({
	initialize:function(loader){
		this.parent();
		this.flashMessage = '';
		this.returnValue = false;
	},
	
	flash:function(message, clearTime){
			try{
				if($id('flashDiv')){
					$id('flashDiv').innerHTML = message;
				}
				if(clearTime){
					setTimeout(function(){$id('flashDiv').innerHTML = '';}, clearTime);
				}
			}catch(e){}
		},
		
	result:function(){
		return this.returnValue;
	},
	
	run:function(action,post,addToHistory){
		var router = new fw.Router();
		router.setAction(action);
		var controller = new app.controllers[router.getClass()]();
		controller.post = post || {};
		controller[router.getMethod()].apply(controller, router.getParams());
	}
});

fw.loadViewsFromDiv = function(div){
	var views = $id(div).childNodes;
	var container ='';
	for(var i=0;i<views.length;i++){
		child = views[i];
		if(child.tagName && child.tagName.toLowerCase()=='textarea' && child.getAttribute('isTemplate')!='false'){
			container = '';
			if(child.getAttribute('container')) container = child.getAttribute('container');
			app.views[child.id] = new fw.View(child.id, {'container':container});
		}
	}
}


 fw.View = new Class({
		initialize: function(options){
			if($type(options)=='string') this.parseDomTemplate(options);
			else if(options['type']=='string') this.parseStringTemplate(options['string']);
			else if(options['url']) this.handleUrlTemplate(options['url'], options);
			this.handleOptions(options);
		},
		
		handleOptions:function(options){
			if(options['container']) this.container = options['container']; 
		},
		
		parseDomTemplate:function(id){
			this.template = TrimPath.parseDOMTemplate(id);
		},

		parseStringTemplate:function(string){
			this.template = TrimPath.parseTemplate(string);
		},
		
		process: function(data, outputInContainer){
			result = this.template.process(data);
			if(!outputInContainer){
			 	return result;
			}else{
				container = $id(this.container);
				container.innerHTML = result;
			}
		}
	});
	
	
	 fw.fc = new Class({
		initialize:function(){
			this.hooks = new fw.Hooks();
		},
		run:function(action, post){
					this.hooks.runHook('preSystem');
			//load config
				this.router = new fw.Router();

					this.hooks.runHook('preController');


					this.router.setAction(action);
					this.className = this.router.getClass();
					this.method = this.router.getMethod();

					
			
					fw.globals['fw'] = new app.controllers[this.className]();
					fw.globals['fw'].post = post;


					this.hooks.runHook('postControllerConstructor');


					if(fw.globals['fw'].preAction) fw.globals['fw'].preAction();
					fw.globals.fw[this.method].apply(fw.globals.fw, this.router.getParams());


					if(fw.globals['fw'].postAction) fw.globals['fw'].postAction();

					this.hooks.runHook('postController');

					result =fw.globals['fw'].result();

					delete(fw.globals['fw']);
		//			//delete router, config ,e tc

					this.hooks.runHook('postSystem');
					return result;
		}
	});
	
	fw.Router = new Class({
		initialize: function(){
			this.controllersPath = app.controllers;
		},
		setAction: function(action){
			this.action = action;
			this.parseAction();
		},
		getClass:function(){
			return this.className;
		},
		getMethod: function(){
			return this.method;
		},
		getParams: function(){
			return this.params;
		},
		parseAction:function(){
			parts = this.action.split('/');
			this.className = parts[0];
			this.method = parts[1];
			if(parts.length>2){
				this.params = parts.slice(2);
			}else{
				this.params = [];
			}
		}
	});
	
	 fw.Hooks = new Class({
		initialize:function(){
			this.runHook('onLoad');
			this.hooks = app.hooks;
		},
		runHook:function(which){
			try{
				this.hooks[which]();
			}catch(e){}
		}
	});
	
	
	fw.flash = function(message, clearTime){
		try{
			if($id('flashDiv')){
				$id('flashDiv').innerHTML = message;
			}
			if(clearTime){
				setTimeout(function(){$id('flashDiv').innerHTML = '';}, clearTime);
			}
		}catch(e){}
	}

	fw.getInstance = function(){
		if($type(fw.globals.fw)=='object') return fw.globals.fw;
		return fw.globals.obj.load;
	}  

	
	fw.loadClass = function(className, obj){
		obj = obj ? obj : fw;
		if(!fw.globals[className])  fw.globals[className] = new obj[className]();
		return fw.globals[className];
	}
	

	fw.Model = new Class({
		initialize:function(){				
		},
		
		_assignLibraries:function(){
			fwi = fw.getInstance();
			for(prop in fwi){
				this[prop] = fwi[prop];
			}
		}
	});
	
	
	function run(action, post, addToHistory){
		post = post || {};
		addToHistory = addToHistory || false;
		log('run('+action+', '+post.toString()+', '+addToHistory.toString()+')');

		if(!addToHistory){
			if(!($.browser.safari && $.browser.version < 500))	 dhtmlHistory.add(action, post||{});
			setTimeout(function(){ ignoreLocation = false; },600);
			ignoreLocation = true;
		}
		
		
		var fc = new fw.fc();
 		fc.run(action,post||{});

	}  

function logLocations(){
		log('getCurrentLocation = '+dhtmlHistory.getCurrentLocation());
		log('dhtmlHistory.currentLocation = '+dhtmlHistory.currentLocation);
}
var logs = [];
function log(mes){
//	logs.push(mes);
//	showLog();
}
function clearLog(){
	logs = [];
	showLog();
}
function showLog(){
	$id('log').innerHTML = logs.join('<br />');
}
