var Nova = {
    version: '0.1',
    page_loaded: false,
    realdomain: document.domain,
    options: {
        debug: false,
			/*
        search_level: 3,
        query_interval: 2000,
        guard_retryinterval: 5000,
        guard_maxwait: 12000
		*/
        search_level: 1,
        query_interval: 0,
        guard_retryinterval: 0,
        guard_maxwait: 0

    }
};

/**
 * Check if cross domain
 * 
 * @param url string
 * @return bool
 */
function nova_domain(url) {
    return url.indexOf('://'+Nova.realdomain) != url.indexOf('://');
}

/**
 * Call ajax function
 * 
 * @param url string
 * @param param array
 * @param callback function
 * @param id string optional
 * @return int
 */
function nova_call(url, param, callback, id) {
    id = id === undefined ? Math.floor(Math.random()*1000000) : id;
    var req = new NovaCall(url, param, callback, id);
    return id;
}
/**
* 获取checkbox的value，将checkbox的value转化为 'value1,value2,value3' 的方式返回
* @todo: 改为采用Prototype方式
*/
function nova_checkbox(name){	
		var elementValue='';
		var samenameelements = document.getElementsByName(name);
		if(samenameelements){
			for(j=0;j<samenameelements.length;j++){
				if(samenameelements[j].checked){
					elementValue=elementValue+samenameelements[j].value+",";
				}
				////alert("elementName'value:"+elementValue);
			}
			if(elementValue!=','&&elementValue!=''){
				if(elementValue.charAt(elementValue.length-1)==','){
					elementValue = elementValue.substr(0,elementValue.length-1);
//					alert(name+"'s value:"+elementValue);
				}
			}				
		}
		return elementValue;
}

/**
 * Merge values of form elements into an object
 * 
 * @param form string
 */
function nova_form2object(form) {
    form = $(form);
    ret = {};
    var eles = form.getElementsByTagName('input');
    //added by liuz
    var procecced = new Array();    
	var eleValue;
    for (var i = 0; i < eles.length; i++) { 
		//alert(element);		
		elementType = eles[i].type.toUpperCase();
		if(elementType=="CHECKBOX"||elementType=="RADIO"){
			eleName = eles[i].name;
			var processdTag = 'false';
			for(f=0;f<procecced.length;f++){
				if(eleName==procecced[f]){
					processdTag = 'true';
					break;
				}
			}
			if(processdTag=='true'){//同名的元素已经处理过
				continue;
			}
			eleValue = nova_checkbox(eleName);
			procecced.push(eleName);
   		 }else{
   		 	eleValue = Form.Element.getValue(eles[i]);
   		 }
    	//added by liuz end
        ret[eles[i].name || eles[i].id] = eleValue; //modify by luz
    }
    eles = form.getElementsByTagName('textarea');
    for (var i = 0; i < eles.length; i++) {
        ret[eles[i].name || eles[i].id] = Form.Element.getValue(eles[i]);
    }
    eles = form.getElementsByTagName('select');
    for (var i = 0; i < eles.length; i++) {
        ret[eles[i].name || eles[i].id] = Form.Element.getValue(eles[i]);
    }
    return ret;
}

NovaCall = Class.create();
Object.extend(Object.extend(NovaCall.prototype, Ajax.Request.prototype), {
    initialize: function(url, param, callback, id) {
        param = param === undefined ? 'null' : JSON.stringify(param);
        var method = 'post';
        this.id = id;
        this.url = url; // + '?__ai=' + id;
        this.callback = callback;
        this.transport = Ajax.getTransport(url);
        this.setOptions({method: method, parameters: '__ap='+encodeURIComponent(param)});
        this.options.onComplete = this.recv.bind(this);
        this.request(this.url);
    },
    recv: function(trans, obj) {
        //var obj = eval('(' + aJSONtext + ')');
        //alert(obj);
        this.callback(obj, this.id);
    }
});

/**
 * Walk through nova elements with a callback func
 * 
 * @param func function
 * @param parentElement string
 */
function nova_apply(func, parentElement) {
    var children = ($(parentElement) || document.body).getElementsByTagName('*');
    var re = new RegExp("(^|\\s)nova_[^\\s]+(\\s|$)","");
    var ar;
    for (var i = 0; i < children.length; i++) {
        if (!children[i].className) continue;
        ar = re.exec(children[i].className);
        if (ar != null) func(Element.extend(children[i]), ar[0].replace(/^\s*|\s*$/g,""));
    }
}

/**
 * Event handler, cancel an event
 */
function nova_cancel(event) {
    Event.stop(event);
}

/**
 * Show an element
 */
function nova_show(id, effect) {
    Effect.Appear($(id));
}

/**
 * Hide an element
 */
function nova_hide(id, effect) {
    Effect.Fade($(id));
}

/**
 * Update an element with ajax call
 */
