(function Snakely() {

    var ROOT_NODE;
    var ROOT_NODE_SELECTOR = "#nav"; //specify the menurootnode which is an element that's wrapping the first <ul>
    var TOP_POS_CONST = 6;
    var LIST_WIDTH = 155; //Oldvalue:140

    var addFrenchQuote = false;

    var selected = {};
    var rootMenu;

    var ie = false;
    var ie6 = false;
    var quirks = false;

    if (window.navigator.userAgent.search("MSIE") > -1) {
        ie = true;
        if (window.navigator.userAgent.search("6.0") > -1) {
            ie6 = true;
        }
    }
    if (document.compatMode == "BackCompat") {
        quirks = true;
    }

    onload = function () {

        //this is the rootnode that will be used at all time throughout the script
        ROOT_NODE = $(document).getElement(ROOT_NODE_SELECTOR);

        //Execute only when snakemenu is used. #nav will not be available on subsites using traditional menu.
        if (ROOT_NODE != null) {
            rootMenu = ROOT_NODE.getElement("ul");
            // collect whats selected at page load
            selected.links = ROOT_NODE.getElements("a.selected");
            selected.menus = ROOT_NODE.getElements("ul.selected");

            //add � to all links that has submenus
            if (addFrenchQuote) {
                var menus = ROOT_NODE.getElements("ul ul");
                menus.getPrevious().each(function (menu, i) {
                    menu.innerHTML += " &#187;";
                });
            }

            //find the top and width of all a-tags
            calculatePositions();

            //create and position snakes according to the pageload-selection
            createSnakes();
            drawSnakes();
            addEvents();
            snapback();
        }
    };

    function calculatePositions() {
        var lists = ROOT_NODE.getElements("ul");
        lists.setStyle("visibility", "hidden").setStyle("display", "block");
        ROOT_NODE.getElements("a").each(function (a, i) {
            a.setStyle("font-weight", "bold");
            a.properties = getElementProperties(a);
            a.setStyle("font-weight", "");
        });
        lists.setStyle("visibility", "").setStyle("display", "");
    }

    var t;
    function addEvents() {

        var menus = ROOT_NODE.getElements("ul li a");
        menus.addEvent("mouseover", function () {
            var link = $(this);
            var submenu = link.getNext();

            hideSnakes(link, "up");
            drawSnakes(link);

            if (t) {
                clearTimeout(t);
            }

            t = setTimeout(function () {
                link.parentNode.parentNode.getElements("a").removeClass("current");
                hideSnakes(link, "down");
                if (!submenu) {

                    var selectedSibling = link.parentNode.parentNode.getElement("a.selected");
                    if (selectedSibling) {
                        snapback(selectedSibling);
                        var fromLink = link.parentNode.parentNode.getPrevious();
                        if (fromLink) {
                            positionSnake(fromLink, link);
                        }
                    } else {
                        hideSubmenus(link);
                        var snake = link.parentNode.parentNode.getChildren();
                        snake[snake.length - 1].setStyle("display", "none");
                    }

                } else {
                    hideSubmenus(submenu);
                    displaySubmenu(submenu);
                    drawSnakes(link);

                    if (link.hasClass("selected")) {
                        snapback(link);
                    }

                    //point the snake at the opened submenu
                    var newLink = submenu.getElement("a.selected");
                    if (!newLink) {
                        newLink = submenu.getElement("a");
                    }
                    positionSnake(link, newLink);
                    link.addClass("current");

                }
            }, 300);
        });

        menus.addEvent("mouseout", function () {
            clearTimeout(t);
        });

        //snapback when outside the menu with the pointer
        var time = false;
        ROOT_NODE
		.addEvent("mouseleave", function () {
		    if (!time) {
		        time = setTimeout(function () {
		            snapback();
		            time = false;
		        }, 500);
		    }
		})
		.addEvent("mouseover", function () {
		    if (time) {
		        clearTimeout(time);
		        time = false;
		    }
		});
    }
    function snapback(rootLink) {
        var links = selected.links;
        var selection = false;

        if (links.length > 0) {
            selection = true;
        }

        if (selection) {
            hideSubmenus(links[0]);
            var menu = links[0].parentNode.parentNode;
        } else {
            var menu = rootMenu;
            hideSubmenus(rootMenu);
        }

        menu.getElements("div.snake").setStyle("display", "none");
        menu.getElements("a").removeClass("current");

        if (selection) {
            displaySubmenu(links[0].getNext());
            drawSnakes(links[links.length - 1]);
        } else {
            displaySubmenu(menu);
        }
        if (selection) {
            var submenu = links[links.length - 1].getNext();
            if (submenu) {
                var newLink = submenu.getElement("a.selected");
                if (!newLink) {
                    newLink = submenu.getElement("a");
                } else {
                    submenu.setStyle("border-color", "");
                }

                positionSnake(links[links.length - 1], newLink);
            }
        }

    }
    function hideSubmenus(element) {
        var submenuCollection = element.parentNode.parentNode.getElements("ul");
        submenuCollection.removeClass("open");

        hideSnakes(element, "down");
    }
    function displaySubmenu(submenu) {
        submenu.addClass("open");
        var nextLink = submenu.getElement("a.selected");

        if (nextLink) {
            var nextSubmenu = nextLink.getNext();
            if (nextSubmenu) {
                displaySubmenu(nextSubmenu);
            }
        } else if (selected.menus.contains(submenu)) {
            var unselectedSubmenu = submenu.getElement("a").getNext();
            if (unselectedSubmenu) {
                unselectedSubmenu.addClass("open");
            }
        }
        return;
    }
    function hideSnakes(link, direction) {

        if (direction == "down") {
            var snakes = link.parentNode.parentNode.getElements("div.snake");
        } else if (direction == "up") {
            var snakes = [];

            var menu = $(link.parentNode.parentNode);

            if (menu.id = "nav") return false;

            while (menu) {
                console.log(menu);
                var snake = menu.getElement("div.snake");

                snakes.unshift(snake);

                if (menu.parentNode) {
                    menu = menu.parentNode.parentNode;
                } else {
                    menu = false;
                }
            }
        } else {
            return false;
        }


        snakes.each(function (snake) {
            snake.setStyle("display", "none");
            snake.getElements("div").setStyle("background-color", "transparent");
        });

    }
    function drawSnakes(link) {
        if (link) {
            var links = findParentLinks(link);
        } else {
            var links = selected.links;
        }

        for (var i = 1; i < links.length; i++) {

            var from = links[i - 1];
            var to = links[i];

            positionSnake(from, to);
        }

    }
    function positionSnake(from, to) {
        // find and display snake snake
        var snake = $(from.parentNode.parentNode).getLast();
        snake.setStyle("display", "block");
        snake.getElements("div").setStyle("background-color", "");

        // get its parts
        var snakeParts = snake.getChildren();
        var tail = snakeParts[0];
        var body = snakeParts[1];
        var head = snakeParts[2];


        var fromLink = from.properties;
        var toLink = to.properties;

        // first horizontal
        tail.setStyle("width", Math.abs(LIST_WIDTH - fromLink.width));
        tail.setStyle("top", TOP_POS_CONST + fromLink.top);

        // second horizontal
        head.setStyle("top", TOP_POS_CONST + toLink.top);
        if (ie && quirks) {
            head.setStyle("width", 15);
            head.setStyle("right", -5);
        }
        // vertical
        var height = Math.abs(toLink.top - fromLink.top);
        if (toLink.top < fromLink.top) {
            body.setStyle("height", height);
            body.setStyle("top", TOP_POS_CONST + toLink.top);
        } else {
            body.setStyle("top", TOP_POS_CONST + fromLink.top);
            body.setStyle("height", height + 2);
        }

        // make it black if it leads to a selected link
        if (to.hasClass("selected")) {
            snake.addClass("selectedSnake");
        } else {
            snake.removeClass("selectedSnake");
        }

    }

    function createSnakes() {
        var menus = ROOT_NODE.getElements("ul");
        for (var i = 0; i < menus.length; i++) {
            var snake = new Element("div").addClass("snake");
            var tail = new Element("div").addClass("tail");
            var body = new Element("div").addClass("body");
            var head = new Element("div").addClass("head");
            snake.adopt(tail).adopt(body).adopt(head);

            snake.setStyle("display", "none");

            menus[i].adopt(snake);
        }
    }

    function getElementProperties(element) {
        var properties = {};
        properties.top = element.offsetTop;
        if (ie && quirks) {
            properties.width = element.offsetWidth + 4;
        } else {
            properties.width = element.offsetWidth;
        }

        return properties;
    }

    function findParentLinks(link) {
        var links = new Array();

        while (link) {
            links.unshift(link);
            link = link.parentNode.parentNode.getPrevious();
        }

        return links;
    }

    function isAnscestor(element, rootElement) {
        if (!element) {
            return false;
        }
        else if (element == rootElement) {
            return true;
        }

        return isAnscestor(element.parentNode, rootElement);
    }
})();
