Object.prototype.extend=function(object){
    try{
        for(var property in object){
            this[property]=object[property];
        }
        return this;
    }catch(e){
        return false;
    }
};
Object.prototype.include=function(object,propertyList){
    try{
        if (propertyList && propertyList.length){
            for(var c=0;c<propertyList.length;c++){
                var property=propertyList[c];
                if (property && (typeof property=='string')){
                    this[property]=object[property];
                }
            }
        }
        return true;
    } catch(e){
        return false;
    }
};

Object.prototype.inherits=function(prototypes){
    return this.prototype.extend(prototypes);
};

Object.prototype.getPropertyList=function(){
    var properties=new Array();
    for(var property in this){
        properties[properties.length]=property;
    }
    return properties;
}



Object.prototype.extend(
    {
/*
*   OBJECT SUPPORT
*/
        isObject:true,
        isClass:false,
        isNumber:false,
        isString:false,
        isArray:false,
        isDate:false,
        serialize:function(){
            var str='';
            for(var property in this){
                var type=typeof this[property];
                switch(type){
                    case 'function':
                    case 'object':
                            str+=type+':'+property;
                            if (this[property]==null){
                                str+='=null';
                            } else if (this[property]==undefined){
                                str+='=undefined';
                            }
                        break;
                    case 'null':
                            str+=type+':'+property+'=null';
                        break;
                    default:
                            str+=type+':'+property+'='+this[property];
                        break;
                }
                str+="\n";
            }
            return str;
        },
        typeArray:function(data){
            try {
                return data.isArray;
            } catch(e){
                return false;
            }
        },
        typeString:function(data){
            return typeof data=='string';
        },
        typeNumber:function(data){
            return typeof data=='number';
        },
        typeScalar:function(data){
            return this.typeString(data) || this.typeNumber(data);
        },
        typeFunction:function(data){
            return typeof data=='function';
        },
/*
*   ERROR REPORTING
*/
        _default_reportError:function(message){
            if (typeof message=='string'){
                alert('Error: '+message);
            } else {
                alert('Error: Unknown Error');
            }
            return false;
        },
        _last_reportError:null,
        resetErrorReporting:function(){
            Object.prototype._last_reportError=
            Object.prototype._default_reportError;
        },
        setErrorReporting:function(errorFunc){
            if (typeof errorFunc=='function'){
                Object.prototype._last_reportError=errorFunc;
            }
        },
        getErrorReporting:function(){
            return Object.prototype._last_reportError;
        },
        reportError:function(message){
            var reporter=Object.prototype.getErrorReporting();
            
            if (typeof reporter!='function'){
                this.resetErrorReporting();
                reporter=Object.prototype.getErrorReporting();
            }
            reporter.call(this,message);
            
        },
/*
*   MODULES
*/
        modulePath:function(){
            var url=window.location.href&&
                    window.location.href.toString(),
    		    domain=url.replace(/^(http\:\/\/[^\/]+).*$/,"$1"),
                isDOM=document.getElementsByTagName,
                scripts=isDOM&&
                    document.getElementsByTagName('head')[0] &&
                    document.getElementsByTagName('head')[0].getElementsByTagName('script'),
                configPath='',
                configScript='';
                
            if (!scripts){
                return false;
            }
            for(var c=0;c<scripts.length;c++){
                var src=scripts[c].getAttribute &&
                    scripts[c].getAttribute('src');
                if (src&&src.match(/base\.js$/)){
                    return src.replace(/[^\/]+$/,'');
                }
            }
            return '';
        },
        loadScript:function(fileName){
            //-- load module
            if (fileName && (typeof fileName=='string')){
    			document.write('<script language="javascript" type="text/javascript" src="'+fileName+'"></script>');
                return true;
            } else {
                return false;
            }
        },
        loadModule:function(name){
            var path=this.modulePath();
            if (name&& (typeof name=='string')){
                this.loadScript(path+name+'.js');
            }
        },
        scriptPath:function(){
            var path=this.modulePath(),
                scriptPath=path && path.replace(/[^\/]+\/$/,'');
            return scriptPath || '';
        },
/*
*   DATA HANDLE
*/
        convertToArray:function(data){
            var arrayData=new Array();
            if (data && data.length){
                for(var c=0;c<data.length;c++){
                    arrayData[arrayData.length]=data[c];
                }
            }
            return arrayData;
        },
        range:function(from,to){
            
            if (this.typeNumber(from) &&
                this.typeNumber(to)
            ){
                var newArray=new Array();
                if (from<to){
                    for(var c=from;c<=to;c++){
                        newArray[newArray.length]=c;
                    }
                } else {
                    for(var c=from;c>=to;c--){
                        newArray[newArray.length]=c;
                    }
                }
                return newArray;
            }
        },
        serializeDom:function(dom){
            if (!dom){
                return '';
            }
            if (typeof XMLSerializer != 'undefined') {
                //xmlSerializer.writeToString //-- opera
                return new String(new XMLSerializer().serializeToString(dom));
            } else if (typeof dom.outerHTML != 'undefined') {
                return dom.outerHTML;
            } else if (typeof printNode != 'undefined') {
                return printNode(dom);
            } else if (typeof Packages != 'undefined') {
                try {
                    var stringWriter = new java.io.StringWriter();
                    Packages.org.apache.batik.dom.util.DOMUtilities.writeNode(
                        dom, stringWriter);
                    return stringWriter.toString();
                } catch (e) {}
            } else {
                return this.serializeDomElement(dom);
            }
            return '';
        },
        serializeDomElement:function(element){
            var encoded='';
            if (element && element.tagName && (typeof element.tagName=='string')){
                
                var attributes=this.serializeDomElementAttribute(element);
                encoded+='<'+element.tagName+(attributes?' '+attributes:'')+'>';
                
                if (element.childNodes &&
                    element.childNodes.length
                ){
                    for(var c=0;c<element.childNodes.length;c++){
                        var node=element.childNodes[c];
                        if (node && node.tagName){
                            encoded+=this.serializeDomElement(node);
                        } else if (typeof node.nodeValue=='string'){
                            encoded+=node.nodeValue.trim().htmlencode();
                            
                        }
                    }
                }
                encoded+='</'+element.tagName+'>';
            }
            return encoded;
        },
        serializeDomElementAttribute:function(element){
            var str='';
            if (element &&
                element.tagName &&
                (typeof element.tagName=='string') &&
                element.attributes &&
                element.attributes.length
            ){
                for(var c=0;c<element.attributes.length;c++){
                    var attribute=element.attributes[c];
                    if (attribute &&
                        attribute.nodeName &&
                        (typeof attribute.nodeValue=='string')
                    ){
                        str+=attribute.nodeName+'="'+attribute.nodeValue.htmlencode()+'"';
                    }
                    if (c<(element.attributes.length-1)){
                        str+=' ';
                    }
                }
            }
            return str;
        },
/*
*   EXECUTION CONTROL
*/
        alarm:function(interval,callback,once){//,parameters){
            var canAlarm=(typeof interval=='number')&&
                    (interval>=0) &&
                    (typeof callback=='function');
           
            if (canAlarm){
                //-- create timeout ID
                var timer={
                        onalarm:callback,
                        contineous:(typeof once=='boolean')?once:false,
                        id:null
                    };
                timer.id=window.setInterval(
                    function(){
                        if (!this.contineous){
                            window.clearInterval(this.id);
                        }
                        this.onalarm();
                    }.bindListener(timer),interval
                );
                return timer.id;
            } else {
                return false;
            }
        },
        cancelAlarm:function(alarmId){
            try{
                window.clearInterval(alarmId);
            } catch(e){
                this.reportError(e);
            }
        }
    }
);

