/*
uuid.js - Version 0.3
JavaScript Class to create a UUID like identifier
 
Copyright (C) 2006-2008, Erik Giberti (AF-Design), All rights reserved.
 
This program is free software; you can redistribute it and/or modify it under 
the terms of the GNU General Public License as published by the Free Software 
Foundation; either version 2 of the License, or (at your option) any later 
version.
 
This program is distributed in the hope that it will be useful, but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License along with 
this program; if not, write to the Free Software Foundation, Inc., 59 Temple 
Place, Suite 330, Boston, MA 02111-1307 USA
 
The latest version of this file can be downloaded from
http://www.af-design.com/resources/javascript_uuid.php
 
HISTORY:
6/5/06 	- Initial Release
5/22/08 - Updated code to run faster, removed randrange(min,max) in favor of
          a simpler rand(max) function. Reduced overhead by using getTime() 
          method of date class (suggestion by James Hall).
9/5/08	- Fixed a bug with rand(max) and additional efficiencies pointed out 
	  by Robert Kieffer http://broofa.com/
 
KNOWN ISSUES:
- Still no way to get MAC address in JavaScript
- Research into other versions of UUID show promising possibilities 
  (more research needed)
- Documentation needs improvement
 
*/
 
// On creation of a UUID object, set it's initial value
function UUID(){
	this.id = this.createUUID();
}
 
// When asked what this Object is, lie and return it's value
UUID.prototype.valueOf = function(){ return this.id; };
UUID.prototype.toString = function(){ return this.id; };
 
//
// INSTANCE SPECIFIC METHODS
//
 
UUID.prototype.createUUID = function(){
	//
	// Loose interpretation of the specification DCE 1.1: Remote Procedure Call
	// described at http://www.opengroup.org/onlinepubs/009629399/apdxa.htm#tagtcjh_37
	// since JavaScript doesn't allow access to internal systems, the last 48 bits 
	// of the node section is made up using a series of random numbers (6 octets long).
	//  
	var dg = new Date(1582, 10, 15, 0, 0, 0, 0);
	var dc = new Date();
	var t = dc.getTime() - dg.getTime();
	var h = '-';
	var tl = UUID.getIntegerBits(t,0,31);
	var tm = UUID.getIntegerBits(t,32,47);
	var thv = UUID.getIntegerBits(t,48,59) + '1'; // version 1, security version is 2
	var csar = UUID.getIntegerBits(UUID.rand(4095),0,7);
	var csl = UUID.getIntegerBits(UUID.rand(4095),0,7);
 
	// since detection of anything about the machine/browser is far to buggy, 
	// include some more random numbers here
	// if NIC or an IP can be obtained reliably, that should be put in
	// here instead.
	var n = UUID.getIntegerBits(UUID.rand(8191),0,7) + 
			UUID.getIntegerBits(UUID.rand(8191),8,15) + 
			UUID.getIntegerBits(UUID.rand(8191),0,7) + 
			UUID.getIntegerBits(UUID.rand(8191),8,15) + 
			UUID.getIntegerBits(UUID.rand(8191),0,15); // this last number is two octets long
	return tl + h + tm + h + thv + h + csar + csl + h + n; 
};
 
 
//
// GENERAL METHODS (Not instance specific)
//
 
 
// Pull out only certain bits from a very large integer, used to get the time
// code information for the first part of a UUID. Will return zero's if there 
// aren't enough bits to shift where it needs to.
UUID.getIntegerBits = function(val,start,end){
	var base16 = UUID.returnBase(val,16);
	var quadArray = new Array();
	var quadString = '';
	var i = 0;
	for(i=0;i<base16.length;i++){
		quadArray.push(base16.substring(i,i+1));	
	}
	for(i=Math.floor(start/4);i<=Math.floor(end/4);i++){
		if(!quadArray[i] || quadArray[i] == '') quadString += '0';
		else quadString += quadArray[i];
	}
	return quadString;
};
 
// Replaced from the original function to leverage the built in methods in
// JavaScript. Thanks to Robert Kieffer for pointing this one out
UUID.returnBase = function(number, base){
	return (number).toString(base).toUpperCase();
};
 
// pick a random number within a range of numbers
// int b rand(int a); where 0 <= b <= a
UUID.rand = function(max){
	return Math.floor(Math.random() * (max + 1));
};

