var MooColumns = new Class({
    Implements: Options,
    options: {
        selector: ".multiColumn",
        className: "multiColumn",
        numOfColumns: 2,
        defaultNumOfColumns: 2,
        gutterWidth: 5,
        gutterClassName: "gutter",
        columnClassName: "column",
        tweak: {
            x: 0,
            y: 0,
            width: 0
        },
        splittableElements: ["span", "ul"],
        morePrecise: true,
        tolerance: 10,
        colBreaksTrump: true,
        debug: false
    },
    sizerElWrapper: null,
    columnParents: [],
    mooColumnsAreasArr: [],
    initialize: function(A) {
        this.setOptions(A);
        if ($type(parseFloat(this.options.numOfColumns)) != "number") {
            this.options.numOfColumns = this.options.defaultNumOfColumns
        }
        this.sizerElWrapper = new Element("div", {
            id: "sizerElWrapper"
        }).inject(document.body, "inside").setStyles({
            visibility: "hidden",
            position: "absolute",
            display: "block",
            padding: 0,
            margin: 0,
            top: 0,
            left: 0,
            width: 0,
            height: 0,
            overflow: "hidden"
        });
        this.columnParents = $(document.body).getElements(this.options.selector);
        this.columnParents.each(function(D, B) {
            var E = this.getOrSetId($(D));
            var C = new MooColumnsArea(this.options, D);
            this.mooColumnsAreasArr[E] = C;
            D.className += "-screen"
        }.bind(this))
    },
    getOrSetId: function(C) {
        if (!C.id) {
            var D = new Date();
            var B = D.getMilliseconds().toString();
            var A = Math.floor(Math.random() * 1000);
            if (C.nodeName) {
                C.id = C.nodeName.toString() + "-" + B + A.toString()
            } else {
                C.id = "element" + B + A.toString()
            }
        }
        return C.id
    }
});
var MooColumnsArea = new Class({
    Implements: Options,
    options: {
        parentEl: null,
        printEl: null,
        debug: null,
        colBreakDepth: 5
    },
    columnElsArr: [],
    gutterElsArr: [],
    colWidth: null,
    targetHeight: null,
    tempContentHolder: null,
    sizerEl: null,
    tallest: 0,
    unsplittableTags: ["td", "tr", "table", "tbody"],
    hasColBreaks: false,
    initialize: function(B, E) {
        this.setOptions(B);
        this.options.parentEl = E;
        this.sizerEl = new Element("div").inject($("sizerElWrapper"), "inside").setStyles({
            visibility: "hidden",
            position: "absolute",
            display: "block",
            padding: 0,
            margin: 0,
            top: 0,
            left: 0
        });
        this.options.printEl = new Element("div", {
            "class": this.options.className + "-print"
        }).inject(this.options.parentEl, "after").set("html", this.options.parentEl.innerHTML);
        this.options.parentEl.empty();
        var D = new Element("div").setStyles({
            display: "block",
            position: "relative",
            padding: 0,
            margin: 0
        }).inject(this.options.parentEl, "top");
        this.options.parentEl = E.getFirst();
        var C = D.getStyle("width").toInt() + this.options.tweak.width.toInt();
        var A = (100 * C) / D.getStyle("width").toInt();
        D.setStyles({
            width: A + "%",
            left: this.options.tweak.x
        });
        this.go();
        window.addEvent("resize",
        function() {
            $clear(F);
            var F = (function() {
                this.setHeights()
            }.bind(this)).delay(100)
        }.bind(this))
    },
    go: function() {
        var A = this.options.numOfColumns - 1;
        if (this.options.gutterWidth.toString().contains("px")) {
            this.options.gutterWidth = Math.round((100 * parseFloat(this.options.gutterWidth)) / this.options.parentEl.getCoordinates().width)
        }
        var B = Math.round(A * parseFloat(this.options.gutterWidth) / this.options.numOfColumns);
        this.colWidth = Math.round(100 / this.options.numOfColumns) - B;
        var C = Math.round((this.options.parentEl.getCoordinates().width * this.colWidth) / 100);
        this.sizerEl.setStyle("width", C).set("html", this.options.printEl.innerHTML);
        this.targetHeight = Math.round(this.sizerEl.getCoordinates().height / this.options.numOfColumns);
        this.makeWireFrame();
        this.options.printEl.set("html", this.options.printEl.get("html").stripScripts().split(/<!--[^(-->)]*-->/).join(""));
        this.wrapTextNodes(this.options.printEl);
        this.convertColBreaks(this.options.printEl);
        if ($(this.options.printEl).getElements(".colBreak").length > 0) {
            this.hasColBreaks = true
        }
        while (this.options.colBreakDepth > 0) {
            this.splitColBreakParents(this.options.printEl);
            this.options.colBreakDepth--
        }
        if (this.options.colBreaksTrump === true && this.hasColBreaks) {
            this.options.morePrecise = false
        }
        var D;
        if (this.hasColBreaks && this.options.colBreaksTrump) {
            D = this.divideContent2()
        } else {
            D = this.divideContent()
        }
        for (i = 0; i < D.length; i++) {
            this.columnElsArr[i].set("html", D[i].innerHTML)
        }
        if (this.options.morePrecise) {
            this.shaveColumns()
        }
        this.columnsContentArr = D;
        this.setHeights()
    },
    setHeights: function() {
        this.options.parentEl.setStyles({
            overflow: "hidden",
            height: "0"
        });
        this.tallest = 0;
        if (!this.options.debug) {
            for (i = 0; i < this.columnsContentArr.length; i++) {
                if (this.columnElsArr[i].getCoordinates().height > this.tallest) {
                    this.tallest = this.columnElsArr[i].getCoordinates().height
                }
            }
            if (this.options.parentEl.getScrollSize().y > 0) {
                this.tallest = this.options.parentEl.getScrollSize().y
            }
            for (i = 0; i < this.columnElsArr.length; i++) {
                this.columnElsArr[i].setStyles({
                    top: 0,
                    bottom: 0
                });
                this.options.parentEl.setStyle("height", this.tallest)
            }
            if (Browser.Engine.trident4) {
                this.options.parentEl.getParent().setStyle("height", this.tallest);
                this.gutterElsArr.each(function(B, A) {
                    B.setStyle("height", "100%")
                })
            }
        }
    },
    makeWireFrame: function() {
        this.options.parentEl.empty();
        for (i = 0; i < this.options.numOfColumns; i++) {
            colLeft = (i * (parseFloat(this.colWidth) + parseFloat(this.options.gutterWidth)));
            this.columnElsArr[i] = new Element("div", {
                "class": "column"
            }).inject(this.options.parentEl, "inside").setStyles({
                display: "block",
                position: "absolute",
                left: colLeft + "%",
                top: this.options.tweak.y,
                width: this.colWidth + "%"
            });
            if (i < this.options.numOfColumns - 1) {
                this.gutterElsArr[i] = new Element("div", {
                    "class": "gutter"
                }).inject(this.options.parentEl, "inside").setStyles({
                    display: "block",
                    position: "absolute",
                    left: (colLeft + parseFloat(this.colWidth) + "%"),
                    top: this.options.tweak.y,
                    width: parseFloat(this.options.gutterWidth) + "%",
                    bottom: 0
                });
                if (this.options.debug) {
                    this.gutterElsArr[i].setStyle("background", "yellow")
                }
            }
            if (this.options.debug) {
                this.columnElsArr[i].setStyle("background", "#eee")
            }
        }
        if (this.options.debug) {
            this.options.parentEl.setStyle("background", "#ccc")
        }
    },
    convertColBreaks: function(H) {
        var B = $(H).getElements("hr");
        for (var A = 0; A < B.length; A++) {
            var I = $(B[A]);
            var G = I.getNext() && I.getNext().get("tag") === "hr";
            var F = I.getNext() && I.getNext().get("tag") === "br" && I.getNext().getNext() && I.getNext().getNext().get("tag") === "hr";
            var E = I.getNext() && I.getNext().get("tag") === "p" && !I.getNext().get("html") && I.getNext().getNext() && I.getNext().getNext().get("tag") === "hr";
            var D = I.getNext() && I.getNext().getNext() && I.getNext().getNext().getNext() && I.getNext().get("tag") === "p" && I.getNext().getNext().get("tag") === "p" && I.getNext().getNext().getNext().get("tag") === "hr" && !I.getNext().get("html") && !I.getNext().getNext().get("html");
            if (D || E || F || G) {
                var C = new Element("span", {
                    "class": "colBreak"
                }).inject(I, "before");
                this.hasColBreaks = true
            }
            if (D) {
                I.getNext().getNext().getNext().dispose()
            }
            if (D || E || F) {
                I.getNext().getNext().dispose()
            }
            if (D || E || F || G) {
                I.getNext().dispose();
                I.dispose()
            }
        }
    },
    splitColBreakParents: function(A) {
        $(A).getElements(".colBreak").each(function(G, C) {
            if (!G.getParent()) {
                return
            }
            if (!G.getParent().hasClass("wrapper-print") && !this.unsplittableTags.contains(G.getParent().get("tag"))) {
                var E = G.getParent();
                var H = E.clone(false);
                if (!H || H.hasClass("colBreak")) {
                    return
                }
                var I = $(E).childNodes;
                var D = I[0];
                var B = 1;
                while (D && !D.className || D && D.className != "colBreak") {
                    if (D.parentNode.className && D.parentNode.className.contains("multi")) {
                        return
                    }
                    if ($type(D) === "textnode" || $type(D) === "whitespace") {
                        if (H && H.innerHTML && D.nodeValue) {
                            H.set("html", H.get("html") + D.nodeValue);
                            D.parentNode.removeChild(D)
                        } else {
                            break
                        }
                    } else {
                        D.inject(H, "bottom")
                    }
                    B++;
                    D = I[B]
                }
                var F = E.clone(true, true).inject(E, "after");
                $(H).replaces($(E));
                if (F.getElements(".colBreak").length >= 1) {
                    $(F.getElements(".colBreak")[0]).inject(H, "after")
                }
            }
        }.bind(this))
    },
    wrapTextNodes: function(A) {
        var C = $(A).childNodes;
        for (i = 0; i < C.length; i++) {
            if ($type(C[i]) === "textnode") {
                var B = new Element("p").inject(C[i], "after").set("html", C[i].nodeValue);
                C[i].parentNode.removeChild(C[i])
            }
        }
    },
    divideContent: function() {
        this.tempContentHolder = new Element("div", {
            id: "tempContentHolder"
        }).set("html", this.options.printEl.innerHTML).inject(document.body, "inside").setStyles({
            display: "none",
            position: "absolute"
        });
        this.sizerEl.empty();
        var C = [];
        var A = 0;
        var B = 1300;
        while (this.sizerEl.getCoordinates().height <= this.targetHeight && $(this.tempContentHolder).getFirst() && B > 0) {
            B--;
            if (!C[A]) {
                C[A] = new Element("div")
            }
            $(this.tempContentHolder).getFirst().inject(this.sizerEl, "inside");
            if (this.sizerEl.getCoordinates().height >= this.targetHeight || this.sizerEl.getLast().hasClass("colBreak")) {
                $(C[A]).set("html", this.sizerEl.innerHTML);
                this.sizerEl.empty();
                A++;
                if (A >= this.options.numOfColumns) {
                    A = this.options.numOfColumns - 1
                }
                if (!C[A]) {
                    C[A] = new Element("div")
                }
                if (!this.tempContentHolder.getFirst()) {
                    $(C[A]).set("html", this.tempContentHolder.innerHTML + $(C[A]).innerHTML)
                }
            }
        }
        $(C[A]).set("html", $(C[A]).innerHTML + this.sizerEl.innerHTML);
        this.sizerEl.empty();
        return C
    },
    divideContent2: function() {
        this.tempContentHolder = new Element("div", {
            id: "tempContentHolder"
        }).set("html", this.options.printEl.innerHTML).inject(document.body, "inside").setStyles({
            display: "none",
            position: "absolute"
        });
        this.sizerEl.empty();
        var C = [];
        var A = 0;
        var B = 1300;
        while (A < this.options.numOfColumns && B > 0) {
            B--;
            if (!C[A]) {
                C[A] = new Element("div")
            }
            if (this.tempContentHolder.getFirst()) {
                $(this.tempContentHolder).getFirst().inject(this.sizerEl, "inside")
            }
            if (this.sizerEl.getLast().hasClass("colBreak")) {
                $(C[A]).set("html", this.sizerEl.innerHTML);
                this.sizerEl.empty();
                A++;
                if (A >= this.options.numOfColumns) {
                    A = this.options.numOfColumns - 1
                }
                if (!C[A]) {
                    C[A] = new Element("div")
                }
                if (!this.tempContentHolder.getFirst()) {
                    $(C[A]).set("html", this.tempContentHolder.innerHTML + $(C[A]).innerHTML)
                }
            }
        }
        $(C[A]).set("html", $(C[A]).innerHTML + this.sizerEl.innerHTML);
        this.sizerEl.empty();
        return C
    },
    shaveColumns: function() {
        for (i = 0; i < this.columnElsArr.length - 1; i++) {
            var C = this.columnElsArr[i].getCoordinates().height - this.targetHeight;
            var F = this.columnElsArr[i].getLast().get("tag") && this.options.splittableElements.contains(this.columnElsArr[i].getLast().get("tag"));
            var G = this.columnElsArr[i].getLast();
            if (C > 0 && F) {
                var B = G.getCoordinates().height - C + this.options.tolerance;
                var H = G.clone().inject($("sizerElWrapper"), "inside");
                H.empty();
                var A = 50;
                while (A > 0 && G.childNodes.length && G.getCoordinates().height > B) {
                    A--;
                    if ($type(G.childNodes[G.childNodes.length - 1]) === "textnode" || $type(G.childNodes[G.childNodes.length - 1]) === "whitespace") {
                        var D = 50;
                        var E = G.childNodes[G.childNodes.length - 1].nodeValue.split(" ");
                        while (D > 0 && G.childNodes[G.childNodes.length - 1].nodeValue.length >= 0 && G.getCoordinates().height > B) {
                            D--;
                            if ($defined(E.getLast())) {
                                H.innerHTML = E.getLast().toString() + " " + H.innerHTML
                            }
                            E = E.filter(function(J, I) {
                                return I < (E.length - 1) && $defined(J)
                            });
                            G.childNodes[G.childNodes.length - 1].nodeValue = E.join(" ")
                        }
                        if (!$defined(E.getLast())) {
                            G.removeChild(G.childNodes[G.childNodes.length - 1])
                        }
                    } else {
                        if ($(G.childNodes[G.childNodes.length - 1])) {
                            if ($(G.childNodes[G.childNodes.length - 1]).hasClass("colBreak")) {
                                A = 0
                            } else {
                                $(G.childNodes[G.childNodes.length - 1]).inject(H, "top")
                            }
                        }
                    }
                }
                H.inject(this.columnElsArr[i + 1], "top")
            } else {
                if (C > this.options.tolerance && !F) {
                    G.inject(this.columnElsArr[i + 1], "top")
                }
            }
        }
    }
});
