var JSON = function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            'boolean': function (x) {
                return String(x);
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            },
            object: function (x) {
                if (x) {
                    var a = [], b, f, i, l, v;
                    if (x instanceof Array) {
                        a[0] = '[';
                        l = x.length;
                        for (i = 0; i < l; i += 1) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a[a.length] = v;
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = ']';
                    } else if (x instanceof Object) {
                        a[0] = '{';
                        for (i in x) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a.push(s.string(i), ':', v);
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = '}';
                    } else {
                        return;
                    }
                    return a.join('');
                }
                return 'null';
            }
        };
    return {
        stringify: function (v) {
            var f = s[typeof v];
            if (f) {
                v = f(v);
                if (typeof v == 'string') {
                    return v;
                }
            }
            return null;
        },
        parse: function (text) {
            try {
                return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                        text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
                    eval('(' + text + ')');
            } catch (e) {
                return false;
            }
        }
    };
}();

if (!window.NovaOptions) window.NovaOptions={};
if (!window.Nova) window.Nova={};
Nova.initializing = true;
Nova.version = '$Rev: 907 $';
Nova.page_loaded = false;
Nova.realdomain = document.domain;
Nova.optionDefault = function(n, v) {if (NovaOptions[n]===undefined) NovaOptions[n]=v;};
Nova.log = window.__LOG__ || function () {};
Nova.optionDefault('debug', window.__LOG__ ? true : false);
Nova.optionDefault('search_level', 3);




/**
 * 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) {
	$(id).style.display = 'block';
    //Effect.Appear($(id));
}

/**
 * Hide an element
 */
function nova_hide(id, effect) {
	$(id).style.display = 'none';
    //Effect.Fade($(id));
}


/**
 * Apply event handlers to elements
 */
function nova_event_assign(id) {
    var code = [];
    var triggers = [];
    var sandboxes = [];
    nova_apply( function(el, cl){
        switch (cl) {
            case 'nova_trigger':
                code.push(el.value);
                el.value = '';
                triggers.push(el);
                break;
            case 'nova_form':
                Event.observe(el, 'submit', nova_cancel);
                break;
            case 'nova_sandbox':
                sandboxes.push(el);
                break;
            default:
                if (rules_click[cl]) Event.observe(el, 'click', rules_click[cl]);
        }
    }, $(id));
    for(var i=0;i<code.length;i++) {
        try {
            eval(code[i]);
        } catch(e) {
        }
    }
    if (!Nova.page_loaded) Nova.initriggers = code;
    for(var i=0;i<triggers.length;i++) {
        try {
            Element.remove(triggers[i]);
        } catch(e) {
        }
    }
    for(var i=0;i<sandboxes.length;i++) {
        if (!sandboxes[i].childNodes.length) continue;
        var s = sandboxes[i].childNodes[0].value;
        Element.remove(sandboxes[i].childNodes[0]);
        Nova.runSandbox(sandboxes[i], s);
    }
}










Nova.clone = function (what) {
    for (i in what) {
        if (typeof what[i] == 'object') {
            this[i] = new Nova.clone(what[i]);
        }
        else
            this[i] = what[i];
    }
}

Nova.uid = function (prefix) {
  if (!prefix) prefix='';
  var r = Math.floor( (Math.random() % 1) * Math.pow(2, 32) );
  var s = r.toString(16);
  while (s.length < 8) {
    s = "0" + s;
  }
  var now = new Date();
  s = now.valueOf().toString(16) + s;
  return prefix + s.substr(s.length - 16 + prefix.length, 16 - prefix.length);
}




NovaLoader = Class.create();
Object.extend(Object.extend(NovaLoader.prototype, Ajax.Request.prototype), {
    initialize: function(id, url, param, method, history) {
        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);
        this.options.onFailure = this.error.bind(this);
        this.options.fixHistory = (!NovaOptions.compatibleMode) && (history || false);
    },
    start: function() {
        this.send();
    },
    send: function() {
        Nova.Indicator.show();
        if (this.options.fixHistory) Nova.History.beforeSend(this.id);
        this.request(this.url);
    },
    recv: function(req, obj) {
        this.update();
        this.end();
    },
    error: function() {
        Nova.Indicator.hide();
        if (window.nova_error_hook) window.nova_error_hook(); 
        else Nova.log('Error in transport.');
    },
    update: function() {
        if (this.options.fixHistory) Nova.History.beforeUpdate(this.id, this.transport.responseText);
        nova_element_update(this.id, this.transport.responseText);
        Nova.Indicator.hide();
    },
    end: function() {
        //this.transport = null;
        try {
            delete this;
        } catch (err) {
        }
    }
});




/**
 * Show an element, with fade effect


function nova_init_hook_internal () {
    var loadiv = $('nova_loading');
    if (loadiv) Element.hide(loadiv);
}

/**
 * Initialize nova framework
 */
function nova_init() {
    Nova.log('Novajax browser engine initialized. ' + Nova.version);
    nova_event_assign(document.body);
    Nova.page_loaded = true;
    Nova.callHooks('init');
    //setTimeout(Nova.callHooks, 1000);
    //Event.observe(document.body, 'onload', Nova.callHooks);
    Nova.History.init();
    Nova.Indicator.init();
}

Nova.callHooks = function (hookname, args) {
    var s = 'nova_'+hookname+'_hook';
    for (var h in window) {
        if (h.indexOf(s)!=0) continue;
        try {
            var func = window[h];
            if (hookname=='init') window[h] = undefined;
            if (func) func(args);
        } catch (err) {
            Nova.log("Error in "+h+": "+err.description);
        }
    }
}

