/*
    Functions from prototype.js (http://prototype.conio.net/)
    Rewritten just a little bit.
*/

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 = 'images[]';
        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];
    }
};



