/*

    Functions from prototype.js (http://prototype.conio.net/)

    Rewritten just a little bit.

*/


function highlight(field) {
        field.focus();
        field.select();
} 

function $() {

    for ( var i = 0, elements = []; i < arguments.length; ++i )

        elements.push ( typeof arguments[i] == 'string' ? document.getElementById ( arguments[i] ) : arguments[i] );

    return elements.length == 1 ? elements[0] : elements;

}



function $A ( array ) {

    if ( !array ) return [];

    if ( array.toArray ) return array.toArray();

    for ( var i = 0, result = []; i < array.length; ++i )

        result.push ( array[i] );

    return result;

}



var Class = {

    create: function() { return function() { this.initialize.apply ( this, arguments ); } }

}



Object.extend = function ( dest, source ) {

    for ( p in source ) dest[p] = source[p];

    return dest;

}



Function.prototype.bind = function() {

    var __method = this, args = $A(arguments), obj = args.shift();

    return function() { return __method.apply ( obj, args.concat ( $A ( arguments ) ) ); }

}



Function.prototype.bindAsEventListener = function ( object ) {

    var __method = this;

    return function ( event ) { return __method.call ( object, event || window.event ); }

}



Object.prototype.shift = function() {

    var result = this[0];

    this.length--;

    for ( var i = 0; i < this.length; ++i )

        this[i] = this[i+1];

    return result;

}



var Try = {

    these: function() {

        for ( var i = 0, retval; i < arguments.length; ++i )

            try { retval = arguments[i](); break; } catch(error){}

        return retval;

    }

}





if (!window.Event) {

    var Event = new Object();

}



Object.extend(Event, {

    KEY_BACKSPACE: 8,

    KEY_TAB:       9,

    KEY_RETURN:   13,

    KEY_ESC:      27,

    KEY_LEFT:     37,

    KEY_UP:       38,

    KEY_RIGHT:    39,

    KEY_DOWN:     40,

    KEY_DELETE:   46,



    element: function(event) {

        return event.target || event.srcElement;

    },



    isLeftClick: function(event) {

        return (((event.which) && (event.which == 1)) || ((event.button) && (event.button == 1)));

    },



    pointerX: function(event) {

        return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));

    },



    pointerY: function(event) {

        return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop));

    },



    stop: function(event) {

        if (event.preventDefault) {

            event.preventDefault();

            event.stopPropagation();

        } else {

            event.returnValue = false;

            event.cancelBubble = true;

        }

    },



    observers: false,



    _observeAndCache: function(element, name, observer, useCapture) {

        if (!this.observers) this.observers = [];

        if (element.addEventListener) {

            this.observers.push([element, name, observer, useCapture]);

            element.addEventListener(name, observer, useCapture);

        } else if (element.attachEvent) {

            this.observers.push([element, name, observer, useCapture]);

            element.attachEvent('on' + name, observer);

        }

    },



    unloadCache: function() {

        if (!Event.observers) return;

        for (var i = 0; i < Event.observers.length; i++) {

            Event.stopObserving.apply(this, Event.observers[i]);

            Event.observers[i][0] = null;

        }

        Event.observers = false;

    },



    observe: function(element, name, observer, useCapture) {

        var element = $(element);

        useCapture = useCapture || false;

        if (name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent))

            name = 'keydown';

        this._observeAndCache(element, name, observer, useCapture);

    },



    stopObserving: function(element, name, observer, useCapture) {

        var element = $(element);

        useCapture = useCapture || false;



        if (name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.detachEvent))

            name = 'keydown';



        if (element.removeEventListener) {

            element.removeEventListener(name, observer, useCapture);

        } else if (element.detachEvent) {

            element.detachEvent('on' + name, observer);

        }

    }

});





// Event stuffs, don't need these anymore, use prototype's observe instead

function addEvent( obj, type, fn, userCapture ) {

    Event.observe ( obj, type, fn, userCapture );

}



function removeEvent( obj, type, fn, userCapture ) {

    Event.stopObserving ( obj, type, fn, userCapture );

}



function addLoadEvent ( func ) {

    var oldonload = window.onload;

    if (typeof window.onload != 'function') window.onload = func;

    else { window.onload = function() { oldonload(); func(); } }

}



/*

    Others stuffs

*/



function getCookie( name ) {

    var start = document.cookie.indexOf( name + "=" );

    var len = start + name.length + 1;

    if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) return null;

    if ( start == -1 ) return null;

    var end = document.cookie.indexOf( ";", len );

    if ( end == -1 ) end = document.cookie.length;

    return unescape( document.cookie.substring( len, end ) );

}