Function.prototype.extend(
    {
        isFunction:true,
        isClass:false,
        bindListener:function(){
            var thisFunction=this,
                parameters=this.convertToArray(arguments),
                context=parameters&&parameters.length&&parameters.shift();
            return function(e){
                return thisFunction.apply(context||thisFunction,parameters);
            }
        },
        bindEventListener:function(){
            var thisFunction=this,
                parameters=this.convertToArray(arguments),
                context=parameters&&parameters.length&&parameters.shift();
            return function(e){
                return thisFunction.call(context||thisFunction,e||window.event,parameters);
            }
        }
    }
);

Array.prototype.extend(
    {
        isArray:true,
        hasValue:function(value){
            return this.foreach(
                function(i){
                    if (i.value==value){
                        return true;
                    }
                }.bindEventListener(value)
            );
        },
        foreach:function(callback){
            if (typeof callback=='function'){
                var returned=null;
                for(var c=0;c<this.length;c++){
                    returned=callback(
                        {
                            key:c,
                            value:this[c]
                        }
                    );
                    if (typeof returned!='undefined'){
                        return returned;
                    }
                }
                return returned;
            }
        },
        from:function(from,to,callback){
            if (!this.typeNumber(from) ||
                !this.typeNumber(to) ||
                (from==to) ||
                (this.length>=to) ||
                (to<0) ||
                (this.length>=from) ||
                (from<0)
            ){
                return;
            }
            var increment=from<to,
                returned=null;
            if (increment){
                for(var c=from;c<to;c++){
                    returned=callback(
                        { key:c, value:this[c] }
                    );
                    if (typeof returned!='undefined'){
                        return returned;
                    }
                }
            } else {
                for(var c=from;c>to;c--){
                    returned=callback(
                        { key:c, value:this[c] }
                    );
                    if (typeof returned!='undefined'){
                        return returned;
                    }
                }
            }
        },
        merge:function(items){
            if (!this.typeArray(items) ||
                !items.length
            ){
                return this;
            }
            items.foreach(
                function(i){
                    this[this.length]=i.value;
                }.bindEventListener(this)
            );
        },
        remove:function(i,count){
            if (!isNaN(i)){
                if (!isNaN(count)){
                    this.splice(i,count);
                } else {
                    this.splice(i,this.length);
                }
            } else {
                this.foreach(
                    function(i){
                        if (i.value == this.i){
                            this.handle.splice(i.key,1);
                            return true;
                        }
                    }.bindEventListener(
                        {
                            handle:this,
                            i:i
                        }
                    )
                );
            }
        }
    }
);