// end of UUID class file

/**
 * sprintf() for JavaScript v.0.4
 *
 * Copyright (c) 2007 Alexandru Marasteanu <http://alexei.417.ro/>
 * Thanks to David Baird (unit test and patch).
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */

function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return(o.join('')); }

function sprintf () {
  var i = 0, a, f = arguments[i++], o = [], m, p, c, x;
  while (f) {
    if (m = /^[^\x25]+/.exec(f)) o.push(m[0]);
    else if (m = /^\x25{2}/.exec(f)) o.push('%');
    else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
      if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) throw("Too few arguments.");
      if (/[^s]/.test(m[7]) && (typeof(a) != 'number'))
        throw("Expecting number but found " + typeof(a));
      switch (m[7]) {
        case 'b': a = a.toString(2); break;
        case 'c': a = String.fromCharCode(a); break;
        case 'd': a = parseInt(a); break;
        case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
        case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
        case 'o': a = a.toString(8); break;
        case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
        case 'u': a = Math.abs(a); break;
        case 'x': a = a.toString(16); break;
        case 'X': a = a.toString(16).toUpperCase(); break;
      }
      a = (/[def]/.test(m[7]) && m[2] && a > 0 ? '+' + a : a);
      c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
      x = m[5] - String(a).length;
      p = m[5] ? str_repeat(c, x) : '';
      o.push(m[4] ? a + p : p + a);
    }
    else throw ("Huh ?!");
    f = f.substring(m[0].length);
  }
  return o.join('');
}

// mootools implement
Element.implement({
    addClassOnOver: function(/* string */className) {
        var overFun = function(event, className) { if (!this.hasClass(className)) { this.addClass(className); } };
        var outFun = function(event, className) { this.removeClass(className); };
        this.addEvents({
            'mouseover': overFun.bindWithEvent(this, className),
            'mouseout': outFun.bindWithEvent(this, className)
        });

        return this;
    },
    getLayout: function() {
        var styles = this.getStyles('padding', 'margin', 'border-width');
        var padding = styles['padding'].split(' ');
        var margin = styles['margin'].split(' ');
        var border = styles['border-width'].split(' ');
        var layout = {
            'padding-top': padding[0].toInt(),
            'padding-right': padding.hasOwnProperty(1) ? padding[1].toInt() : padding[0].toInt(),
            'padding-bottom': padding.hasOwnProperty(2) ? padding[2].toInt() : padding[0].toInt(),
            'padding-left': padding.hasOwnProperty(3) ? padding[3].toInt() : padding[0].toInt(),
            'margin-top': margin[0].toInt(),
            'margin-right': margin.hasOwnProperty(1) ? margin[1].toInt() : margin[0].toInt(),
            'margin-bottom': margin.hasOwnProperty(2) ? margin[2].toInt() : margin[0].toInt(),
            'margin-left': margin.hasOwnProperty(3) ? margin[3].toInt() : margin[0].toInt(),
            'border-top': border[0].toInt(),
            'border-right': border.hasOwnProperty(1) ? border[1].toInt() : border[0].toInt(),
            'border-bottom': border.hasOwnProperty(2) ? border[2].toInt() : border[0].toInt(),
            'border-left': border.hasOwnProperty(3) ? border[3].toInt() : border[0].toInt()
        };

        layout.height = this.getHeight() - layout['border-top'] - layout['border-bottom'] - layout['padding-top'] - layout['padding-bottom'];
        layout.width = this.getWidth() - layout['border-left'] - layout['border-right'] - layout['padding-left'] - layout['padding-right'];

        layout.totalHeight = layout['margin-top'] + layout['margin-bottom'] + layout['border-top'] + layout['border-bottom']
                           + layout['height'] + layout['padding-top'] + layout['padding-bottom'];
        layout.totalWidth = layout['margin-left'] + layout['margin-right'] + layout['border-left'] + layout['border-right']
                          + layout['width'] + layout['padding-left'] + layout['padding-right'];

        return layout;
    },
    setDisplayed: function(/* boolean|string */value) {
        if ('boolean' == typeof value) {
            value = value ? '' : 'none';
        }
        this.setStyle('display', value);
        return this;
    },
    fitParent: function(/* boolean */resizeListener, /* number */min_height, /* number */min_width) {
        var parentNode = this.parentNode, allPrevious = this.getAllPrevious(), allNext = this.getAllNext();
        var other = allPrevious.extend(allNext), otherHeight = 0;
        for (var i = 0, len = other.length; i < len; i++) {
            var el = other[i], tagName = el.get('tag').toLowerCase();
            if ('script' == tagName || 'link' == tagName || 'style' == tagName) { continue; }
            if ('absolute' == el.getStyle('position')) { continue; }

            var elLayout = el.getLayout();
            otherHeight += elLayout.totalHeight;
        }

        if ('body' == $(parentNode).get('tag').toLowerCase()) {
            var bodySize = document.body.getSize();
            var parentHeight = bodySize.y;
            var parentWidth = bodySize.x;

            parentNode.setStyle('height', parentHeight);
        } else {
            var parentLayout = parentNode.getLayout();
            var parentHeight = parentLayout.height;
            var parentWidth = parentLayout.width;
        }
        var thisLayout = this.getLayout();
        var height = parentHeight - otherHeight, width = parentWidth - (thisLayout.totalWidth - thisLayout.width);

        if (min_height && (height < min_height || height < 0)) { height = min_height; }
        if (min_width && (width < min_width || width < 0)) { width = min_width; }

        this.setStyles({'height':height, 'width':width});

        //if (true === resizeListener) {
        //    $(document.body).addEvent('resize', this.fitParent(null, min_height, min_width).bind(this));
        //}
    }
});