function setCookie( name, value, expires, path, domain, secure ) {

	var today = new Date();

	today.setTime( today.getTime() );

	if ( expires )

	    expires = expires * 1000 * 60 * 60 * 24;

	var expires_date = new Date( today.getTime() + (expires) );

	document.cookie = name+"="+escape( value ) +

        ( ( expires ) ? ";expires="+expires_date.toGMTString() : "" ) + //expires.toGMTString()

        ( ( path ) ? ";path=" + path : "" ) + ( ( domain ) ? ";domain=" + domain : "" ) + ( ( secure ) ? ";secure" : "" );

}



function deleteCookie( name, path, domain ) {

    if ( getCookie( name ) ) document.cookie = name + "=" + ( ( path ) ? ";path=" + path : "") +

    ( ( domain ) ? ";domain=" + domain : "" ) + ";expires=Thu, 01-Jan-1970 00:00:01 GMT";

}





if ( typeof Array.prototype.push == 'undefined' ) {

    Array.prototype.push = function() {

        for ( var i = 0, l = this.length; i < arguments.length; ++i )

            this[l+i] = arguments[i];

        return this.length;

    }

}



Array.prototype.remove = function(v)

{

    for ( var i = 0; i < this.length; ++i )

        if ( this[i] == v )

            return this.splice(i, 1);

    return false;

}



Object.prototype.toQueryString = function() {

    var query = [];

    for ( var x in this ) {

        var type = typeof this[x];

        if ( type != 'function' && type != 'object' )

            query.push([x, encodeURIComponent(this[x])].join('='));

    }

    return query.join('&');

}



// from: http://jsfromhell.com/string/wordwrap

String.prototype.wordWrap = function(m, b, c){ //v1.0

    var i, j, l, s, r = this.split("\n");

    if(m > 0) for(i = -1, l = r.length; ++i < l;){

        for(s = r[i], r[i] = ""; s.length > m;

            j = c ? m : (j = s.substr(0, m).match(/\S*$/)).input.length - j[0].length

            || j.input.length + (j = s.substr(m).match(/^\S*/)).input.length + j[0].length,

            r[i] += s.substr(0, j) + ((s = s.substr(j)).length ? b : "")

        );

        r[i] += s;

    }

    return r.join("\n");

};



Object.extend ( String.prototype, {

    escapeHTML: function() {

        var div = document.createElement('div');

        var text = document.createTextNode(this);

        div.appendChild(text);

        return div.innerHTML;

    },



    getTextWidth: function(){

        var span = document.createElement('span');

        Object.extend(span.style, {visibiliy:'hidden', position:'absolute', left:'0px', top:'0px'});

        span.innerHTML = this;

        document.body.appendChild(span);

        var width = span.offsetWidth;

        document.body.removeChild(span);

        return width;

    },



    // from: http://jsfromhell.com/string/wordwrap

    wordWrap: function(m, b, c) {

        var i, j, l, s, r = this.split("\n");

        if(m > 0) for(i = -1, l = r.length; ++i < l;){

            for(s = r[i], r[i] = ""; s.length > m;

                j = c ? m : (j = s.substr(0, m).match(/\S*$/)).input.length - j[0].length

                || j.input.length + (j = s.substr(m).match(/^\S*/)).input.length + j[0].length,

                r[i] += s.substr(0, j) + ((s = s.substr(j)).length ? b : "")

            );

            r[i] += s;

        }

        return r.join("\n");

    }

});





/* Basic funcs & objs */

function Timer()

{

    this.t=false;

    this.intv=false;

    this.start=function(func,delay){this.stop();this.t=window.setTimeout(func,delay);};

    this.stop=function(){if(this.t)window.clearTimeout(this.t);}

    this.startInterval=function(func,delay){this.intv=window.setInterval(func,delay);};

    this.stopInterval=function(){if(this.intv)window.clearInterval(this.intv);}

}





var quickEditBase = Class.create();

quickEditBase.prototype =