//-- backward compatibility array.shift()
if (typeof Array.prototype.splice=='undefined'){
Array.prototype.extend(
    {
        splice:function(startIndex,width){
            var returnValue=new Array();
            if (!isNaN(startIndex) && (startIndex>-1)){
                //-- get exact width
                if (isNaN(width)){
                    width=this.length-startIndex;
                }
                var replaceItems=new Array();
                if (typeof arguments[2]!='undefined'){
                    for(var c=2;c<arguments.length;c++){
                        replaceItems[replaceItems.length]=arguments[c];
                    }
                }
                //-- create first items
                if (this.length){
                    var sliced=this.slice(0,startIndex),
                        returnValue=this.slice(startIndex,startIndex+width),
                        lastSlice=this.slice(startIndex+width);
                
                    //-- concatenate items
                    if (replaceItems.length){
                        sliced=sliced.concat(replaceItems);
                    }
                    if (lastSlice && lastSlice.length){
                        sliced=sliced.concat(lastSlice);
                    }
                    //-- remodel items
                    var newLength=(this.length>sliced.length)?this.length:sliced.length;
                    for(var c=0;c<newLength;c++){
                        if (typeof sliced[c]!='undefined'){
                            this[c]=sliced[c];
                        } else if (typeof this[c]!='undefined') {
                            delete this[c];
                        }
                    }
                    this.length=sliced.length;
                }
            }
            return returnValue;
        },
        shift:function(){
            if (this.length){
                return this.splice(0,1);
            }
        },
        unshift:function(){
            if (arguments.length){
                return this.splice(0,0,arguments[0]);
            }
        },
        push:function(){
            if (arguments.length){
                return this.splice(this.length,0,arguments[0]);
            }
        },
        pop:function(){
            if (arguments.length){
                return this.splice(this.length,0,arguments[0]);
            }
        }
    }
);

}