String.implement({
    isHtml: function() {
        return /<\s?(\w+)[^<>]*>.*<\s?\/\s?\1\s?>|<\s?\w+[^<>]*\/?>/.test(this);
    },
    nl2br: function() {
        return this.replace(/(\r\n)|(\r)|(\n)/g, '<br/>');
    },
    htmlspecialchars: function() {
        if (!this.length || !this.trim().length) {
            return this;
        } else if (/[&<>"']/.test(this)) {
            var result;
            result = this.replace(/&/g, '&amp;');
            result = result.replace(/</g, '&lt;');
            result = result.replace(/>/g, '&gt;');
            result = result.replace(/"/g, '&quot;');
            result = result.replace(/'/g, '&#039;');
            return result;
        } else {
            return this;
        }
    },
    toggle: function(value, other) {
        return this == value ? other : value;
    }
});

var Config = new Class({
    set: function(config) {
        if (this.hasOwnProperty('_config')) {
            if (this.hasOwnProperty('fireEvent')) {
                this.fireEvent('set', arguments);
            }
        } else {
            this._config = {};
        }

        if (2 == arguments.length) {
            var key = arguments[0], value = arguments[1], config = {};
            config[key] = value;
        }
        for (key in config) {
            this._config[key] = config[key];
        }

        return this;
    },
    get: function(/* arg1, arg2[, arg3[, ...]] */) {
        var result = [];
        for (var i = 0, len = arguments.length; i < len; i++) {
            var key = arguments[i];
            if (this._config.hasOwnProperty(key)) {
                result.push(this._config[key]);
            } else {
                throw {message:'specified config key ['+ key +'] not exist'};
            }
        }

        return arguments.length == 1 ? result.shift() : result.associate(arguments);
    }
});

function alertObject(obj) {
    var result = [];
    for (key in obj) {
        result.push(key+': '+obj[key].toString());
    }

    alert(result.join("\n"));
}

var Dialog = new Class({
    Implements: [Config, Events],
    initialize: function(/* HTMLElement|string */el, /* object */config) {
        var _default = {
            'footerAlign': 'center',
            'modal': true,
            'dragable': true,
            'title': '',
            'autoScroll': false,
            'width': 'auto',
            'height': 'auto',
            'top': 'auto',
            'left': 'auto'
        };
        this.set($merge(_default, config || {}));
        this.el = 'undefined' != typeof el && $(el)
                ? $(el)
                : new Element('div');

        this._fixEl();
        this._initEvents();
    },
    _fixEl: function() {
        if (!this.el.parentNode) { $(document.body).appendChild(this.el); }

        if (!this.el.hasClass('windowbox')) { this.el.addClass('windowbox'); }

        var header = this.el.getElement('.wb-header');
        if (!header) {
            var header = new Element('div', {'class':'wb-header'});
            header.inject(this.el, 'top');
        }

        var headerTitle = header.getElement('.wb-title');
        if (!headerTitle) {
            var headerTitle = new Element('span', {'class':'wb-title'});
            headerTitle.inject(header, 'bottom');
        }

        var headerTool = header.getElement('.wb-tool');
        if (!headerTool) {
            // 如果display不是none，在IE下，由于float right，整个窗口右边会一直顶到窗口右边去
            // 只有等到this.el被指定了宽度之后才不会发生这个问题
            // 所以等到this._fixSize()之后才可以把display设置为''
            var headerTool = new Element('span', {'class':'wb-tool', 'html':'x', 'styles':{'display':'none'}});
            headerTool.inject(header, 'top');
        }

        var body = this.el.getElement('.wb-body');
        if (!body) {
            var body = new Element('div', {'class':'wb-body'});
            body.inject(header, 'after');
        }
        if (this.get('autoScroll')) {
            body.setStyle('overflow', 'auto');
        }

        var footer = this.el.getElement('.wb-footer');
        if (!footer) {
            var footer = new Element('div', {
                'class':'wb-footer',
                'styles':{
                    'text-align': this.get('footerAlign')
                }
            });
            footer.inject(this.el, 'bottom');
        }
        this.set('buttons', footer.getElements('button'));

        this.el.setStyles({
            'display':'block',
            'visibility':'hidden',
            'position':'absolute',
            'width': 'auto',
            'height': 'auto'
        });

        if (this.get('title')) { this.setTitle(this.get('title')); }
        if (this.get('modal')) { this._initModal(); }

        return this;
    },
    _initModal: function() {
        this.modalOverlay = new Element('div', {
            styles: {
                'display': 'none',
                'position': 'absolute',
                'top': 0,
                'left': 0,
                'width': '100%',
                'background': '#000000',
                'opacity': 0,
                'filter': 'alpha(opacity=0)',
                '-moz-opacity': 0,
                'z-index': 10000
            }
        });
        this.modalOverlay.inject(document.body);

        if (Browser.Engine.trident4){
            this.modalFix = new Element('iframe', {
                'scrolling': 'no',
                'marginWidth': 0,
                'marginHeight': 0,
                'src': 'javascript:void(0)',
                'styles': {
                    'display': 'none',
                    'position': 'absolute',
                    'top': 0,
                    'left': 0,
                    'width': '100%',
                    'opacity': 0,
                    'filter': 'alpha(opacity=0)',
                    '-moz-opacity': 0,
                    'z-index': 9500
                }
            }).inject(document.body);
        }

        this.modalOverlay.setStyle('opacity', 0.5);

        this._fixModalSize();
    },
    _fixModalSize: function() {
        var styles = {'height':document.getCoordinates().height};
        this.modalOverlay.setStyles(styles);
        if (Browser.Engine.trident4) {
            this.modalFix.setStyles(styles);
        }
    },
    _showModal: function() {
        this.modalOverlay.setStyles({'visibility':'visible', 'display':'block'});
        if (Browser.Engine.trident4) {
            this.modalFix.setStyles({'visibility':'visible', 'display':'block'});
        }
        this.el.setStyle('z-index', 11000);
    },
    _hideModal: function() {
        this.modalOverlay.setStyles({'visibility':'hidden', 'display':'none'});
        if (Browser.Engine.trident4) {
            this.modalFix.setStyles({'visibility':'hidden', 'displya':'none'});
        }
    },
    _initEvents: function() {
        if (this.get('dragable') && 'undefined' != typeof Drag) {
            var header = this.getEl('header');
            header.setStyle('cursor', 'move');
            new Drag(this.el, {'handle':header});
        }

        this.el.getElement('.wb-header .wb-tool').addEvent('click', this.hide.bindWithEvent(this));

        if (this.get('top') == 'auto' || this.get('left') == 'auto') {
            window.addEvents({
                'resize': this._fixPosition.bindWithEvent(this),
                'scroll': this._fixPosition.bindWithEvent(this)
            });
        }

        if (this.get('modal')) {
            window.addEvent('resize', this._fixModalSize.bindWithEvent(this));
        }
    },
    _fixSize: function() {
        this.el.getElement('.wb-tool').setStyle('display', 'none');

        this.el.setStyles(this.get('height', 'width'));

        var dialogLayout = this.el.getLayout();
        var headerLayout = this.getEl('header').getLayout();
        var body = this.getEl('body'), bodyLayout = body.getLayout();
        var footerLayout = this.getEl('footer').getLayout();

        // 计算header footer body内外补丁边框高度，把剩余的高度设置给body
        var offset = [
            dialogLayout['padding-top'], dialogLayout['padding-bottom'], dialogLayout['border-top'], dialogLayout['border-bottom'],
            headerLayout.totalHeight,
            footerLayout.totalHeight,
            bodyLayout['padding-top'], bodyLayout['padding-bottom'], bodyLayout['margin-top'], bodyLayout['margin-bottom'],
            bodyLayout['border-top'], bodyLayout['border-bottom']
        ];

        var offsetHeight = 0;
        for ( var i = 0, len = offset.length; i < len; i++) {
            offsetHeight += offset[i];
        }
        var bodyHeight = this.el.getHeight() - offsetHeight;
        body.setStyle('height', bodyHeight);

        // 把dialog当前高宽计算出来设置到dialog的style里
        // 如果不明确指定dialog高宽，.wb-tool的float:right在ie里会把窗口右边扯到右边窗口边上
        var styles = {};
        if ('auto' == this.get('height')) {
            styles.height = dialogLayout.height;
        }

        if ('auto' == this.get('width')) {
            styles.width = dialogLayout.width;
        }
        this.el.setStyles(styles);

        this.el.getElement('.wb-tool').setStyle('display', '');

        return this;
    },
    setSize: function(/* integer */width, /* integer */height) {
        if (width) { this.get('width', width); }
        if (height) { this.get('height', height); }
        this._fixSize();
    },
    _fixPosition: function() {
        var el = this.getEl();
        if ('none' != el.getStyle('display')) {
            var elSize = el.getSize(), bodySize = $(document.body).getSize();

            var styles = {};
            var x = ('auto' == this.get('left')) ? ((bodySize.x - elSize.x) / 2) : this.get('left');
            styles.left = x;

            var y = ('auto' == this.get('top')) ? ((bodySize.y - elSize.y) / 2) : this.get('top');
            styles.top = y;

            el.setStyles(styles);
        }
        return this;
    },
    setPosition: function(/* integer */top, /* integer */left) {
        if (top) { this.set('top', top); }
        if (left) { this.set('left', left); }
        this._fixPosition();
    },
    setTitle: function(/* string */title) {
        this.el.getElement('.wb-header .wb-title').innerHTML = title;
        this._fixSize();
        return this;
    },
    setContent: function(/* HTMLElement|string */content) {
        var body = this.getEl('body');
        body.empty();
        if ('string' == typeof content) {
            body.set('html', content);
        } else {
            body.appendChild(content);
        }
        this._fixSize();
    },
    addButton: function(/* string|object */properties, /* function */callBack) {
        if ('string' == typeof properties) { properties = {'html':properties}; }

        properties.type = 'button';
        var button = new Element('button', properties);

        this.getEl('footer').appendChild(button);
        this.get('buttons').push(button);

        if ('function' == $type(callBack)) { button.addEvent('click', callBack.bindWithEvent(this, button)); }

        this._fixSize();
        return button;
    },
    getEl: function(/* string */place) {
        switch (place) {
            case 'header': return this.el.getElement('.wb-header');
            case 'body': return this.el.getElement('.wb-body');
            case 'footer': return this.el.getElement('.wb-footer');
            default: return this.el;
        }
    },
    getBody: function() {
        return this.getEl('body');
    },
    show: function() {
        this._fixPosition();
        if (this.get('modal')) { this._showModal(); }
        this.el.setStyle('visibility', 'visible');
        this.fireEvent('show', this);
    },
    hide: function() {
        if (this.get('modal')) { this._hideModal(); }
        this.el.setStyle('visibility', 'hidden');
        this.fireEvent('hide', this);
    }
});

//
// example options: {mode: 'pathinfo', controllerAccessor:'c', actionAccessor:'a', namespaceAccessor:'n', moduleAccessor:'m'}
//
function url(/* string */controllerName,
             /* string */actionName,
             /* object */params,
             /* string */moduleName,
             /* string */namespaceName,
             /* string */anchor,
             /* object */options) {
    var params = params || {};
    var options = options || {};

    var controllerName = controllerName || 'default';
    var actionName = actionName || 'index';

    var controllerAccessor = options.controllerAccessor || 'controller';
    var actionAccessor = options.actionAccessor || 'action';
    var namespaceAccessor = options.namespaceAccessor || 'namespace';
    var moduleAccessor = options.moduleAccessor || 'module';

    var urlMode = (options.mode || 'pathinfo').toLowerCase();
    var lowerChar = options.lowerChar ? options.lowerChar : false;

    if (lowerChar){
        controllerName = controllerName.toLowerCase();
        actionName = actionName.toLowerCase();
    }
    // current url
    var curl = document.baseURI ? document.baseURI : document.URL;
    var match = curl.match(/^([a-z]+):\/\/([^\/\?#]+)\/*([^\?#]*)\??([^#]*)#?(\w*)$/i);
    var url = {
        'schema': match[1],
        'host': match[2],
        'path': match[3],
        'query': match[4],
        'anchor': match[5]
    };

    var query = [], base = url['schema'] +'://'+ url['host'] +'/';
    if ('standard' == urlMode) {
        if (namespaceName) { query.push(namespaceAccessor +'='+ namespaceName); }
        if (moduleName) { query.push(moduleAccessor +'='+ moduleName); }
        query.push(controllerAccessor +'='+ controllerName);
        query.push(actionAccessor +'='+ actionName);

        for (key in params) { query.push(key +'='+ params[key]); }
        url = base + url['path'] +'?'+query.join('&');
    } else if ('pathinfo' == urlMode) {
        for (key in params) { query.push(key); query.push(params[key]); }
        url = base;
        if (namespaceName) { url += namespaceName +'/'; }
        if (moduleName) { url += moduleName + '/'; }
        url += controllerName +'/'+ actionName;
        if (query.length) { url += '/'+ query.join('/'); }
    }
    if (anchor) { url += '#'+ anchor; }
    return url;
}

// author: yangyi (yangyi.cn.gz@gmail.com)

// Based on <http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247> (copy from ajaxslt)
var DOM_ELEMENT_NODE = 1;
var DOM_ATTRIBUTE_NODE = 2;
var DOM_TEXT_NODE = 3;
var DOM_CDATA_SECTION_NODE = 4;
var DOM_ENTITY_REFERENCE_NODE = 5;
var DOM_ENTITY_NODE = 6;
var DOM_PROCESSING_INSTRUCTION_NODE = 7;
var DOM_COMMENT_NODE = 8;
var DOM_DOCUMENT_NODE = 9;
var DOM_DOCUMENT_TYPE_NODE = 10;
var DOM_DOCUMENT_FRAGMENT_NODE = 11;
var DOM_NOTATION_NODE = 12;

/**
 * http://developer.mozilla.org/en/docs/DOMParser
 * 接受一段xml，解析成为xml document对象
 * 调用时可用try{}catch(e){}捕捉错误，错误对象具有parser xml message属性
 * @param   {String}    xml string
 * @return  {Object}    xml document object
 */
function xmlDocument(/* String */xml) {
    if ('object' == typeof xml) { return xml; }

    var doc = null;
    if (window.ActiveXObject) {
        var ActiveIds = ['MSXML2.DOMDocument.6.0', 'MSXML2.DOMDocument.5.0', 'MSXML2.DOMDocument.4.0', 'MSXML2.DOMDocument.3.0', 'MSXML2.DOMDocument', 'Microsoft.XmlDom'];
        for (var len = ActiveIds.length, i = 0; i < len; i++) {
            var id = ActiveIds[i];
            try {
                var doc = new ActiveXObject(id);
                doc.async = false;
                doc.setProperty('SelectionLanguage', 'XPath');
                doc.loadXML(xml);
                break;
            } catch (e) {
            } finally {
                if (doc && doc.parseError && doc.parseError.errorCode != 0) {
                    throw {parser:'MSXML', message:doc.parseError.reason, xml:xml, func:'xmlDocument'};
                }
            }
        }
    } else if (typeof DOMParser != 'undefined') {
        var parser = new DOMParser();
        var doc = parser.parseFromString(xml, 'text/xml');
        if (doc.documentElement.nodeName == 'parsererror') {
            throw {parser:'DOMParser', message:doc.documentElement.firstChild.nodeValue, xml:xml, func:'xmlDocument'};
        }
    } else { return false; }

    return doc;
}

/**
 * 获取指定节点或文档对象的xml内容
 * port from ajaxslt xmlText()
 * @param   {Object}    xml DOM Node or xml Document
 * @return  {String}    xml string
 */
function xmlText(/* Document|Element */node) {
    if (typeof node == 'string') { return node; }

    if (node.innerXML) {
        return node.innerXML;
    } else if (node.xml) {
        return node.xml;
    } else if (typeof XMLSerializer != 'undefined') {
        return (new XMLSerializer()).serializeToString(node);
    } else { return false; }
}

/**
 * 获取所有节点的内容
 * port from ajaxslt xmlValue()
 * @param   {Object}    xml DOM Node or xml Document
 * @return  {String}
 */
function xmlValue(/* Document|Element */node) {
    var val = '';
    if (node.nodeType == DOM_TEXT_NODE ||
        node.nodeType == DOM_CDATA_SECTION_NODE ||
        node.nodeType == DOM_ATTRIBUTE_NODE) {
        val += node.nodeValue;
    } else if (node.nodeType == DOM_ELEMENT_NODE ||
              node.nodeType == DOM_DOCUMENT_NODE ||
              node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
        for (var len = node.childNodes.length, i = 0; i < len; i++) {
            val += arguments.callee(node.childNodes[i]);
        }
    }
    return val;
}

/**
 * 获取节点属性，以对象形式返回
 * @param   {Object}
 * @return  {Object}
 */
function xmlGetAttributes(/* Element */node, /* Boolean */typeFormat) {
    var result = {};
    var nodeMap = node.attributes;
    if (nodeMap) {
        for (var len = nodeMap.length, i = 0; i < len; i++) {
            var aNode = nodeMap.item(i);
            var value = aNode.nodeValue;
            if (typeFormat === true) { value = value.test(/^\d+$/) ? value.toInt() : value; }
            result[aNode.nodeName] = value;
        }
    }
    return result;
}

/**
 * 设置节点属性
 * @param   {Object}    xml DOM Node
 * @param   {Object}    attribute data as object type
 * @return  {Void}
 */
function xmlSetAttributes(/* Element */node, /* Object */attributes) {
    var attributes = attributes || {};
    for (key in attributes) {
        node.setAttribute(key, attributes[key]);
    }
}

/**
 * 使用xpath在xml树中查询
 * http://developer.mozilla.org/en/docs/Introduction_to_using_XPath_in_JavaScript
 * @param   {Object}    xml Document or xml DOM Node
 * @param   {String}    xpath query string
 * @param   {Boolean}   if set true, only return first result node
 * @return  {Mixed}     return array include all nodes or first node
 */
function xpathSelect(/* Document|Element */root, /* String */query, /* Boolean */returnFirst) {
    if (window.ActiveXObject) {
        return returnFirst ? root.selectSingleNode(query) : root.selectNodes(query);
    } else if (document.evaluate) {
        /**
         * DOMParser的return type有ordered和unordered两种
         * ordered会按照树中间的顺序排列结果，unordered不一定
         * 另外还有一种snapshots的，这种结果是树节点的一个clone
         * 也就是说，如果操作结果节点，原来的节点不会有改变
         * 这里使用非clone方式
         */
        var returnType = returnFirst ? XPathResult.FIRST_ORDERED_NODE_TYPE : XPathResult.ORDERED_NODE_ITERATOR_TYPE;
        var doc = (root.nodeType == DOM_DOCUMENT_NODE) ? root : root.ownerDocument;
        var root = (root.nodeType == DOM_DOCUMENT_NODE) ? root.documentElement : root;
        var result = doc.evaluate(query, root, null, returnType, null);

        if (returnFirst) {
            var nodes = result.singleNodeValue;
        } else {
            var nextNode = result.iterateNext();
            var nodes = [];
            while (nextNode) {
                nodes.push(nextNode);
                nextNode = result.iterateNext();
            }
        }
    }
    return nodes;
}

/**
 * http://developer.mozilla.org/en/docs/Transforming_XML_with_XSLT
 * http://developer.mozilla.org/en/docs/Using_the_Mozilla_JavaScript_interface_to_XSL_Transformations
 * @param   {Mixed}     source xml, xml string or xml Document or xml DOM Node
 * @param   {Mixed}     xslt style sheet, xml string or xml Document or xml DOM Node
 * @param   {Boolean}   if set true, return processed xml as Document
 * @return  {Mixed}     return string or Document
 */
function xsltProcess(/* String|Document|Element */srcDoc, /* String|Document|Element */stylesheet, /* Boolean */returnAsDoc) {
    var returnAsDoc = (typeof returnAsDoc == 'undefined') ? false : returnAsDoc;
    try {
        var srcDoc = (typeof srcDoc == 'string') ? xmlDocument(srcDoc) : srcDoc;
        var stylesheet = (typeof stylesheet == 'string') ? xmlDocument(stylesheet) : stylesheet;
    } catch(e) { e.func = 'xsltProcess'; throw e; }

    if (typeof XSLTProcessor != 'undefined') {
        var processor = new XSLTProcessor();
        try {
            processor.importStylesheet(stylesheet);
            var dest = processor.transformToDocument(srcDoc);
            return returnAsDoc ? dest : xmlText(dest);
        } catch(e) { throw {func:'xsltProcess', processor:'XSLTProcessor', xml:xmlText(srcDoc), xslt:xmlText(stylesheet)}; }
    } else if (window.ActiveXObject) {
        try {
            var dest = srcDoc.transformNode(stylesheet);
            return returnAsDoc ? xmlDocument(dest) : dest;
        } catch(e) { throw {func:'xsltProcess', processor:'MSXML', xml:xmlText(srcDoc), xslt:xmlText(stylesheet)}; }
    }

    return false;
}

function copyToClipboard(txt){
    if (window.clipboardData) {
        window.clipboardData.clearData();
        window.clipboardData.setData("Text", txt);
    }else if (navigator.userAgent.indexOf("Opera") != -1) {
        window.location = txt;
    }else if (window.netscape) {
        try{
            netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
        }catch(e){
            window.alert("Your firefox secuity setting doesn't allow you to use clipboard, please open \"about:config\", then set \"signed.applets.codebase_principal_support\" to be true and try again.");
            return false;
        }
        var clip = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
        if (!clip){ return; }
        var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
        if (!trans){ return; }
        trans.addDataFlavor('text/unicode');
        var str = new Object();
        var len = new Object();
        var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
        var copytext = txt;
        str.data = copytext;
        trans.setTransferData("text/unicode",str,copytext.length*2);
        var clipid = Components.interfaces.nsIClipboard;
        if (!clip){ return false; }
        clip.setData(trans,null,clipid.kGlobalClipboard);
        window.alert('Succeed');
    }
}

var edit_survey_dialog;
function edit_survey(sn) {
    var request = new Request({
        url: '/survey/beforeedit',
        data: {'survey_sn':sn},
        autoCancel: true,
        async: false,
        onSuccess: function(responseText) {
            var response = JSON.decode(responseText, true);
            if (false === response) {
                window.alert('You can not edit this survey');
            } else if (true === response || null === response) {
                window.location = '/edit/'+sn;
            } else if ('object' === typeof response) {
                if (!edit_survey_dialog) {
                    edit_survey_dialog = new Dialog(null, {'title':'Edit survey', 'width':500, 'height':100});
                    edit_survey_dialog.addButton({'text':'Load survey with last change', 'class':'normal', 'id':'edit-survey-with-cache'});
                    edit_survey_dialog.addButton({'text':'Load default survey', 'class':'normal', 'id':'edit-survey-without-cache'});
                    edit_survey_dialog.addButton({'text':'Cancel', 'class':'normal'}, edit_survey_dialog.hide.bind(edit_survey_dialog));
                }
                var message = 'Your last change was not saved on：'+response.create_time;
                edit_survey_dialog.setContent(message);

                $('edit-survey-with-cache').addEvent('click', (function(event){
                    event.target.set({'disabled': true, 'text':'Loading...'});
                    window.location = '/edit/'+sn+'?cache';
                }).bindWithEvent(null));
                
                $('edit-survey-without-cache').addEvent('click', (function(event){
                    event.target.set({'disabled': true, 'text':'Loading...'});
                    window.location = '/edit/'+sn;
                }).bindWithEvent(null));
                edit_survey_dialog.show();
            }
        },
        onException: function() {
            window.location = '/edit/'+sn;
        }
    });
    request.send();
}
