﻿/// <reference path="~/js/jquery-1.3.2.js" />

jQuery.sequencedFade = function (selector, params, config) {

    var group = (selector.jquery != undefined) ? selector : $(selector); // is jQuery?
    var count = group.length - 1;

    var ElementComplete = (jQuery.isFunction(config.elementCompleted)) ? config.elementCompleted : null;
    var Tollerance = config.tollerance || 0.15;

    group.each(function (i, el) {

        $(el)
            .animate(
                { empty: count },
                {
                    queue: "__Qx1", duration: (i * config.delay0),
                    complete: function () {
                        if (ElementComplete != null)
                            ElementComplete(this);

                        $(this).animate(
                            params,
                            {
                                duration: config.duration + (i * config.delay1),
                                tollerance: 0.15, count: 1,
                                group_complete: function () {
                                    if (i == count && jQuery.isFunction(config.complete))
                                        config.complete();
                                }
                            }
                        );

                    }
                }
            );

    });

};

jQuery.fn.sequencedAnimation = function (config, stepThreshold, callback, callback_completed) {

    var d0 = config.duration * stepThreshold;
    var pause = 0;
    var queue = this;
    var count = this.length;
    var tessel = 0;

    var call0 = jQuery.isFunction(callback) ? callback : OMAA.Stage.EventNull;
    var call1 = jQuery.isFunction(callback_completed) ? callback_completed : OMAA.Stage.EventNull;

    return this.each(function () {
        $(this).animate({ empty: 1 }, { duration: pause += d0 })
        $(this).animate({ empty: 2 }, { duration: config.duration, complete: function () {
            call0(this);
            if (++tessel >= count) {
                $(this).delayed(5, function () { call1(queue); });
            }
        }
        });
    });

};

jQuery.fn.delayed = function (ms, callback) {
    var call0 = jQuery.isFunction(callback) ? callback : OMAA.Stage.EventNull;
    return $(this).animate({ empty: new Math.random() }, { duration: ms, complete: callback });
};


jQuery.fn.disabled = function (state) {
    if (state == undefined)
        return !this.enabled();
    else
        return this.enabled(!state);
};
jQuery.fn.enabled = function (state) {
    if (state == undefined)
        return (this.attr("disabled") != "disabled");
    else {
        if (state)
            return this.removeAttr("disabled");
        else
            return this.attr("disabled", "disabled");
    }
    return this.upadteStatus(state);
};
jQuery.fn.upadteStatus = function (state) {
    if (this.IsStaticButton())
        return this;

    if (state == undefined || state == false)
        this.triggerHandler("mouseleave");
    else
        this.triggerHandler("mouseenter");

    return this;
};

jQuery.fn.IsStaticButton = function () {
    return (this.data("static") == 1);
};

jQuery.fn.static = function (state) {

    this.stop(true, false).unbind("mouseenter mouseleave").removeAttr("disabled").css({ opacity: null });

    if (!state) {
        this.removeData("static");
        this.enabled(false).ButtonState("on");
        return this;
    }

    this.data("static", 1);
    this.enabled(true).ButtonState("on");

    return this.defaultHover();

};

jQuery.fn.toggle = function (el, state) {

    if (window._omaa_oldtoggle) {
        var old_el = window._omaa_oldtoggle
        old_el.data("toggle:state", false).ButtonState("off");
    }
    else
        this.not(el).data("toggle:state", false).ButtonState("off");

    window._omaa_oldtoggle = el.data("toggle:state", true).ButtonState("on");

    return this;
};

jQuery.fn.isToggle = function () {
    return ($(this).data("toggle") == 1);
};

jQuery.fn.isToggled = function () {
    return ($(this).data("toggle:state") == true);
};

