
var OTOS = window.OTOS || {};
OTOS.ElementManager = function () {

    return {

        /**
         *
         */
        COLUMN_WIDTH: null,


        /**
         * Changes the number of columns displayed in the screen
         */
        changeColumnCount: function () {

            var contentElement = $(CONTENT_ELEMENT_ID);

            /*
             * If OTOS.Main.TREEMODE = true, we'll have to go through each container
             * and create the columns to each of them separately. If the OTOS.Main.TREEMODE is
             * false, we have only one container.
             */
            if (OTOS.Main && OTOS.Main.TREEMODE) {

                var cameraContainers = document.getElementsByClassName('cameraRowContainer', contentElement);

                for (var i = 0; i < cameraContainers.length; i++) {
                    OTOS.ElementManager.applyChangedColumnCount(cameraContainers[i]);
                } // for

            } else {
                OTOS.ElementManager.applyChangedColumnCount(contentElement);
            } // else

            OTOS.ElementManager.setDefaultElementSizes(); // update the element sizes

            // update the imagesizes only if there are any images
            if (document.getElementsByClassName('imageContainer').length > 0) {
                OTOS.Camera.updateImageSizes();
            } // if

            // update the statistics only if there are any statistics elements
            if (document.getElementsByClassName('areaElement').length > 0) {
                OTOS.Statistics.refreshStatistics(null, null, null);
            } // if

            // set the element heights equal
            OTOS.ElementManager.setCameraBarHeights(contentElement);

        },


        /**
         * Applies the column number change to one container.
         *
         * @param   {element}   contentElement  The container where to change the column number
         */
        applyChangedColumnCount: function (contentElement) {

            var colCount = OTOS.ElementConfig.COLUMN_COUNT,
                bars = document.getElementsByClassName('cameraBar', contentElement);

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

                if (i % colCount == 0) {
                    Element.addClassName(bars[i], 'firstOfTheRow');
                } else {
                    Element.removeClassName(bars[i], 'firstOfTheRow');
                } // else

            } // for

        },


        /**
         * Creates different elements to the content area by splitting the
         * hash-string and getting information about the saved
         * elements and settings from it.
         *
         * TODO     Setting period/hour -values might be buggy
         * @param   {String}    strHash     window.location.hash -string
         */
        showContent: function (strHash) {

            var container = $(CONTENT_ELEMENT_ID);

            OTOS.Dom.removeChildNodes(container);

            strHash = (strHash === undefined) ? window.location.hash : strHash;
            strHash = OTOS.Util.trim(strHash.replace('#', ''));

            if (strHash != '') {

                var arrElements = strHash.split('&'),
                    parts       = [];

                // go through all the founded elements and settings

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

                    parts = arrElements[i].split('=');

                    if (parts[0] == 'cols') {
                        OTOS.ElementConfig.COLUMN_COUNT = parts[1];
                    } else if (parts[0] == 'p') { // period
                        OTOS.ElementConfig.PERIOD = parts[1];
                    } else if (parts[0] == 't') { // time
                        OTOS.ElementConfig.HOUR = parts[1];
                    } else if (parts[0] == 'st') { // statistic type
                        OTOS.ElementConfig.STAT_TYPE = parts[1];
                    } else if (parts[0] == 'ct') { // chart type
                        OTOS.ElementConfig.CHART_TYPE = parts[1];
                    } // else if

                } // for

            } // else

            /*
             * PENDING
             *
             * Changing period and hour values might be buggy. Should call
             * OTOS.Util.updateHours -function when changing the period, but
             * it also changes the value of the OTOS.ElementConfig.HOUR -variable.
             * The function OTOS.Util.updateHours sets the current hour as the
             * default value for the OTOS.ElementConfig.HOUR -variable, so it
             * overrides the url-parameter.
             */
            if ($('lstPeriods') !== undefined) {
                OTOS.FormElement.selectOptionByValue($('lstPeriods'), OTOS.ElementConfig.PERIOD);
            } // if

            if ($('lstTimes') !== undefined) {

                if (OTOS.ElementConfig.PERIOD == 'HOUR') {
                    OTOS.FormElement.disableElement($('lstTimes'), false);
                } // if

                OTOS.FormElement.selectOptionByValue($('lstTimes'), OTOS.ElementConfig.HOUR);

            } // if

            if ($('lstStatTypes') !== undefined) {
                OTOS.FormElement.selectOptionByValue($('lstStatTypes'), OTOS.ElementConfig.STAT_TYPE);
                OTOS.Main.updateChartTypes();
            } // if

            if ($('lstChartTypes') !== undefined) {
                OTOS.FormElement.selectOptionByValue($('lstChartTypes'), OTOS.ElementConfig.CHART_TYPE);
            } // if

            if ($('lstColumnCount') !== undefined) {
                OTOS.FormElement.selectOptionByValue($('lstColumnCount'), OTOS.ElementConfig.COLUMN_COUNT);
            } // if

            // set the default value for the COLUMN_WIDTH -variable
            OTOS.ElementManager.columnWidthChanged();

            // create the elements

            if (strHash == '') {
                OTOS.Server.showServer(OTOS.Server.getFirstServer());

            } else {

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

                    parts = arrElements[i].split('=');

                    var prefix      = parts[0],
                        addrParts   = parts[1].split('|');

                    if (prefix == 's') { // server element
                        OTOS.Server.serverInfo(addrParts[0], false);

                    } else if (prefix == 'c') { // camera element

                        if ($(OTOS.Tree.TREE_ID) !== undefined) {
                            OTOS.Tree.toggleSubItems($(SERVER_LINK_ID_PREFIX + '_' + addrParts[0]), true);
                        } // if

                        OTOS.Camera.cameraInfo(addrParts[0], addrParts[1], false);

                    } else if (prefix == 'a') { // area element

                        if ($(OTOS.Tree.TREE_ID) !== undefined) {
                            OTOS.Tree.toggleSubItems($(SERVER_LINK_ID_PREFIX + '_' + addrParts[0]), true);
                            OTOS.Tree.toggleSubItems($(CAMERA_LINK_ID_PREFIX + '_' + addrParts[1]), true);
                        } // if

                        OTOS.Statistics.statisticsInfo(addrParts[0], addrParts[1], addrParts[2], false);

                    } // else if

                } // for

                OTOS.ElementManager.setCameraBarHeights(container);

            } // else

        },


        /**
         * Calculates the width for a column. Counts the width by getting the width of the whole
         * container, divides it with the number of columns and then subtracts margins and borders
         * from the result.
         *
         * @return  The width for a single column
         * @type    {double}
         */
        getColumnWidth: function () {

            var marginWidth = 10,
                columnCount = parseInt(OTOS.ElementConfig.COLUMN_COUNT),
                parentWidth = $(CONTENT_ELEMENT_ID).offsetWidth,
                borderWidth = 1;

            var columnWidth = (((100 / columnCount) / 100) * parentWidth) - marginWidth - (marginWidth / columnCount) - (borderWidth * 2);

            return columnWidth;

        },


        /**
         * Calculates the width for an image element by subtracting the desired padding from
         * the width of the column.
         *
         * @return  The width for the image element
         * @type    {double}
         */
        getImageWidth: function () {
            return (OTOS.ElementManager.COLUMN_WIDTH - (2 * 15));
        },


        /**
         * Calculates the width for an statistics element by subtracting the desired padding from
         * the width of the column.
         *
         * @return  The width for the statistics element
         * @type    {double}
         */
        getStatWidth: function () {
            return (OTOS.ElementManager.COLUMN_WIDTH - (2 * 2));
        },


        /**
         * Finds the tallest element in the container, gets it's height and sets that
         * height to all the other elements in the container.
         *
         * @param   {element}   container   The element that contains the elements we're handling
         */
        setCameraBarHeights: function (container) {
            var maxHeight = OTOS.Dom.getMaximumChildHeight(container, 'element');
            OTOS.Dom.setChildHeight(container, 'element', maxHeight);
        },


        /**
         * Sets the default sizes for the different infoelements (camera, stats, serverinfo)
         * by setting the height-property of the style attribute to "auto".
         */
        setDefaultElementSizes: function () {

            var container   = $(CONTENT_ELEMENT_ID),
                els         = document.getElementsByClassName('element', container),
                colWidth    = parseInt(OTOS.ElementManager.COLUMN_WIDTH) + 'px';

            for (var i = 0; i < els.length; i++) {
                els[i].style.height     = 'auto';
                els[i].style.minHeight  = 0;
                OTOS.Dom.getFirstAncestorByClassName(els[i], 'cameraBar').style.width = colWidth;
            } // for

        },


        /**
         * Creates the main page
         */
        createPage: function () {
            OTOS.Dom.removeChildNodes($('navigation'));
            OTOS.Dom.removeChildNodes($(CONTENT_ELEMENT_ID));
            OTOS.Navigation.createNavigation();
        },


        /**
         * Does the needed tricks after adding an single element to the content
         * area. If treemode is true, removes all the other elements from the content
         * area. If treemode is false, removes all the elements that are not server,
         * camera or statistics elements.
         *
         * @param   {element}   parent      The parent of the elements to be removed
         */
        handleElementAdding: function (parent) {

            if (OTOS.Main.TREEMODE) {
                OTOS.Main.TREEMODE = false;
                OTOS.Dom.removeChildNodes(parent);

            } else {

                $A($(CONTENT_ELEMENT_ID).childNodes).each(function (item) {
                    if (!Element.hasClassName(item, 'cameraBar')) {
                        Element.remove(item);
                    } // if
                });

            } // else

        },


        /**
         * Creates a button from which the user can hide or show the whole
         * navigation bar.
         *
         * @return      The button element
         * @type        {element}
         */
        createToggleNavButton: function () {

            var button = Builder.node('div', { id: 'toggleNav' });

            // show/hide the whole navigation element
            Event.observe(button, 'click', OTOS.ElementManager.toggleNavigation);
            // mouseover event for the navigation's toggle-button
            Event.observe(button, 'mouseover', function () {
                button.style.backgroundPosition = '-10px 0';
            });
            // mouseout event for the navigation's toggle-button
            Event.observe(button, 'mouseout', function () {
                button.style.backgroundPosition = '0 0';
            });

            return button;

        },


        /**
         * Hides or displays the navigation bar.
         */
        toggleNavigation: function () {

            var nav = $('navContainer'), // navigation element
                content = $(CONTENT_ELEMENT_ID), // content element
                navWidth = Element.getDimensions(nav).width, // navigation width
                contentWidth = Element.getDimensions(content).width, // content width
                navOffset = Position.cumulativeOffset(nav)[0], // x-position of the navigation
                navOffsetParent = Position.cumulativeOffset(nav.parentNode)[0], // x-position of the subcontainer (nav's parent)
                xTrans = (navOffset < 0)
                    ? (navWidth + navOffsetParent)
                    : (-navWidth - navOffset); // transition

            // move the navigation bar and the content. navigation bar is positioned absolutely
            // and content area is positioned with margin, so to change the position of the
            // elements, we have to change the navigation bar's left-attribute and content area's
            // left margin -attribute
            nav.style.left = nav.offsetLeft + xTrans + 'px';
            content.style.marginLeft = content.offsetLeft + xTrans + 'px';

            // the content area has more space now, so let's resize it to fill the whole
            // free area
            content.style.width = contentWidth - xTrans + 'px';
            $('toggleNav').style.background = (navOffset < 0)
                ? 'url(images/hide.gif)'
                : 'url(images/show.gif)';

            // if we're on the main page, we'll have to update the column count
            if (OTOS.Main) {
                OTOS.ElementManager.columnWidthChanged();
                OTOS.ElementManager.changeColumnCount();
            } // if

        },


        /**
         *
         */
        columnWidthChanged: function () {
            OTOS.ElementManager.COLUMN_WIDTH = OTOS.ElementManager.getColumnWidth();
        },


        /**
         *
         */
        createElementColumn: function () {

            var columnWidth = parseInt(OTOS.ElementManager.COLUMN_WIDTH) + 'px',
                col = Builder.node('div', { className: 'cameraBar' });

            col.style.width = columnWidth;

            return col;

        },


        /**
         *
         */
        removeColumn: function (el, container) {
            OTOS.Dom.getFirstAncestorByClassName(el, 'cameraBar').remove();
            OTOS.ElementManager.applyChangedColumnCount(container);
        }

    };

}();