{

    initialize : function() {

        this.options = {inputSize:50, maxInput:255, maxCharsVisible:100, textAlign:'left', maxWidth:100, style:{}};

    },



    setOptions : function(options) {

        Object.extend(this.options, options||{});

    },



    initContainer : function()

    {

        if(!this.container) return false;

        this.oldStyles = { backgroundColor: this.container.style.backgroundColor, color: this.container.style.color };



        this.observers = {

            mouseover: function(){Object.extend(this.container.style, {backgroundColor:'#FFFFE6',cursor:'text',color:'#000'});}.bind(this),

            mouseout: function() { Object.extend(this.container.style, this.oldStyles); }.bind(this),

            mouseclick: this.showEditable.bind(this)

        };



        Event.observe ( this.container, 'mouseover', this.observers.mouseover );

        Event.observe ( this.container, 'mouseout', this.observers.mouseout );

        Event.observe ( this.container, 'click', this.observers.mouseclick );

    },



    restoreContainer: function()

    {

        if(!this.container) return false;

        Object.extend(this.container.style, this.oldStyles);

        this.container.onmouseover = null;

        Event.stopObserving ( this.container, 'mouseover', this.observers.mouseover );

        Event.stopObserving ( this.container, 'mouseout', this.observers.mouseout );

        Event.stopObserving ( this.container, 'click', this.observers.mouseclick );

    },



    showEditable : function()

    {

        this.editBox = document.createElement('span');

        this.inputField = document.createElement('input');

        if(!this.editBox||!this.inputField)return false;

        this.inputField.value = this.value;

        this.inputField.size = this.options.inputSize;

        this.inputField.onkeypress = this.keyPressHandler.bindAsEventListener(this);

        this.inputField.onblur = this.doUpdate.bind(this);

        this.inputField.maxLength = this.options.maxInput;

        this.inputField.style.textAlign = this.options.textAlign;

        this.editBox.className = 'qinput';

        Object.extend(this.editBox.style, this.options.style||{});

        this.editBox.appendChild(this.inputField);

        this.container.parentNode.insertBefore(this.editBox, this.container);

        this.container.style.display = 'none';

        this.inputField.setAttribute('autocomplete', 'off');



        var width = this.inputField.value.getTextWidth();

        this.inputField.style.width = ( width > this.options.maxWidth ? this.options.maxWidth : ( width < 40 ? 40 : width ) ) + 'px';



        this.inputField.focus();

        this.inputField.select();

    },



    hideEditable : function(value)

    {

        var str = value || this.value;

        str = str_slice ( str.escapeHTML(), this.options.maxCharsVisible );

        this.container.innerHTML = str;

        this.container.style.display = '';

        if(this.editBox.parentNode) this.editBox.parentNode.removeChild(this.editBox);

    },



    keyPressHandler : function ( event )

    {

        event = event || window.event;

        var key = event.keyCode;

        if ( key == Event.KEY_RETURN ) {

            this.inputField.onblur = function(){};

            window.setTimeout(this.doUpdate.bind(this), 50);

            return false;

        }

        if ( key == Event.KEY_ESC ) {

            this.hideEditable();

            return;

        }

        var str = this.inputField.value + String.fromCharCode(key);

        var width = str.getTextWidth();

        this.inputField.style.width = ( width > this.options.maxWidth ? this.options.maxWidth : ( width < 40 ? 40 : width ) ) + 'px';

        return true;

    },



    doUpdate : function() {

        alert ( 'doUpdate() must be implemented' );

        this.hideEditable();

    }

};



// Ajax stuffs

var Ajax = {

    events: ['uninitialized', 'loading', 'loaded', 'interactive', 'complete'],

    enabled: ( typeof XMLHttpRequest != 'undefined' || typeof ActiveXObject != 'undefined' ),

    getXMLHttpObject: function ( ) {

        return Try.these (

            function() {return new ActiveXObject('Msxml2.XMLHTTP')},

            function() {return new ActiveXObject('Microsoft.XMLHTTP')},

            function() {return new XMLHttpRequest()}

        ) || false;

    }

}



AjaxRequest = Class.create();

