/**
 * Inject file content in dom element
 * 
 * @author Angelo Selvini <angelo@exmachina.ch>
 * @requires ch.exmachina.bravofly.utils
 */


if(!ch){
	var ch = {};
}
if(!ch.exmachina){
	ch.exmachina = {};
}
if(!ch.exmachina.bravofly){
	ch.exmachina.bravofly = {};
}
if(!ch.exmachina.bravofly.ui){
	ch.exmachina.bravofly.ui = {};
}

ch.exmachina.bravofly.ui.Injector = function(/* object */ ctorArgs){
	var t;

	this.target = t = ctorArgs["target"];
	if (!t || !t.nodeType || t.nodeType != 1)
		throw new Error("Injector requires target");

	// defaults
	this.name      = t.getAttribute("bf:param") || ctorArgs["name"] || "injectorWidget"+parseInt(Math.random()*1000);
	this.listening  = false;
	this.isExpanded = false;
	this.isLoaded   = false;

	this.options   =
	{ expanded      : t.getAttribute("bf:expanded")  == "true" ? true : false
	, hideError     : t.getAttribute("bf:hideError") == "true" ? true : false
	, expanderClass : t.getAttribute("bf:expanderClass") || this.getConstants()["CLASS_EXPANDER"]
	, loaderClass   : t.getAttribute("bf:loaderClass")   || this.getConstants()["CLASS_LOADER"]
	, closerClass   : t.getAttribute("bf:closerClass")   || this.getConstants()["CLASS_CLOSER"]
	};

	this.dict =
	{ error:  t.getAttribute("bf:errorMessage") || "Load failed. <span class=\"vg_injRetry\">Click to retry</span>."
	};

	this.file   = t.getAttribute("bf:file")   || null;
	this.fields = t.getAttribute("bf:fields") || null;

	this.dom     = null;
	this.request = null;
};