Number.prototype.extend(
    {
        isNumber:true,
        _digitReference:"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        baseConvert:function(number,base){
            var value=(number!=null)?number:this.valueOf();
            if (typeof value!='number'){
                return this.reportError(value+' is type '+typeof value);
            }
            if (typeof base!='number'){
                return this.reportError('base: '+base+' is type '+typeof base);
            }
            if (base>=this.digitReference.length){
                return this.reportError('cannot convert base greater than: '+this.digitReference.length);
            }
            
            var newvalue='';
            while(value>=base){
                var r=value%base;
    			value=Math.floor(value/base);
                newvalue=this.digitReference.charAt(r)+newvalue;
            }
            if (value){
                newvalue=this.digitReference.charAt(value)+newvalue;
            }
            if (base<=10){
                return parseInt(newvalue);
            } else {
                return newvalue;
            }
        },
        hex:function(number){
            return this.baseConvert(number,16);
        },
        octal:function(number){
            return this.baseConvert(number,8);
        },
        binary:function(number){
            return this.baseConvert(number,2);
        }
    }
);

String.prototype.extend(
    {
        urlencode:function(){
            var value=this.valueOf();
            return (!value)?'':escape(value);
        },
        urldecode:function(){
            var value=this.valueOf();
            return (!value)?'':unescape(value);
        },
        htmlencode:function(){
            var div = document.createElement('div');
            var text = document.createTextNode(this);
            div.appendChild(text);
            return div.innerHTML;
    	},
        ucwords:function(){
            var value=new String();
            if (this.length){
                for(var c=0;c<this.length;c++){
                    var character=this.charAt(c);
                    if ((c==0) ||
                        (c && this.charAt(c-1).match(/[^a-z]/i))
                    ){
                        value+=character.toUpperCase();
                    } else {
                        value+=character;
                    }
                }
            }
            return value;
        },
        trimLeft:function(){
            var value=this.valueOf().replace(/^[\s\t\r\n\v]+/,'');
            return value;
        },
        trimRight:function(){
            var value=this.valueOf().replace(/[\s\t\r\n\v]+$/,'')
            return value;
        },
        trim:function(){
            var value=this.trimLeft();
            return value.trimRight();
        },
        truncate:function(limit,append){
            limit=this.typeNumber(limit)?parseInt(limit):0;
            var str=this.valueOf(),
                append=this.typeString(append)?append:'';
            if ((limit>0) && (str.length>limit)){
                str=this.slice(0,limit)+append;
            }
            return str;
        }
    }
);