function nova_update(id, url, param, method) {
    //Element.update($(id), 'Loading');
	var loader = new NovaLoader(id, url, param, method);
	loader.start();
}

function nova_static_update(hid,id, url, param, method){

	nova_hide(hid,effect);
	nova_update(id, url, param, method);
}

/**
 * Update an element with ajax call and fade effect
 */
function nova_update_fade(id, url, param, method) {
	var loader = new NovaFadingLoader(id, url, param, method);
	loader.start();
}

/**
 * Apply event handlers to elements
 */
function nova_event_assign(id) {
    var code = '';
    var triggers = new Array();
    nova_apply( function(el, cl){
        switch (cl) {
            case 'nova_trigger':
                code += el.value;
                el.value = '';
                triggers.push(el);
                //Element.remove(el);
                break;
            case 'nova_uploadform':
                if (!el.id) el.id = 'uf' + Math.floor(Math.random()*1000000);
                nova_iframe(el.id+'_queryframe');
                nova_iframe(el.id+'_targetframe');
                var id = Form.getInputs(el, null, 'UPLOAD_IDENTIFIER');
                if (!id.length) {
                    id = document.createElement('input');
                    id.name = 'UPLOAD_IDENTIFIER';
                    id.type = 'hidden';
                    if (el.childNodes.length) el.insertBefore(id, el.childNodes[0]); else el.appendChild(id);
                }
                id = Form.getInputs(el, null, 'NOVA_RETURNTEMPLATE');
                if (!id.length) {
                    id = document.createElement('input');
                    id.name = 'NOVA_RETURNTEMPLATE';
                    id.type = 'hidden';
                    el.appendChild(id);
                }
                Event.observe(el, 'submit', nova_upload);
                break;
            case 'nova_form':
                Event.observe(el, 'submit', nova_cancel);
                break;
            default:
                if (rules_click[cl]) Event.observe(el, 'click', rules_click[cl]);
        }
    }, $(id));
    if (code!='') eval(code);
    for(var i=0;i<triggers.length;i++)Element.remove(triggers[i]);
}

/**
 * Clear event handlers of elements
 */
function nova_event_clear(id) {
    nova_apply( function(el, cl) {
        switch (cl) {
            case 'nova_trigger':
                Element.remove(el);
                break;
            case 'nova_form':
                Event.stopObserving(el, 'submit', nova_cancel);
                break;
            case 'nova_uploadform':
                Event.stopObserving(el, 'submit', nova_upload);
                break;
            default:
                if (rules_click[cl]) Event.stopObserving(el, 'click', rules_click[cl]);
        }
        if (rules_click[cl]) Event.stopObserving(el, 'click', rules_click[cl]);
    }, id);
}

/**
 * Find real nova raiser of a click event
 */
function nova_raiser(element) {
    var search_level = Nova.options.search_level; //increase this if u want a deeper throat!
    while (--search_level) {
        if (!element) return null;
        if (element.href) return element;
        element = element.parentNode;
    }
    return null;
}

var rules_click = {
    'nova_updater': function(event) {
        var element = Event.element(event);
        element = nova_raiser(element);
        if (!element) return; //error here.
        var id = element.id.split('_')[0];
        var url = element.href;
        nova_update(id, url);
        Event.stop(event);
    },
    'nova_updater_fade': function(event) {
        var element = Event.element(event);
        element = nova_raiser(element);
        if (!element) return; //error here.
        var id = element.id.split('_')[0];
        var url = element.href;
        nova_update_fade(id, url);
        Event.stop(event);
    },
    'nova_submit': function(event) {
        var element = Event.element(event);
        var id = element.id.split('_')[0];
        var form = $(element.id.split('_')[1]);
	upload = nova_findsubupload(form);
	if (upload) {
		Event.stop(event);
		nova_subupload(form, id, upload);
		return;
	}
        var url = form.action;
        nova_update(id, url, Form.serialize(form), 'post');
        Event.stop(event);
    },
    'nova_submit_fade': function(event) {
        var element = Event.element(event);
        id = element.id.split('_')[0];
        form = $(element.id.split('_')[1]);
        url = form.action;
        nova_update_fade(id, url, Form.serialize(form), 'post');
        Event.stop(event);
    }
}

function nova_findsubupload(form) {
	form = $(form);
	var upload = null;
	var eles = form.getElementsByTagName('input');
	for (var i=0; i<eles.length; i++) {
		if (eles[i].className == 'nova_uploadid') upload = eles[i];
	}
	return upload;
}

function nova_subupload(form, partid, upload) {
	form = $(form);
	upform = $(upload.id.split('_')[0]);
	r = Form.getInputs(upform, null, 'NOVA_RETURNTEMPLATE');
	r = r[0];
	r.value = '<script>window.parent.nova_uploaded({"form": "'+upform.id+'", "parent_form": "'+form.id+'", "parent_part": "'+partid+'"}, __CODE__, "__DATA__");</script>';
	upform.submit();
}

