var joy = {
        /* count next size at tick count for various styles */
    setSizeAtTick: function(dimOrig, dimAt, attributes, tick, speed, style, way)
    {
        /* TODO: styles */
        var at, change

        at = (100 * tick) / speed;

        if (at > 85) {
            change = 170;
        } else if (at > 70) {
            change = 140;
        } else if (at > 40) {
            change = 110;
        } else {
            change = 80;
        }

        if (typeof(attributes) == 'string') {
            attributes = Array(attributes)
        }

        for(var i = 0; i < attributes.length; ++i) {
            dimAt[attributes[i]] += (((dimOrig[attributes[i]] * change) / 100) / speed) * way
        }

        return dimAt
    },

        /*
         * closes an element over time
         */
    dimSlider: function(element, slideSpeed, slideWay, slideStyle, changeWay, endingFunc) 
    {
        this.element = op(element)
        this.way = slideWay
        this.style = slideStyle
        this.speed = slideSpeed
        this.changeWay = (changeWay == 'open' ? 1 : -1)
        this.callAtEnd = endingFunc

        this.timer = new common.tick(this, 50)
    },

    ulSlider: function(element, slideSpeed, slideWay, endingFunc)
    {
        this.element = op(element)
        this.way = slideWay
        this.speed = slideSpeed
        this.callAtEnd = endingFunc
    }
}

/* prototypes */

    /* dimSlider */

joy.dimSlider.prototype = {
    start: function()
    {
        this.element.ready(
            common.closure(this, function() {
                this.element.obj.style.overflow = 'hidden'

                if (this.changeWay == 1 && this.element.isHidden()) {
                    this.element.show()
                    this.dimOrig = this.element.getDimensions()
                    this.element.obj.style.height = 0
                } else {
                    this.dimOrig = this.element.getDimensions()
                }
                this.dimAt = op(this.dimOrig).clone()
                this.timer.start()

                if (this.changeWay == 1) {
                    this.dimAt.height = 0
                }
            })
        )
    },
    
    stop: function()
    {
        this.timer.stop();
        if (this.changeWay == -1) {
            this.element.hide();
        }
        this.element.obj.style.height = '';
        if (typeof(this.callAtEnd) == "function") {
            this.callAtEnd(this.element);
        }
    },

    tick: function(obj) 
    {
        var newSize;

        if (this.timer.tickCount == this.speed) {
            this.stop();
            return
        }

        this.dimAt = joy.setSizeAtTick(this.dimOrig, this.dimAt,
                                       'height',
                                       this.timer.tickCount, this.speed, this.style, 
                                       this.changeWay)

        if (this.dimAt.height < 0.1) {
            this.stop()
            return
        }

        this.element.obj.style.height = this.dimAt.height + 'px'
    }
}

    /* ulSlider */

joy.ulSlider.prototype = {
    startTreeBottomReq: function(parent)
    {
        var uls, lUls, found

        lUls = (uls = op('ul', parent)).length

        found = false
        for(var i = 0; i < lUls; ++i) {
            if (uls[i].obj.parentNode.parentNode !== parent.obj) {
                continue;
            }
            this.startTreeBottomReq(uls[i])
            found = true
        }
        
        if (!found) {
            (new joy.dimSlider(parent, this.speed, this.way, 
                                 'accelerate', 'close',
                                 common.closure(this, this.finishedOne))).start()
            return
        }
    },

    start: function()
    {
        if (this.element.isHidden()) {
            new joy.dimSlider(this.element, this.speed, this.way,  
                              'accelerate', 'open',
                              common.closure(this, this.finishedOne)).start()
        } else {
            this.startTreeBottomReq(this.element)
        }
    },

    finishedOne: function(opObj)
    {
        var next, list

        if (opObj.obj == this.element.obj) {
            if (typeof(this.callAtEnd) == "function") {
                this.callAtEnd(this.element);
            }
            return
        }

        next = opObj.obj.parentNode.parentNode
        lUls = (uls = op('ul', next)).length

        for(var i = 0; i < lUls; ++i) {
            if (uls[i].obj.style.display != "none") {
                return
            }
        }

        (new joy.dimSlider(opObj.obj.parentNode.parentNode, this.speed, this.way, 
                             'accelerate', 'close', this.finishedOne)).start()
    }
}