Date.prototype.extend(
    {
        isDate:true,
        _wkString:['sun','mon','tues','wed','thur','fri','sat'],
        _weekString:['sunday','monday','tuesday','wednesday','thursday','friday','saturday'],
        _mnthString:['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'],
        _monthString:['january','february','march','april','may','june','july','august','september','october','november','december'],
        getMaxDays:function(){
    		var month=this.getMonth(),
	    		year=this.getFullYear(),
		    	maxMonths=[31,(year%4)?29:28,31,30,31,30,31,31,30,31,30,31];
    		return maxMonths[month];
	    },
        getTimestamp:function(){
            return Math.round(this.getTime()/1000.0);
        },
        setTimestamp:function(time){
            var time=parseInt(time);
            if (!isNaN(time)){
                this.setTime(time*1000.0);
            }
        },
        format:function(format,timestamp){
    		if (!this.typeString(format)){
	    		return false;
            }
            
            if (this.typeNumber(timestamp) &&
                (timestamp>=0)
            ){
	    		this.setTime(timestamp);
            }
            var time={
                'a':(this.getHours()<12)?'am':'pm',
                'A':(this.getHours()<12)?'AM':'PM',
                
                'd':this.getDate(),
                'D':this._wkString[this.getDay()]||'',
                'F':this._monthString[this.getMonth()],
                
                'h':((this.getHours()%12)+1),
                'H':this.getHours(),
                'i':this.getMinutes(),
                
                'l':this._weekString[this.getDay()]||'',
                'L':!(this.getFullYear()%4),
                'm':(this.getMonth()+1),
                'M':this._mnthString[this.getMonth()],
                
                'O':this.getTimezoneOffset(),
                'N':this.getDay()?(this.getDay+1):'',
                's':this.getSeconds(),
                'u':this.getTime(),
                'w':this.getDay(),
                'y':this.getYear(),
                'Y':this.getFullYear()
            }
            
            var newFormat='';
            for(var c=0;c<format.length;c++){
                var chr=format.charAt(c);
                if (typeof time[chr]!='undefined'){
                    newFormat+=time[chr];
                } else {
                    newFormat+=chr;
                }
            }
            
            return newFormat;
        }
    }
);

/*
*   INITIAL DOM
*/
window.loaded=false;
window.onload=function(){
    this.loaded=true;
}


if (document){
    document.getElementsByClassName=function(className,tagName){
        if (className && (typeof className=='string')){
            var tag=(tagName && (typeof tagName=='string'))?tagName:'*',
                elements=document.getElementsByTagName && document.getElementsByTagName(tag),
                found=new Array();
            for(var c=0;c<elements.length;c++){
                if (elements[c] && (elements[c].className==className)){
                    found[found.length]=elements[c];
                }
            }
            return found;
        }
    }
}

/*
*   BASE CLASS
*/

window.Class={
    isClass:true,
    _className:'Class',
    create:function(name,initialize){
        var classObject=name &&
            (typeof name=='string') &&
            function(){
                var parameters=this.convertToArray(arguments);
                if (typeof this.initialize=='function'){
                    this.initialize.apply(this,parameters);
                } else {
                    this.reportError('constructor of: '+this._className+' do not exist or not a function');
                }
            };

        if (classObject){
            this[name]=classObject;
        } else {
            return this.reportError('invalid class name: '+name);
        }
        this[name].include(this,
            ['_className','create','isClass']
        );
        
        this[name]._className=this._className+'.'+name;
        this[name].declare=this[name].inherits;
        this[name].inherits(
            {
                initialize:new Function(),
                _className:this[name]._className,
                _class:this[name],

                //-- Object Messenging
                lastState:null,
                setObjectState:function(name,parameter){
                    if (name && this.typeString(name)){
                        var state={
                            name:name,
                            parameter:parameter
                        };
                        
                        this.lastState=state;
                        
                        //-- activate
                        if (typeof this.onchange=='function'){
                            this.onchange(state);
                        }
                        
                    }
                }
                
            }
        );
        //-- module require for Class.Application
        this[name]._requires=new Array();
        this[name].isModuleName=function(name){
            return name && (typeof name=='string') && name.match(/^[a-zA-Z]+(\.[a-zA-Z]+)*$/);
        }
        this[name].requireModule=function(name){
            if (this.isModuleName(name)){
                return this._requires[this._requires.length]={
                    name:name,
                    type:'module'
                }
            } else {
                this.reportError('requiring invalid module name: '+name);
            }
        }
        this[name].requireUserModule=function(name){
            if (this.isModuleName(name)){
                return this._requires[this._requires.length]={
                    name:name,
                    type:'user-module'
                }
            } else {
                this.reportError('requiring invalid module name: '+name);
            }
        }
        
    }
};

Class.loadModule('Browser');
Class.loadModule('Dom');