(function() 
{
    function init() {
        if (!!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1)) {
            this.settings.browserType ='IE'
        } else if (navigator.userAgent.indexOf('Opera') > -1) {
            this.settings.browserType ='opera'
        } else if (navigator.userAgent.indexOf('AppleWebKit/') > -1) {
            this.settings.browserType ='WebKit'
        } else if (!!navigator.userAgent.match(/Apple.*Mobile.*Safari/)) {
            this.settings.browserType ='mobileSafari'
        } else {
            this.settings.browserType ='gecko';
        }
    }

    this.settings = {
        browserType: false
    }

    this.op = function() {
        return new this.op.prototype.constructor(arguments)
    }

    this.op.prototype = {
        constructor: function() 
        {
            var thing

            arguments = arguments[0]

            if (!arguments.length) {
                return null
            }
            
            thing = arguments[0] || document

            if (thing.nodeType) {
                this.obj = thing
            } else if (typeof(thing) === 'string') {
                if (thing.charAt(0) === '#') {
                    this.obj = document.getElementById(thing.substr(1))
                } else {
                    parentObj = op(arguments[1]).obj || document
                    var objs = parentObj.getElementsByTagName(thing)

                    var ret = new Array;
                    for(var i = 0;i < objs.length; ++i) {
                        ret[i] = op(objs[i])
                    }
                    return ret
                }
            } else if (thing.imanop) {
                return thing
            } else if (typeof(thing) === 'object') {
                this.obj = thing
            }

            return this
        },
            /* its me */
        imanop: true,

            /* base object functions */
        clone: function()
        {
            var ret = new Object
            for (var property in this.obj) {
                ret[property] = this.obj[property]
            }

            return ret
        },

        asArray: function()
        {
            var arr = new Array()

            for(var i = 0; this.obj[i] != undefined; ++i) {
                arr[i] = this.obj[i]
            }

            return arr
        },

            /* events */
        eventTypes:
        {
            'IE': {'DOMContentLoaded': 'readystatechange'}
        },

        uniformEvent: function(event) 
        {
            if (this.eventTypes[settings.browserType] !== undefined && 
                    this.eventTypes[settings.browserType][event] !== undefined) {
                return this.eventTypes[settings.browserType][event]
            }
            return event;
        },

        listenForEvent: function(event, func)
        {
            if (this.obj.addEventListener) {
                this.obj.addEventListener(this.uniformEvent(event), func, false)
            } else {
                this.obj.attachEvent("on" + this.uniformEvent(event), func)
            }
        },

        stopEventListening: function(event, func)
        {
            if (this.obj.removeEventListener) {
                this.obj.removeEventListener(this.uniformEvent(event), func, false)
            } else {
                this.obj.detachEvent("on" + this.uniformEvent(event), func)
            }
        },

            /* loaded? */
        loaded: false,
        imageUnloaded: false,

        imageLoaded: function() {
            --this.imageUnloaded
            if (!this.imageUnloaded) {
                this.loaded = true
                this.ready()
            }
        },

        doOnLoad: function() {
            if (this.obj.addEventListener || this.obj.readyState === "complete") {
                this.loaded = true
                this.ready()
            } else if (this.obj.documentElement.doScroll && this.obj == this.obj.top) {
                try {
                    this.obj.documentElement.doScroll("left")
                }
                catch(E) {
                    setTimeout(arguments.callee, 0)
                    return
                }
                this.loaded = true
                this.ready()
            }
        },
            /* executes function when or after element is loaded */
        ready: function() {
            if (this.loaded) {
                while(this.onLoadFunctions.length) {
                    this.onLoadFunctions.shift()()
                }
                if (arguments.length) {
                    arguments[0]()
                }
                return 
            }

            if (this.onLoadFunctions === undefined) {
                this.onLoadFunctions = new Array
                if (this.obj !== document) {
                    /* assume document is loaded already */
                    /* loaded if all image is loaded */
                    var images = op('img', this.obj)
                    var till = this.imageUnloaded = images.length

                    for(var i = 0; i < till; ++i ) {
                        if (images[i].obj.complete) {   /* image already loaded */
                            --this.imageUnloaded
                        } else {
                            images[i].listenForEvent('load', common.closure(this, this.imageLoaded))
                        }
                    }
                    if (!this.imageUnloaded) {  /* all image is already loaded */
                        this.loaded = true
                        this.ready(arguments[0])
                        return
                    }
                } else {
                    this.listenForEvent("DOMContentLoaded", common.closure(this, this.doOnLoad))
                }
            }
            this.onLoadFunctions.push(arguments[0])
        },

        /* DOM element properties */
            /* element dimensions */
        getLeft: function()
        {
        },

        getTop: function()
        {
        },

        getWidth: function()
        {
            if (this.obj.offsetWidth) {
                return this.obj.offsetWidth
            }
            else {
                return this.obj.style.pixelWidth
            }
        },

        getHeight: function()
        {
            if (this.obj.offsetHeight) {
                return this.obj.offsetHeight
            }
            else {
                return this.obj.style.pixelHeight
            }
        },

        getPosition: function()
        {
            return { left: this.getLeft(), top: this.getTop() }
        },

        getDimensions: function()
        {
            return { height: this.getHeight(), width: this.getWidth() }
        },

        getInnerHeight: function()
        {
            return this.getHeight() - (parseInt(this.getStyle("padding-top", 10)) +
                                        parseInt(this.getStyle("padding-bottom", 10)))
        },

        getInnerWidth: function()
        {
            return this.getWidth() - (parseInt(this.getStyle("padding-left", 10)) +
                                       parseInt(this.getStyle("padding-right", 10)))
        },

        getInnerDimensions: function()
        {
            return { innerHeight: this.getInnerHeight(), innerWidth: this.getInnerWidth(),
                      paddingTop: parseInt(this.getStyle("padding-top", 10)), 
                      paddingBottom: parseInt(this.getStyle("padding-bottom", 10)), 
                      paddingLeft: parseInt(this.getStyle("padding-left", 10)),
                      paddingRight: parseInt(this.getStyle("padding-right", 10))
                    }
        },

            /* styles */
        getStyle: function(styleName)
        {
            var val;

            if(document.defaultView && document.defaultView.getComputedStyle) {
                val = document.defaultView.getComputedStyle(this.obj, "").getPropertyValue(styleName)
            } else if(this.obj.currentStyle) {
                styleName = styleName.replace(/\-(\w)/g, 
                                function (strMatch, p1) {
                                    return p1.toUpperCase()
                                }
                )
                val = this.obj.currentStyle[styleName]
            }

            return val
        },
            /* visibility */
        hide: function()
        {
            this.obj.style.display = 'none';
        },

        show: function()
        {
            this.obj.style.display = '';
        },

        isHidden: function() {
            return this.obj.style.display == 'none';
        }
    }

    this.op.prototype.constructor.prototype = this.op.prototype;  

    init();


        /* common function definitions */
    this.common = {
        closure: function(obj, func) 
        {
            return function() { func.apply(obj, op(arguments).asArray().splice(0, 2)) }
        },

        /* tick */

        tick: function(requester, interval) 
        {
            this.ref = null
            this.requester = requester
            this.interval = interval
            this.tickCount = 0
        },
 
        /* popup */
        popup: function(name, href)
        {
            return window.open(href, name);
        }
    }

    this.common.tick.prototype = {
        start: function() 
        {
            this.ref = setInterval(common.closure(this, this.tick), this.interval)
        },

        stop: function() 
        {
            clearInterval(this.ref)
        },

        tick: function() 
        {
            this.tickCount++;
            this.requester.tick()
        }
    }

})()