function nova_iframe(id) {
	var f = $(id);
	if (f) return f;
	f = document.createElement('iframe');
	f.name = id;
	if (navigator.appVersion.match(/\bMSIE\b/)) f = document.createElement('<iframe name="'+id+'"></iframe>');
	f.id = id;
	f.width="0";
	f.height="0";
	f.scrolling="no";
	f.frameborder="0";
	document.body.appendChild(f);
	return f;
}

function nova_reload(event) {
	var i = Event.element(event);
	if (!i) i = this;
	i.queryThread = setTimeout('window.frames["'+i.name+'"].document.location.reload();', Nova.options.query_interval);
	i.guardWait = 0;
}

function nova_reload_clear(id) {
	var i = $(id);
	Event.stopObserving(i, 'load', nova_reload);
	if (i.queryThread) clearTimeout(i.queryThread);
	if (i.guardThread) clearTimeout(i.guardThread);
	var d = window.frames[i.name];
	if (d) d = d.doucment;
	if (d) d.location = "about:blank";
	i.guardWait = 0;
}

function nova_upload_guard(id, url) {
	var i = $(id+'_queryframe');
	i.guardWait+=1000;
	if (i.guardWait<Nova.options.guard_maxwait) {
		if (i.guardWait % Nova.options.guard_retryinterval == 0) i.queryThread = setTimeout('window.open("'+url+'", "'+id+'_queryframe");', 0);
		i.guardThread = setTimeout('nova_upload_guard("'+id+'", "'+url+'");', 1000);
	} else if (i.guardWait==Nova.options.guard_maxwait) {
		if (nova_upload_hook(id, -2, '')) nova_reload_clear(id+'_queryframe');
	}
}

function nova_upload(event) {
	var id = 'u'+Math.floor(Math.random()*1000000)+'.'+Math.floor(Math.random()*1000000);
	var form = Event.element(event);
	var files = Form.getInputs(form, 'file');
	var upid = Form.getInputs(form, null, 'UPLOAD_IDENTIFIER')[0];
	var tmpl = Form.getInputs(form, null, 'NOVA_RETURNTEMPLATE')[0];
	var url = form.action;
	var empty = true;
	var qframe = $(form.id+'_queryframe');
	var code_callback = 'window.parent.nova_uploaded({"form": "'+form.id+'"}, __CODE__, "__DATA__");';
	var code_stop = 'window.parent.nova_reload_clear("'+qframe.id+'");';
	var re = new RegExp("[^\.]+\.[^\.]+$","");
	var ar = re.exec(document.domain);
	if (ar) {
		try {
			document.domain = ar[0];
		} catch (err) {
		}
	}
	var code_domain = 'document.domain="'+document.domain+'";';
	for (var i=0; i<files.length; i++) {
		if (files[i].value) empty = false;
	}
	if (empty) {
		alert('Please select at least one file');
		Event.stop(event);
		return;
	}
	form.target = form.id+'_targetframe';
	upid.value = id;
	tmpl.value = '<script>' + code_domain + code_stop + code_callback + '</script>';
	url += (url.indexOf('?')==-1 ? '?' : '&') + 'NOVA_QUERYUPLOAD=' + id + '&NOVA_RETURNTEMPLATE=' + encodeURIComponent('<script>' + code_domain + code_callback + '</script>');
	if (Nova.options.debug) {
		url += '&NOVA_UPLOADDEBUG=dummy';
		qframe.width = '40%';
		qframe.height = '300';
		qframe.width = '40%';
		qframe.height = '300';
	}
	setTimeout('if (window.nova_upload_hook) window.nova_upload_hook({"form":"'+form.id+'"}, 1, 0);', 0);
	Event.observe(qframe, 'load', nova_reload);
	qframe.queryThread = setTimeout('window.open("'+url+'", "'+qframe.id+'");', 1);
	qframe.guardThread = setTimeout('nova_upload_guard("'+form.id+'", "'+url+'");', 1000);
	qframe.guardWait = 0;
}

function nova_uploaded(param, code, data) {
	if (window.nova_upload_hook) window.nova_upload_hook(param, code, data);
	switch (code) {
		case -1://error
			break;
		case 0://done
			if (param.parent_form) {
				var form = $(param.parent_form);
				upload = nova_findsubupload(form);
				upload.value = data;
				nova_update(param.parent_part, form.action, Form.serialize(form), 'post');
			}
			break;
		case 1://starting
		case 2://progress
		case 3://encoding
		default:
			break;
	}
}