AjaxRequest.prototype = {

    initialize: function ( url, options ) {

        this.options    = Object.extend ( { method: 'post', async: true, postData: {}, response: 'json' }, options || {} );

        this.onloading  = null;

        this.onloaded   = null;

        this.oncomplete = null;

        this.response   = null;

        this.xmlhttp    = Ajax.getXMLHttpObject();

        this.url        = url;

    },



    setOptions: function ( options ) {

        this.options = Object.extend ( this.options, options || {} );

    },



    request: function ( url )

    {

        this.url = url || this.url;

        this.xmlhttp.open ( this.options.method, this.url + (this.url.indexOf('?')<0?'?':'&') + 'ajax=' + this.getRand(), this.options.async );

        if ( this.options.async )

            this.xmlhttp.onreadystatechange = this.stateChange.bind(this);

        if ( this.options.method == 'post' )

            this.xmlhttp.setRequestHeader ( 'Content-type','application/x-www-form-urlencoded; charset=utf-8' )

        this.xmlhttp.send ( this.options.method == 'post' ? this.options.postData.toQueryString() : null );

    },



    stateChange: function ( )

    {

        var state = Ajax.events[this.xmlhttp.readyState];

        if ( state == 'loading' && this.onloading != null )

            this.onloading.bind(this)();

        if ( state == 'loaded' && this.onloaded != null )

            this.onloaded.bind(this)();

        if ( state == 'complete' && this.xmlhttp.status == 200 )

        {

            this.response = this.getResponse();

            this.xmlhttp.onreadystatechange = function(){};

            if ( this.oncomplete != null )

                this.oncomplete.bind(this)();

        }

    },



    getResponse: function ( type ) {

        var type = type || this.options.response;

        if ( type == 'json' ) {

            try { eval ( 'var resp = ' + this.xmlhttp.responseText ); return resp; }

            catch (error) { return { result: 'failed', message: 'Returned result is not proper JSON format. Probably parse error.' }; }

        }

        return type == 'xml' ? this.xmlhttp.responseXML : this.xmlhttp.responseText;

    },



    getRand: function ( ) {

        for ( var i = 0, rand = ''; i < 5; ++i )

            rand += String(Math.floor(Math.random()*10000000000));

        return rand;

    }

};



Element = new Object();

Object.extend(Element,

{

    position: function ( element, type )

    {

        element = $(element);

        if ( !element ) return;

        if ( type == 'absolute' && !element._absolute )

        {

            var offset = Element.getOffset ( element, false );

            Object.extend ( element.style, { position: 'absolute', top: offset.offsetTop + 'px', left: offset.offsetLeft } );

            element._absolute = true;

        }

    },



    cumulativeOffset: function(element)

    {

        var valueT = 0, valueL = 0;

        do {

            valueT += element.offsetTop  || 0;

            valueL += element.offsetLeft || 0;

            element = element.offsetParent;

        } while (element);

        return [valueL, valueT];

    },



    setOpacity: function(element, opacity)

    {

        element = $(element);

        if(!element) return false;

        if(element.filters)

        {

            try { element.filters.alpha.opacity = opacity; }

            catch (error) { element.style.filter = "alpha(opacity=" + opacity + ")"; }

        }

        Object.extend ( element.style, { 'opacity': opacity / 100, MozOpacity: opacity / 100, visibility: opacity <= 0 ? 'hidden' : 'visible' } );

    },



    getOffset: function(element, absolute)

    {

        absolute = absolute || false;

        element = $(element);

        if(!element) return false;

        var offset = Object.extend ( Element.cumulativeOffset ( element ) );

        var retval = {offsetWidth: element.offsetWidth, offsetHeight:element.offsetHeight, offsetLeft: offset[0], offsetTop: offset[1]};

        retval.offsetRight = retval.offsetLeft + retval.offsetWidth;

        retval.offsetBottom = retval.offsetTop + retval.offsetHeight;

        return retval;

    },



    fade: function(element, from, to, step)

    {

        element = $(element);

        if(!element) return false;

        if(from == null) from = 100;

        step = step || 10;

        if ( from == to )

        {

            if(typeof element.onfadefinish == 'function')

                element.onfadefinish();

            return true;

        }

        from = Element.__getNextStepValue(from, to, step);

        Element.setOpacity(element, from);

        window.setTimeout ( Element.fade.bind ( this, element, from, to, step ), 10 );

    },



    __getNextStepValue: function(from, to, step)

    {

        if(from > to) from -= (from - to) > step ? step : from - to;

        else from += (to - from) > step ? step : to - from;

        return from;

    }

});



var Form = {

    disable: function(element, disabled) {

        element = $(element);

        if(!element) return false;

        var tagName = element.tagName.toLowerCase();



        if ( tagName == 'form' || tagName == 'input' || tagName == 'textarea' || (tagName == 'fieldset' && document.all) ) {

            element.disabled = disabled;

            return true;

        }

        if(typeof disabled == 'undefined') disabled = true;

        var inputs = element.getElementsByTagName('input');

        for(var i = 0; i < inputs.length; ++i)

            inputs[i].disabled = disabled;

        var inputs = element.getElementsByTagName('textarea');

        for(var i = 0; i < inputs.length; ++i)

            inputs[i].disabled = disabled;

    }

};





var Drag = Class.create();