ch.exmachina.bravofly.ui.Injector.prototype = {

	type: "ch.exmachina.bravofly.ui.Injector",

	_listening: false,

	dom    : null,
	file   : null,
	dict   : null,

	dLoader: null,
	dError : null,

	isExpanded: null,
	isLoaded  : null,

	fields: null,
	params : null,
	target : null,
	options: null,
	request: null,

	setOptions: function(/* object */ o){
		if (!o) return;

		var i = 0,
			c = this.options,
			l = [ { type:"s", name:"loaderClass"   }
				, { type:"s", name:"closerClass"   }
				, { type:"s", name:"expanderClass" }
				, { type:"b", name:"expanded"      }
				, { type:"b", name:"hideError"     }
				, { type:"s", name:"errorMessage"  }
				] // param not allowed to be changed
		;

		c = ch.exmachina.bravofly.utils.validateOptions(
				{ optsNew: o
				, optsOld: c
				, rules: l
				}
			);
	},

	setParams: function(/* object */ p){
		if (p.file)
			this.file = p.file;
		if (p.fields && typeof(p.fields)=="string")
			this.fields = p.fields;
	},

	// DOM
	create: function(){
		// summary: setup data retrivied
		var d,l,
			C = this.getConstants(),
			o = this.options
		;

		d = this.dom = $(document.createElement('div'));
		d.addClassName( C.CLASS_MAIN );
		
		l = this.dLoader = $(document.createElement('div'));
		l.addClassName( o.loaderClass || C.CLASS_LOADER );
	},

	draw: function(){
		// summary: evaluate template with parameters
		var d = this.dom,
			o = this.options,
			t = this.target
		;

		if (d)
			t.appendChild( d );

		if (o.expanded)
			this.expand();
	},

	expand: function(){
		var d = this.dom,
			t = this.target,
			l = this.dLoader,
			e = this.isExpanded
		;
		if (e) {
			this.reduce();
			return;
		}

		t.addClassName(this.getConstants()["CLASS_EXPANDED"]);

		e = this.isExpanded = true;
		d.setStyle({display:""});

		if (!this.isLoaded)
			this.load();
	},

	reduce: function(){
		var c,
			d = this.dom,
			t = this.target,
			e = this.isExpanded
		;

		if (!e) return;

		c = this.getConstants()["CLASS_EXPANDED"];

		if (t.hasClassName(c))
			t.removeClassName(c);

		d.setStyle({display:"none"});

		e = this.isExpanded = false;
	},

	_loaderActive: function(/* boolean */ b){
		var l = this.dLoader,
			d = this.dom
		;
		if (b){
			if (!this.hasParentNode(l))
				d.appendChild(l);
		} else {
			if (this.hasParentNode(l))
				l.parentNode.removeChild(l);
		}
	},

	load: function(){
		// summary: make ajax request to load file content
		if (this.isLoaded) return;

		var ao,
			ar = this.request,
			u  = this.normalizeUrl( this.file )
		;

		ao =
		{ onSuccess: this.delegate(this, this._loadSuccess)
		, onFailure: this.delegate(this, this._loadFailed)
		};

		if (!ar)
			ar = new Ajax.Request(u, ao);

		this._loaderActive(true);
	},

	_loadSuccess: function(e){
		// summary: create innerHTML
		this.isLoaded = true;

		this._loaderActive(false);
		var r,
			C = this.getConstants(),
			d = this.dom,
			txt = e.responseText
		;

		r = $(document.createElement("div"));
		r.addClassName(C.CLASS_CONTENT);
		r.innerHTML = txt;

		this._analyzeContent(r);

		d.appendChild(r);

		this._analyzeWidgets(r);
	},

	_loadFailed: function(e){
		this._loaderActive(false);
		if (!this.options.hideError)
			this._showError()
	},

	_analyzeContent: function(/* dom */ d){
		// Find known buttons
		var cb,i,
			o = this.options,
			C = this.getConstants()
		;

		cb = d.select("."+o.closerClass);
		for (i=0;i<cb.length;i++){
			cb[i].observe("click", this.delegate(this, this.reduce) );
			cb[i].setStyle(C.STYLE_PNT);
		}

	},

	_analyzeWidgets: function(/* dom */ d){
		//	summary: initialize widgets
		var w;

		if (!d) return;

		if (com && com.bravofly && com.bravofly.app && com.bravofly.app.Widgets){
			w = com.bravofly.app.Widgets;

			// prevent inserting injectors for recursive loops
			var i,
				a = $(d).select("*[bf:type=\"Injector\"]")
				for (i=0;i<a.length;i++){
					a[i].setAttribute("bf:type","ignore");
				}
			;

			w.update(d,{fields:this.fields});
		}

	},


	_showError: function(){
		var e,r,
			l = this.dLoader,
			d = this.dom,
			t = this.target,
			C = this.getConstants()
		;

		this.reduce();

		if (this.dError) return;

		e = $(document.createElement("div"));
		e.addClassName("vg_error");
		e.innerHTML = this.dict.error;

		r = $(e).select("."+C.CLASS_RETRY)[0];
		if (r){
			r.setStyle(C.STYLE_PNT);
			r.observe("click", this.delegate(this, this._retry) );
		}

		t.appendChild(e);

		this.dError = e;
	},

	_retry: function(){
		var d = this.dom,
			e = $(this.dError)
		;

		e.stopObserving("click");
		e.setStyle({cursor:"default"});
		e.parentNode.removeChild(e);

		e = this.dError = null;

		this.expand();
	},

	update: function(){
	},

	setListening: function(/* boolean */ b){
		if (b && !this._listening)
			this._addListeners();
		else if (!b)
			this._removeListeners();
	},

	_addListeners: function(){
		this._listening = true;

		var i,
			t = this.target,
			o = this.options
		;

		this._buttonActivate(true);
	},
	_removeListeners: function(){
		this._listening = false;
		this._buttonActivate(false);
	},

	_buttonActivate: function(/* boolean */ b){
			
		var c = this.options.expanderClass,
			v = /^\./.test(c) ? c : "."+c, // Validate classname
			a = $(this.target).select(v),
			C = this.getConstants()
		;

		for (i=0;i<a.length;i++){
			if (b){
				a[i].observe("click", this.delegate(this, this.expand));
				a[i].setStyle(C.STYLE_PNT);
			} else {
				a[i].stopObserving("click");
				a[i].setStyle(C.STYLE_DFL);
			}
		}
	},

	getParamName: function(){
		var s = null,
			o = this.options
		;
		if (o && o.param)
			s = o.param;

		return s;
	},

	getNode: function(){
		// return: dom
		return this.dom;
	},

	getName: function(){
		return this.name;
	},

	getType: function(){
		return this.type;
	},

	destroy: function(){
		this.setListening(false);
	},
	getConstants: function(){
		return window.ch.exmachina.bravofly.ui.Injector.getConstants();
	},

	hasParentNode: ch.exmachina.bravofly.utils.hasParentNode,
	normalizeUrl: ch.exmachina.bravofly.utils.normalizeUrl,
	delegate: ch.exmachina.bravofly.utils.delegate
};

ch.exmachina.bravofly.ui.Injector.getConstants = function() {
	var cnst =
	{ CLASS_MAIN    :"vg_inj"
	, CLASS_RETRY   :"vg_injRetry"
	, CLASS_CLOSER  :"vg_injClose"
	, CLASS_LOADER  :"vg_injLoaderImage"
	, CLASS_CONTENT :"vg_injContent"
	, CLASS_EXPANDED:"vg_ingExpanded"
	, CLASS_EXPANDER:"vg_injExpandable"
	, STYLE_VI :{display:""}
	, STYLE_HD :{display:"none"}
	, STYLE_PNT:{cursor:"pointer"}
	, STYLE_DFL:{cursor:"default"}
	};
	return cnst;
};

