jQuery(document).ready(function($) {
    var AP = Array.prototype;
    AP.forEach = AP.forEach || function(fn, thisObj) {
        for (var i = 0, l = this.length; i < l; i++) {
            if (i in this) {
                fn.call(thisObj, this[i], i, this);
            }
        }
    };
    var FP = Function.prototype;
    FP.bind = FP.bind || function(context) {
            var args = AP.slice.call(arguments, 1),
            orig = this,
            res = function() {
                return orig.apply(this instanceof dummy ? this : context,
                                  AP.concat.call(args, AP.slice.call(arguments, 0)));
            },
            dummy = function() {};
            dummy.prototype = orig.prototype;
            res.prototype = new dummy();
            return res;
    };

    var extend = function(obj) {
        AP.forEach.call(AP.slice.call(arguments, 1), function(source) {
            for (var prop in source) obj[prop] = source[prop];
        });
        return obj;
    };
    
    var isFunction = function(obj) {
        return !!(obj && obj.call && obj.apply);
    };
    
    var isNumber = function(obj) {
        return (typeof obj === typeof 0); // suppress isFinite
    };
    
    var ease = {
        linear: function(x) { return x; },
        cubic: function(x) { return x*x*x; }
    };

    var Motion = function() {
        var queue = new Array();
        function next(shift) {
            if (shift || shift === undefined)
                queue.shift();
            if (queue.length) {
                var top = queue[0];
                if (top.callee)
                    top.tid = setTimeout(top.delay ? step : function() {
                        top.callee(queue);
                        next();
                    }, 0);
                else
                    top.tid = setTimeout(next, top.delay);
            };
        }
        function step() {
            var top = queue[0];
            if (top.lt) {
               top.callee(top.from + (top.to - top.from) * top.ease(1 - top.lt / top.ticks), queue);
               top.tid = setTimeout(step, Motion.MSPF);
            } else {
               top.callee(top.to, queue);
               console.log("finish: ", queue);
               next();
            }
            top.lt--;
        };
        
        function push(obj) {
            if (queue.push(obj) == 1)
                next(false);
            return queue;
        };

        function complete(obj) {
            if (obj.callee) {
                if (!obj.delay)
                    obj.callee(queue);
                else {
                    obj.lt = 0;
                    obj.callee(obj.to, queue);
                };
            }
        }
        
        return extend(queue, {
            run: function(ms, options, func) {
                var opts = extend({
                    from: 0,
                    to: 1,
                    callee: func,
                    delay: ms,
                    ease: "linear"
                }, options);
                opts.lt = opts.ticks = Math.floor(ms / Motion.MSPF) + 1;
                if (!isFunction(opts.ease))
                    opts.ease = ease[opts.ease];
                return push(opts);
            },
            
            delay: function(ms) {
                return push({ delay: ms });
            },
            spike: function(func) {
                return push({ calee: func });
            },
            stop: function(all, finish) {
                if (this.length) {
                    var top = this[0];
                    if (top.tid)
                        clearTimeout(top.tid);
                    if (!all) {
                        if (finish)
                            complete(top);
                        next();
                    } else {
                        if (!finish)
                            this.splice(0, this.length);
                        else
                            while (this.length) {
                                complete(this.shift());
                            }
                    };
                }
                return this;
            }
            //pause: function(revive) {
            //}
        });
    };
    Motion.MSPF = 1000 / 30;  // 1/FPS * 1000
    
    function addEvent(elem, type, fn) {
	if (elem.addEventListener) {
            elem.addEventListener(type, fn, false);
            return fn;
        }
        var iefn = function() { fn.apply(elem, arguments); };
	elem.attachEvent('on' + type, iefn);
        return iefn;
    };

    var getElementsByClass = document.getElementsByClassName ? function(classes, node) {   
            return (node || document).getElementsByClassName(classes);
        } : function (classes, node) {
            node = node || document;
            var elements = node.getElementsByTagName('*'),
                res = [];
            classes = classes.split(/\s+/);
            for (var k = 0, lc = classes.length; k < lc; k++)
                classes[k] = "\\b" + classes[k] + "\\b";
            for (var i = 0, le = elements.length; i < le; i++)
                for (k = 0; k < lc; k++)
                    if (elements[i].className.search(classes[k]) != -1) {
                        res.push(elements[i]);
                        break;
                    }
            return res;
        };

    function fixEventTarget(event) {
        if (!event.target)
	    event.target = event.srcElement;
        if (!event.relatedTarget && event.fromElement)
	    event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

        return event;
    }

    function getStyle(el) {
        var style = window.getComputedStyle ? getComputedStyle(el, null) :
                                              el.currentStyle;
        if (arguments.length == 1)
            return style;
        for (var i = 1, res; i < arguments.length; i++) {
            res = style[arguments[i]];
            if (res)
                break;
        }
        if (/px$/.test(res))
            return parseFloat(res) || res;
        return res;
    }
    
    // --------------------------------------------------

    /* var menu = getElementsByClass("menu", getElementsByClass("page")[0])[0],
        moveMargin = function(offset) {
            this.style.marginTop = offset + "px";
        },
        clearLi = function(q) {
            this.removeAttribute("style");
            this.parentNode.removeAttribute("style");
            console.log(q);
        };

    for (var i = 0; i < menu.children.length; i++) {
        var item = menu.children[i];
        if (item.getElementsByTagName("ul").length) {
            item.animate = Motion();
            addEvent(item, "mouseover", function() {
                var ul = this.getElementsByTagName("ul")[0],
                    li = ul.getElementsByTagName("li")[0];
                if (this.animate.length > 2)
                    this.animate.stop(true);
                else {
                    ul.style.overflow = "hidden";
                    this.animate.run(200, {from: -getStyle(ul, "height"), to: 0, ease: "cubic"}, moveMargin.bind(li))
                        .spike(clearLi.bind(li));
                }
            }
            );

            addEvent(item, "mouseout", function() {
                var ul = this.getElementsByTagName("ul")[0],
                    li = ul.getElementsByTagName("li")[0];
                ul.style.visibility = "visible";
                this.animate.delay(300).spike(function () { ul.style.overflow = "hidden"; })
                    .run(200, {from: 0, to: -getStyle(ul, "height"), ease: "cubic"}, moveMargin.bind(li))
                    .spike(clearLi.bind(li));
            });
        }
    };*/
});