NovaLoader = Class.create();
Object.extend(Object.extend(NovaLoader.prototype, Ajax.Request.prototype), {
    initialize: function(id, url, param, method) {
        param = param === undefined ? '' : param;
        method = method === undefined ? 'get' : method;
        this.id = id;
        this.url = url + ((url.indexOf('?')==-1) ? '?' : '&') + '__rt=1&__ro='+id;
        this.transport = Ajax.getTransport(url);
        this.setOptions({method: method, parameters: param});
        this.options.onComplete = this.recv.bind(this);
    },
    start: function() {
        this.send();
    },
    send: function() {
        this.request(this.url);
    },
    recv: function(req, obj) {
        this.update();
        this.end();
    },
    update: function() {
        nova_event_clear($(this.id));
        Element.update($(this.id), this.transport.responseText);
        nova_event_assign($(this.id));
    },
    end: function() {
        //this.transport = null;
        try {
            delete this;
        } catch (err) {
        }
    }
});

NovaFadingLoader = Class.create();
Object.extend(Object.extend(NovaFadingLoader.prototype, NovaLoader.prototype), {
    start: function(){
        this.fader = new nova_fadeout(this.id, {afterFinish:this.hided.bind(this)});
    },
    hided: function(effect){
        try {
            delete this.fader;
        } catch (err) {
        }
        Element.addClassName($(this.id+'_wrap'), 'nova_loading');
        this.send();
    },
    recv: function(request, object){
        this.update();
        this.fader = new nova_fadein(this.id, {afterFinish:this.showed.bind(this)});
        Element.removeClassName($(this.id+'_wrap'), 'nova_loading');
    },
    showed: function(effect){
        try {
            delete this.fader;
        } catch (err) {
        }
        this.end();
    }
});

/**
 * Hide an element, with fade effect
 */
nova_fadeout = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
  duration: 0.4,
  from: element.getOpacity() || 1.0,
  to:   0.1,
  afterFinishInternal: function(effect) {
    if(effect.options.to!=0) return;
    //effect.element.hide();
    //effect.element.setStyle({opacity: oldOpacity});
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

/**
 * Show an element, with fade effect
 */
nova_fadein = function(element) {
  element = $(element);
  var options = Object.extend({
  duration: 0.4,
  from: (element.getStyle('display') == 'none' ? 0.1 : element.getOpacity() || 0.1),
  to:   1.0,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from);
    effect.element.show();
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

// Array of DOMContentLoaded event handlers.
window.onDOMLoadEvents = new Array();
window.DOMContentLoadedInitDone = false;

// Function that adds DOMContentLoaded listeners to the array.
function addDOMLoadEvent(listener) {
	window.onDOMLoadEvents[window.onDOMLoadEvents.length]=listener;
}

// Function to process the DOMContentLoaded events array.
function DOMContentLoadedInit() {
	// quit if this function has already been called
	if (window.DOMContentLoadedInitDone) return;

	// flag this function so we don't do the same thing twice
	window.DOMContentLoadedInitDone = true;

	// iterates through array of registered functions 
	for (var i=0; i<window.onDOMLoadEvents.length; i++) {
		var func = window.onDOMLoadEvents[i];
		func();
	}

	window.onDOMLoadEvents = new Array();
}

function DOMContentLoadedScheduler() {
	// quit if the init function has already been called
	if (window.DOMContentLoadedInitDone) return true;
	
	//if DOM methods are supported, and the body element exists
	//(using a double-check including document.body, for the benefit of older moz builds [eg ns7.1] 
	//in which getElementsByTagName('body')[0] is undefined, unless this script is in the body section)
	if(typeof document.getElementsByTagName != 'undefined' && (document.getElementsByTagName('body')[0] != null || document.body != null)) {
		DOMContentLoadedInit();
	} else {
		// Not ready yet, wait a little more.
		setTimeout("DOMContentLoadedScheduler()", 200);
	}
	
	return true;
}

// If Mozilla, use the built in DOMContentLoaded event.
if(document.addEventListener && !window.opera && !(!document.all && document.childNodes && !navigator.taintEnabled)) {
	document.addEventListener("DOMContentLoaded", DOMContentLoadedInit, false);
} else if (!navigator.appVersion.match(/\bMSIE\b/)) {
	// Schedule to run the init function.
	setTimeout("DOMContentLoadedScheduler()", 200);
	// Just in case window.onload happens first, add it there too.
	Event.observe(window, 'load', DOMContentLoadedInit);
}

/**
 * Initialize nova framework
 */
function nova_init() {
    if (Nova.page_loaded) return;
    Nova.page_loaded = true;
    nova_event_assign(document.body);
    loadiv = $('nova_loading');
    if (loadiv) Element.hide(loadiv);
    if (window.nova_init_hook) window.nova_init_hook();
}

addDOMLoadEvent(nova_init);
/*@cc_on @*/
/*@if (@_win32)
	//document.write('<script defer type="text/javascript" src="/js/novainit_ie.js"></script>');
/*@end @*/