jQuery.fn.toToggleButtons = function (creationState, originalStatus, contextToggledOnId) {

    creationState = creationState || true;
    originalStatus = originalStatus || false;

    window._omaa_oldtoggle = null;

    if (creationState) {
        var st2 = (originalStatus) ? "on" : "off";
        for (var i = 0; i < this.length; i++) {
            $(this).data("toggle", 1).ButtonState(st2).enabled(true);
        }
    }
    else {
        for (var i = 0; i < this.length; i++) {
            $(this).removeData("toggle").removeData("toggle:state").ButtonState("off").enabled(true);
        }
    }

    if (contextToggledOnId != undefined) {
        window._omaa_oldtoggle = $("#" + contextToggledOnId).ButtonState("on").enabled(true);
    }

    return this;

};

jQuery.fn.RemoveHover = function (state) {
    state = (state == undefined) ? "off" : state;
    return this.enabled(false).unbind("mouseenter mouseleave").ButtonState(state);
};

function Btn_MouseOver(event) {

    var el = $(this);
    if (el.data("mouse:internal") !== undefined)
    { }
    else if (!event.isImmediatePropagationStopped())
		event.stopImmediatePropagation();

	if (!el.enabled()) return;
    if (el.isToggle()) {
        el.ButtonState("on");
        return;
    }
    el.ButtonState("on");
};

function Btn_MouseOut(event) {

    var el = $(this);
    if (el.data("mouse:internal") !== undefined)
    { }
    else if (!event.isImmediatePropagationStopped())
		event.stopImmediatePropagation();
        
    var el = $(this);
    if (!el.enabled()) return;
    if (el.isToggle()) {
        if (!el.isToggled())
            el.ButtonState("off");
        return;
    }
    el.ButtonState("off");
};

function Btn_MouseClick(event) {

    if (!event.isImmediatePropagationStopped())
        event.stopImmediatePropagation();

    var el = $(this);
    if (!el.enabled()) return;

    var callback = el.data("click:internal");
    callback(el);
};

jQuery.fn.ButtonState = function (name) {
    this.children("img").css({
        left: this.data(name)
    });
    return this.css({ opacity: null });
};

jQuery.CreateButtons = function (Buttons, callback_done) {

    var groupSelector = new Array();

    var cssNow = {
        position: "relative",
        top: 0,
        left: -64,
        width: "auto",
        height: stage.settings.tassels.h
    };

    $(Buttons).each(function () {

        var on = (this.on == undefined) ? 0 : this.on;
        var off = (this.off == undefined) ? -64 : this.off;

        cssNow.left = off;
        var btn = $("<img />")
                    .attr("src", this.img)
                    .css(cssNow);

        var Tassel = $(":tassel(" + this.tassel + ")");

        //console.log(this.tassel);

        Tassel
			.attr("disabled", "")
			.data("on", on).data("off", off).data("key", OMAA.Tessels.GenerateKey(this.key))
			.hover(Btn_MouseOver, Btn_MouseOut)
			.append(btn);

        if (jQuery.isFunction(this.click)) 
		{
            Tassel.click(Btn_MouseClick).data("click:internal", this.click); // bind("click:internal", Tassel, this.click);
        }

        if (jQuery.isFunction(this.mouseover)) 
		{
            Tassel.mouseover(this.mouseover).data("mouse:internal", true);
        }

        if (jQuery.isFunction(this.mouseout)) 
		{
            Tassel.mouseout(this.mouseout).data("mouse:internal", true);
        }

        groupSelector.push(Tassel);

    });

    if (jQuery.isFunction(callback_done)) {
        callback_done();
    }

    return groupSelector;
};

jQuery.extend(jQuery.expr[":"], {

    tassel: function (elem, i, match, array) {

        if (elem.tagName != "DIV")
            return false;

        if (!OMAA.Tessels.validFast(elem)) // | !OMAA.Tessels.valid(elem))
            return false;

        if (match[3] == undefined || (typeof (match[3]) == "string" && match[3].length < 1))
            return true;
        else {
            var currentTasseID = elem.id.substring(2).toUpperCase();
            return match[3].toUpperCase().indexOf(currentTasseID) != -1;
        }
    }

});