Nova.initCallbacks = [];

Nova.addInitFunc = function (listener) {
  if (!Nova.initializing) listener();
  else Nova.initCallbacks[Nova.initCallbacks.length]=listener;
}

Nova.processInit = function () {
  if (!Nova.initializing) return;
  Nova.initializing = false;
  for (var i=0; i<Nova.initCallbacks.length; i++) {
    var func = Nova.initCallbacks[i];
    func();
  }
  Nova.initCallbacks = [];
}

Nova.scheduleInit = function () {
  if (!Nova.initializing) return true;
  if(typeof document.getElementsByTagName != 'undefined' && (document.getElementsByTagName('body')[0] != null || document.body != null)) {
    Nova.processInit();
  } else {
    setTimeout("Nova.scheduleInit()", 200);
  }
  return true;
}
Nova.addInitFunc(nova_init);

Nova.runSandbox = (function () {
var element_stack = [];
var input_stack = [];
var timer = null;
var ua = navigator.userAgent.toLowerCase();
var isIE = (ua.indexOf('msie') >= 0 && ua.indexOf('opera') < 0);
var old_document_write = document.write;
var old_document_writeln = document.writeln;
 
var callback = function () {
    if (element_stack.length == 0) {
        clearInterval(timer);
        timer = null;
        document.write = old_document_write;
        document.writeln = old_document_writeln;
        return;
    }
    var index = element_stack.length - 1;
    var input = input_stack[index];
    if (input.length == 0) {
        var element = element_stack.pop();
        //element.innerHTML = ''; //FIXME
        element.innerHTML = element.hiddenHTML;
        input_stack.pop();
        return;
    }
    var item = input[input.length - 1];
    if (typeof item == 'string') {
        element_stack[index].hiddenHTML += item;
        //element_stack[index].innerHTML = element_stack[index].hiddenHTML; //FIXME
        input.pop();
    } else if (typeof item == 'object') {
        if (item.src) {
            input[input.length - 1] = {};
            var script = document.createElement('script');
            script.src = item.src;
            script.__index = index;
            if (isIE) {
                script.onreadystatechange = script_loaded;
            } else {
                script.onload = script_loaded;
            }
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
        }
        if (item.text) {
            var script = document.createElement('script');
            script.text = item.text;
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
            input.pop();
        }
    } else {
        input.pop();
    }
}
 
var script_loaded = function () {
    if (isIE && this.readyState.toLowerCase() != "loaded" && this.readyState.toLowerCase() != "complete") {
        return;
    }
    var index = this.__index;
    input_stack[index].pop();
}
 
var new_document_write = function() {
    for (var i = 0; i < arguments.length; i++) {
        element_stack[element_stack.length - 1].hiddenHTML += arguments[i];
        //element_stack[element_stack.length - 1].innerHTML = element_stack[element_stack.length - 1].hiddenHTML; //FIXME
    }
}
 
var new_document_writeln = function () {
    for (var i = 0; i < arguments.length; i++) {
        new_document_write(arguments[i] + "\n");
    }
}
 
return function (element, htmlCode) {
    element.innerHTML = '';
    element.hiddenHTML = '';
    element_stack.push(element);
    var input = [];
    while (true) {
        if ((m = htmlCode.match(/<script([^>]*>)((.|\r|\n)*?)<\/script>/i)) == null) {
            break;
        }
        input.unshift(htmlCode.substr(0, m.index));
        htmlCode = htmlCode.substr(m.index + m[0].length);
        if ((m2 = m[1].match(/src\s*=\s*(['"]?)([^'">\s]*)\1/i)) != null) {
            input.unshift({src:m2[2]});
        } else {
            input.unshift({text:m[2]});
        }
    }
    input.unshift(htmlCode);
    input_stack.push(input);
    if (timer == null) {
        document.write = new_document_write;
        document.writeln = new_document_writeln;
        timer = setInterval(callback, 10);
    }
}})();



Nova.onDOMContentLoaded = function(onready){
    var Browser = {
        IE           :  !!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1),
        Opera        :  navigator.userAgent.indexOf('Opera') > -1,
        WebKit       :  navigator.userAgent.indexOf('AppleWebKit/') > -1,
        Gecko        :  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') === -1,
        MobileSafari :  !!navigator.userAgent.match(/Apple.*Mobile.*Safari/),
        Version      :  parseFloat(navigator.appVersion)
    }
    var isReady = false;
    function doReady(){
        if( isReady ) return;
        //确保onready只执行一次
        isReady = true;
        onready();
    }
    /*IE*/
    if( Browser.IE ){
        (function(){
            if ( isReady ) return;
            try {
                document.documentElement.doScroll("left");
            } catch( error ) {
                setTimeout( arguments.callee, 0 );
                return;
            }
            doReady();
        })();
        window.attachEvent('onload',doReady);
    }
    /*Webkit*/
    else if (Browser.WebKit && Browser.Version < 525){
        (function(){
            if( isReady ) return;
            if (/loaded|complete/.test(document.readyState))
                doReady();
            else
                setTimeout( arguments.callee, 0 );
        })();
        window.addEventListener('load',doReady,false);
    }
    /*FF Opera 高版webkit Other*/
    else{
        document.addEventListener( "DOMContentLoaded", function(){
            document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
            doReady();
        }, false );
        window.addEventListener('load',doReady,false);
    }
}
Nova.onDOMContentLoaded(Nova.scheduleInit);