Drag.prototype = {

    initialize: function(element, options) {

        this.dragObj = $(element);

        if ( !this.dragObj ) return false;

        this.options = { zIndex: 1, horizontal: true, vertical: true, leftBound: 0, rightBound: -1, topBound: 0, bottomBound: -1 };

        Object.extend ( this.dragObj.style, { position: 'absolute' } );

        this.setOptions ( options || this.options );

        this.lastMousePos = [0, 0]; // [x, y]

        this.observers = {

            mouseMove: this.mouseMoveListener.bindAsEventListener(this),

            mouseDown: this.startDrag.bindAsEventListener(this),

            mouseUp: this.stopDrag.bindAsEventListener(this)

        };

        this.ondrag = null;

        this.ondragstart = null;

        this.ondragend = null;

        Event.observe ( this.dragObj, 'mousedown', this.observers.mouseDown );

        Event.observe ( this.dragObj, 'mouseup', this.observers.mouseUp );



        this.dragObj.onmousedown = function(){ return false; }

    },



    setBoundary: function(top, right, bottom, left) {

        this.setOptions({leftBound:left, rightBound:right, topBound:top, bottomBound:bottom});

    },



    setBoundingObject: function(element)

    {

        element = $(element);

        if(!element) return false;

        var offset = Element.getOffset(element);

        this.setBoundary(offset.offsetTop, offset.offsetRight, offset.offsetBottom, offset.offsetLeft);

    },



    setOptions: function(options) {

        Object.extend(this.options, options || {});

    },



    startDrag: function(event)

    {



        if ( !Event.isLeftClick ( event ) ) return false;

        Object.extend ( this.dragObj.style, { zIndex: this.options.zIndex + 1 } );

        Event.observe ( document, 'mousemove', this.observers.mouseMove );

        Event.observe ( document, 'mouseup', this.observers.mouseUp );

        document.onselectstart = function(){return false;};

        document.ondragstart = function(){return false;}



        var offset = Element.getOffset ( this.dragObj, true );

        var mousePosX = ( event.pageX || event.pageY ) ? event.pageX : event.clientX + document.body.scrollLeft;

        var mousePosY = ( event.pageY || event.pageY ) ? event.pageY : event.clientY + document.body.scrollTop;

        this.relativeX = mousePosX - offset.offsetLeft;

        this.relativeY = mousePosY - offset.offsetTop;

        this.dragObjOffset = offset;

        if ( typeof this.ondragstart == 'function' ) this.ondragstart ( Element.getOffset ( this.dragObj, true ) );



        Element.position ( this.dragObj, 'absolute' );

        return false;

    },



    stopDrag: function(event)

    {

        Object.extend ( this.dragObj.style, { zIndex: this.options.zIndex } );

        Event.stopObserving ( document, 'mousemove', this.observers.mouseMove );

        Event.stopObserving ( document, 'mouseup', this.observers.mouseUp );

        document.onselectstart = function(){return true;};

        if ( typeof this.ondragend == 'function' ) this.ondragend ( Element.getOffset ( this.dragObj, true ) );

        Element.position ( this.dragObj, 'relative' );

    },



    mouseMoveListener: function(event)

    {

        var mousePosX = Event.pointerX(event);

        var mousePosY = Event.pointerY(event);

        if ( this.lastMousePos[0] == mousePosX && this.lastMousePos[1] == mousePosY ) return;

        var pos = {

            left: mousePosX - this.relativeX, right: (mousePosX - this.relativeX) + this.dragObjOffset.offsetWidth,

            top: mousePosY - this.relativeY, bottom: (mousePosY - this.relativeY) + this.dragObjOffset.offsetHeight

        };

        // boundary constraints

        if ( pos.left < this.options.leftBound ) pos.left = this.options.leftBound;

        else if ( this.options.rightBound > -1 && ( pos.right > this.options.rightBound ) ) pos.left = ( this.options.rightBound  - this.dragObjOffset.offsetWidth );

        if ( pos.top < this.options.topBound ) pos.top = this.options.topBound;

        else if ( this.options.bottomBound > -1 && ( pos.bottom > this.options.bottomBound ) ) pos.top = ( this.options.bottomBound - this.dragObjOffset.offsetHeight );

        // direction constraints

        if ( this.options.horizontal ) this.dragObj.style.left = pos.left + 'px';

        if ( this.options.vertical ) this.dragObj.style.top = pos.top + 'px';

        if ( typeof this.ondrag == 'function' ) this.ondrag ( Element.getOffset ( this.dragObj, true ) );

        this.lastMousePos = [mousePosX, mousePosY];

    }

};