jQuery.fn.moveTasselTo = function (old_coord, new_coord, speed, queueName) {

    var old_position = OMAA.Tessels.FromCoordToPos(old_coord);
    var position = OMAA.Tessels.FromCoordToPos(new_coord);
    if (!position | !old_position)
        return $(this);

    //    speed = speed || "slow";

    var deltaX = Math.abs(position.left - old_position.left);
    var deltaY = Math.abs(position.top - old_position.top);

    return $(this)
        .animate({ left: position.left }, { duration: speed, queue: queueName })
        .animate({ top: position.top }, { duration: speed, queue: queueName });
};

jQuery.fn.moveTasselDirect = function (destination) {

    //var queueName = config.queue || "global";

    var old_coord = this.data("ts");
    var new_coord = OMAA.Tessels.getDestination(this, destination);
    if (new_coord == old_coord)
        return this;

    this.data("ts", new_coord);
    var position = OMAA.Tessels.FromCoordToPos(new_coord);

    return this.css({ left: position.left, top: position.top });

};


jQuery.fn.Position = function () { return $(this).data("ots"); };

jQuery.fn.GetKey = function () { return $(this).data("key"); };

jQuery.fn.moveTassel = function (config) {

    var queueName = config.queue || "global";
    var callback_start = config.start || OMAA.Stage.EventNull;
    var callback_complete = config.complete || OMAA.Stage.EventNull;
    var speed = config.speed || "normal";

    return this.each(function () {

        var id = this.id;
        var currentTassel = $(this);

        var pos = currentTassel.data("ts");

        if (speed > 0) {
            currentTassel
            .animate({ blank: 1 }, { duration: 0, queue: queueName, complete: function () {
                $(this).triggerHandler("omaa.moveBegin");
                callback_start(currentTassel, pos, id);
            }
            });
        }

        for (var i = 0; i < config.newDestination.length; i++) {

            var destination = config.newDestination[i];

            if (destination instanceof Object) {
                var op = OMAA.Tessels.ActionOnMove(currentTassel, pos, id, queueName, destination);

                if (typeof op != "string")
                    continue;
                destination = op;
            }

            var np = OMAA.Tessels.getDestination(currentTassel, destination);
            if (np == pos)
                continue;

            currentTassel.moveTasselTo(pos, np, speed, queueName);

            pos = np;
        }

        if (speed > 0) {
            currentTassel.data("ts", pos)
            .animate({ blank: 1 }, { duration: 0, queue: queueName, complete: function () {
                $(this).triggerHandler("omaa.moveDone");
                callback_complete(currentTassel, pos, id);
            }
            });
        }
    });

};


//jQuery.OMAA = {};
window.OMAA.Tessels = {

    _rex_IsValid: /^ts[A-Z]+\d+$/,

    GenerateKey: function (key) {

        if (!key || key == undefined || key.length < 1)
            return null;

        if (key.indexOf('.') != -1) {
            key = key.substring(0, key.lastIndexOf('.'));
        }

        return key.toLowerCase();
    },

    Clear: function (callback, selector, speed) {

        speed = speed || 1000;
        selector = selector || ":tassel:not(:tassel(a1))";

        $(selector).remove();
        OMAA.Stage.background.hide().appendTo("body").empty();

        if (jQuery.isFunction(callback))
            callback();

    },

    OnProcessAction: function (currentTassel, pos, id, action) {

        if (action.css != undefined) {
            //$.extend(currentTassel.css, css);
            currentTassel.css(action.css);
        }

        if (action.pos != undefined)
            return action.pos;

        return true;
    },

    ActionOnMove: function (currentTassel, pos, id, queueName, action) {
        // { pos: "A2", onlyfor: "a1", css: { border: "red"} }

        if (action.onlyfor && id.substring(2).toUpperCase() != action.onlyfor.toUpperCase())
            return false;

        if (action.delay) {

            var ms = action.delay;
            action.delay = null;

            try {

                queueName = queueName || "global";
                currentTassel
                    .animate({ blank: 1 }, { duration: ms, queue: queueName, complete: function () {
                        return OMAA.Tessels.OnProcessAction(currentTassel, pos, id, action);
                    }
                    });
            }
            catch (e) {
                console.error(e);
            }

            return false;
        }

        return OMAA.Tessels.OnProcessAction(currentTassel, pos, id, action);
    },

    validFast: function (elem) {

        return elem && elem.id && this._rex_IsValid.test(elem.id);
        //return (/[A-Z][A-Z]*[1-9]\d*/gim).test(id);
    },

    valid: function (elem) {

        return (jQuery.data(elem, "ts") != undefined);
        //return (/[A-Z][A-Z]*[1-9]\d*/gim).test(id);
    },

    toID: function (arg) {
        if (arg)
            return arg[1].toUpperCase() + arg[2];
        return null;
    },

    FromColToValue: function (col) {

        col = col.toUpperCase();

        var v = 0;
        for (var i = 0; i < col.length; i++) {
            var p = (col.charCodeAt(col.length - i - 1) - 64);
            var m = Math.pow(this.baseN, i);
            v += p * m;
        }

        return v;
    },

    FromCoordToColRow: function (coord) {

        try {
            var tmp = this.FromNamedToColRow(coord);
            if (tmp != null)
                return tmp;

            var nt = null;
            var re = /([A-Z][A-Z]*)([1-9]\d*)/i;
            nt = re.exec(coord);
            if (!nt)
                return null;

            var col = this.FromColToValue(nt[1]);
            if (col < 1 || col > stage.settings.tassels.nX)
                return null;

            var row = parseInt(nt[2], 10);
            if (row < 1 || row > stage.settings.tassels.nY)
                return null;

            return { col: col, row: row };

        } catch (e) {
            console.error("FromCoordToColRow: %s", e);
        }

        return null;
    },

    FromNamedToColRow: function (namedValue) {

        if (namedValue == undefined || namedValue == null || namedValue.length < 2 || namedValue.charAt(0) != "{")
            return null;

        namedValue = new String(namedValue);
        var re = /^\s*(\{)\s+|\s+(\})\s*$|(\s)\s+/g;
        namedValue = namedValue.replace(re, "$1$2$3").toLowerCase();

        switch (namedValue) {
            case "{home}":
            case "{top left}":
            case "tl":
                return { col: 1, row: 1 };

            case "{top right}":
            case "tr":
                return { col: stage.settings.tassels.nX, row: 1 };

            case "{bottom right}":
            case "br":
                return { col: stage.settings.tassels.nX, row: stage.settings.tassels.nY };

            case "{bottom left}":
            case "bl":
                return { col: 1, row: stage.settings.tassels.nY };
        }
        return null;
    },

    FromColRowToCoord: function (c, r) {

        var colRowValue = this.FromNamedToColRow(c);
        var M = (colRowValue == null) ? c : colRowValue.col;

        var stack = new Array();
        while (M > window.OMAA.Tessels.baseN) {
            var p = M % window.OMAA.Tessels.baseN;
            stack.push(String.fromCharCode(64 + p));
            M = M / window.OMAA.Tessels.baseN;
        }
        if (M > 0)
            stack.push(String.fromCharCode(64 + M));

        return stack.reverse().join('') + colRowValue.row;
    },

    FromCoordToPos: function (coord) {
        var cr = this.FromCoordToColRow(coord);
        if (!cr)
            return null;

        return this.FromColRowToPos(cr.col, cr.row);
    },

    FromColRowToPos: function (col, row) {

        return {
            left: stage.settings.padding.L + stage.settings.margins.x + (col - 1) * stage.settings.tassels.W  /*(stage.settings.tassels.w + stage.settings.margins.H)*/,
            top: stage.settings.padding.T + stage.settings.margins.y + (row - 1) * stage.settings.tassels.H /*(stage.settings.tassels.h + stage.settings.margins.V)*/
        };
    },

    ToRightAlignment: function (coord) {
        if (coord != undefined && coord != null) {
            coord.right = coord.left - stage.settings.tassels.w;
            coord.left = null;
        }
        return coord;
    },

    OffsetRect: function (rect, dx, dy, calculateWithMargins) {

        calculateWithMargins = calculateWithMargins || false;

        if (rect.right)
            rect.right += dx * stage.settings.tassels.W;
        else
            rect.left += dx * stage.settings.tassels.W;

        if (rect.bottom)
            rect.bottom += dy * stage.settings.tassels.H;
        else
            rect.top += dy * stage.settings.tassels.H;

        rect.width -= 2 * dx * stage.settings.tassels.W;
        rect.height -= 2 * dy * stage.settings.tassels.H;

        if (calculateWithMargins == true) {
            dx = (dx == 0) ? 0 : (dx > 0) ? 1 : -1;
            dy = (dy == 0) ? 0 : (dy > 0) ? 1 : -1;

            //            console.log(stage.settings.margins.H, stage.settings.margins.V, stage.settings.margins.y);

            rect.left += dx * stage.settings.margins.H;
            rect.width -= 2 * dx * stage.settings.margins.H;

            rect.top += dy * stage.settings.margins.V;
            rect.height -= (2 * dy * stage.settings.margins.V + stage.settings.margins.y);
        }

        return rect;
    },

    MakeRect: function (tl, br, rightAlignment) {

        rightAlignment = rightAlignment || false;

        var coordTL = this.FromCoordToPos(tl);
        var coordBR = this.FromCoordToPos(br);
        var w = coordBR.left - coordTL.left + stage.settings.tassels.w;
        var h = coordBR.top - coordTL.top + stage.settings.tassels.h;

        if (rightAlignment == true) {
            coordTL = OMAA.Tessels.ToRightAlignment(coordTL);
        }

        return jQuery.extend(coordTL, { width: w, height: h });
    },

    OnAnimationBegin: function () {
        //console.info("%s %s", "OnAnimationBegin", this.id);
        $(this).css("zIndex", 101);
    },

    OnAnimationComplete: function () {
        //console.warn ("%s %s", "OnAnimationComplete", this.id);
        $(this).css("zIndex", 101).css("background", "red");
    },

    getDestination: function (source, path) {
        if (!path || path == "" || path == "-") {
            return source.data("ots");
        }
        else if (path == "home") {
            return "A1";
        }
        return path;
    },

    createTassels: function (config) {

        config.position = config.position.toUpperCase();
        //var size = { width: stage.settings.tassels.w - stage.settings.margins.x, height: stage.settings.tassels.h - stage.settings.margins.y };
        var size = { width: stage.settings.tassels.w, height: stage.settings.tassels.h };
        var staticElementIdx = config.static;

        config.css = jQuery.extend(config.css, size);

        var nt;
        var re = /([A-Z][A-Z]*)([1-9]\d*)/gim;

        var createdTassels = new Array();
        var idx = 0;

        while ((nt = re.exec(config.position)) != null) {

            var id = "ts" + nt[0];
            if ($("#" + id).size() > 0) { // DO NOT DUPLICATE!!!
                console.log("dup!", id);
                continue;
            }

            var col = this.FromColToValue(nt[1]);
            if (col < 1 || col > stage.settings.tassels.nX)
                continue;

            var row = parseInt(nt[2], 10);
            if (row < 1 || row > stage.settings.tassels.nY)
                continue;

            var position = this.FromColRowToPos(col, row);
            var css = jQuery.extend(config.css, position);

            var Tassel_front;

            //            Tassel.css("background", "url(images/1x1.png?" + getRandomArbitary(1, 100) + ") 0% 0% repeat scroll");
            //css = jQuery.extend(css, { background: "url(images/1x1.png) transparent 0% 0% repeat scroll" });

            var Tassel = $("<div />").attr("id", id)
                .addClass("tassel").css(css)
                .data("ots", nt[0]).data("ts", nt[0])
                .bind("omaa.moveBegin", this.OnAnimationBegin)
                .bind("omaa.moveDone", this.OnAnimationComplete);

            Tassel.appendTo(OMAA.Stage.div);

            if (staticElementIdx != undefined) {
                if (idx++ == staticElementIdx) {
                    staticElementIdx = undefined;
                    Tassel.static(true);
                }
            }

            createdTassels.push(jQuery(Tassel));
        }

        if (jQuery.isFunction(config.done)) {
            config.done(createdTassels);
        }

        return createdTassels;
    }

};

window.OMAA.Tessels.baseN = "Z".charCodeAt(0) - 64;

