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

    return {

        /**
         * Counter counts how many navigation elements has been tried to add to the navigation bar.
         * when the counter equals the amount of available navigation elements, the navigation bar
         * is ready and the content can be shown
         */
        NAVIGATION_ELEMENT_COUNTER: 0,

        /**
         * The available navigation elements and their indexes (in which order they
         * should be in the navigation bar)
         */
        NAVIGATION_ELEMENTS: { userBox:          { index: 0, name: 'user' },
                               browserBox:       { index: 1, name: 'browser' },
                               reportTypeBox:    { index: 2, name: 'report_types' },
                               calendarBox:      { index: 3, name: 'calendar' },
                               viewBox:          { index: 4, name: 'view' } },


        /**
         * Creates the navigation bar. Iterates through the list of available navigation
         * elements and each time calls a function which checks whether the user has a permission
         * to see the element or not. If the user has a permission to see the element, then
         * the element is created.
         */
        createNavigation: function () {

            // add the callback functions to the object

            OTOS.Navigation.NAVIGATION_ELEMENTS.userBox.callback        = OTOS.Navigation.showUserBox;
            OTOS.Navigation.NAVIGATION_ELEMENTS.browserBox.callback     = OTOS.Navigation.showBrowserBox;
            OTOS.Navigation.NAVIGATION_ELEMENTS.reportTypeBox.callback  = OTOS.Navigation.showReportTypeBox;
            OTOS.Navigation.NAVIGATION_ELEMENTS.calendarBox.callback    = OTOS.Navigation.showCalendarBox;
            OTOS.Navigation.NAVIGATION_ELEMENTS.viewBox.callback        = OTOS.Navigation.showViewBox;

            OTOS.Navigation.NAVIGATION_ELEMENT_COUNTER = 0;

            elementObj = OTOS.Navigation.NAVIGATION_ELEMENTS;

            OTOS.Dom.removeChildNodes($('navigation'));

            // iterate through the object and check the permission for each element and then
            // create the element if it's allowed
            for (var i in elementObj) {
                OTOS.Util.checkPermission(elementObj[i]['name'], elementObj[i]['callback']);
            } // for

        },


        /**
         * Event handler for the statistics type -select list's onchange event. Sets the
         * value for the global STAT_TYPE -variable, updates the chart type -select
         * list, changes the statistics type of the flash components and updates the hash string
         *
         * @param   {int}   val     The value of the statistics type -select list
         */
        statTypeChanged: function (val) {
            OTOS.ElementConfig.STAT_TYPE = val;
            OTOS.Main.updateChartTypes();
            OTOS.Statistics.changeStatType();
            OTOS.Main.updateHash();
        },


        /**
         * Event handler for the chart type -select list's onchange event. Sets the value
         * for the global CHART_TYPE -variable, changes the chart type of the flash components
         * and updates the hash string.
         *
         * @param   {string}    val     The value of the chart type -select list
         */
        chartTypeChanged: function (val) {
            OTOS.ElementConfig.CHART_TYPE = val;
            OTOS.Statistics.changeChartType();
            OTOS.Main.updateHash();
        },


        /**
         * Event handler for the column count -select list's onchange event. Sets the value
         * for the global COLUMN_COUNT -variable, changes the number of columns shown on the
         * page and updates the hash string.
         *
         * @param   {int}   val     The value of the column count -select list
         */
        columnCountChanged: function (val) {
            OTOS.ElementConfig.COLUMN_COUNT = val;
            OTOS.ElementManager.columnWidthChanged();
            OTOS.ElementManager.changeColumnCount();
            OTOS.Main.updateHash();
        },


        /**
         * Event handler for the period -select list's onchange event. Sets the value
         * for the global PERIOD -variable, updates the hour -select list, updates the
         * hash string and reloads all the page's flash components.
         *
         * @param   {string}    val     The value of the period -select list
         */
        periodChanged: function (val) {
            OTOS.ElementConfig.PERIOD = val;
            OTOS.Util.updateHours();
            OTOS.Statistics.refreshStatistics(null, null, null);
            OTOS.Main.updateHash();
        },


        /**
         * Event handler for the hour -select list's onchange event. Sets the value
         * for the global HOUR -variable, reloads all the page's flash components and
         * updates the hash string
         *
         * @param   {string}    val     The value of the hour -select list
         */
        timeChanged: function (val) {
            OTOS.ElementConfig.HOUR = val;
            OTOS.Statistics.refreshStatistics(null, null, null);
            OTOS.Main.updateHash();
        },


        /**
         * Get's the date and time parameters (for the statistics) from the calendar.
         *
         * @return  Returns an object with properties { period, date, dow }
         * @type    {Object}
         */
        getStatParameters: function () {

            var paramObj;

            // if the calendar exists, date and dow values are fetched from the calendar
            // and otherwise their values are set to null

            if ($('calendarBox') == undefined) {
                paramObj = { period: OTOS.ElementConfig.PERIOD,
                             date: null,
                             dow: null };
            } else {

                var myDate  = OTOS.Navigation.getSelectedDate(),
                    date    = myDate[0] + "%20" + OTOS.ElementConfig.HOUR + ":00:00",
                    dow     = myDate[1],

                paramObj = { period: OTOS.ElementConfig.PERIOD,
                             date: date,
                             dow: dow };

            } // else

            return paramObj;

        },


        /**
         * Gets an array with the selected date (Y-m-d) and the day of the week (dow).
         * If none of the dates in the calendar isn't selected, then we'll use the
         * current date.
         *
         * @return  An array with the selected date (index = 0) and dow (index = 1)
         * @type    {array}
         */
        getSelectedDate: function () {

            var date    = OTOS.Main.CAL.getSelectedDates(),
                dow     = null;

            // if there's nothing selected in the calendar, the default date is today

            if (date[0] === undefined) {
                var newDate     = new Date();
                dow             = newDate.getDay();
                selectedDate    = newDate.formatDate('Y-m-d');
            } else {
                selectedDate    = date[0].formatDate('Y-m-d');
                dow             = date[0].getDay();
            } // else

            // dow = day of week. javascript's date functions think that the first
            // day of the week is sunday, but we need it to be monday. so let's change it

            dow = (dow == 0) ? 6 : dow - 1;

            return [selectedDate, dow];

        },


        /**
         * Inserts a navigation element to the navigation bar to the right position
         * by checking the element's index from the NAVIGATION_ELEMENTS -object
         *
         * @param   {element}   el      The element to be inserted to the navbar
         * @param   {string}    elId    The id attribute of the element
         */
        insertNavigationElement: function (el, elId) {

            var navigation  = $('navigation'),
                navElements = document.getElementsByClassName('navBox', navigation),
                elIndex     = OTOS.Navigation.NAVIGATION_ELEMENTS[elId]['index'],
                inserted    = false;

            // go through all the navigation elements and find the right place for the
            // element we're adding

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

                var currentId       = OTOS.Dom.getFirstChildByClassName('navContent', navElements[i]).id;
                var currentIndex    = OTOS.Navigation.NAVIGATION_ELEMENTS[currentId]['index'];

                if (elIndex < currentIndex) {
                    navigation.insertBefore(el, navElements[i]);
                    inserted = true;
                    break;
                } // if

            } // for

            // if we didn't find a place for the element, we'll append it to the end of the navbar
            if (!inserted) {
                navigation.appendChild(el);
            } // if

        },


        /**
         * The response handler for the request which checks the user's permission
         * to see a certain element. If the user has permission, the function callback
         * is called.
         *
         * @param   {request}   request     The xmlhttprequest, which responseText-property
         *                                  should contain boolean values hasPermission, isUser
         *                                  and isAdmin separated by '###'-strings.
         * @param   {function}  callback    The function to be called if hasPermission is true
         */
        showBox: function (request, callback) {

            var response    = OTOS.Util.trim(request.responseText),
                parts       = response.split('###'),
                permObj     = { permission: (parts[0] == 'true' ? true : false),
                                user: (parts[1] == 'true' ? true : false),
                                admin: (parts[2] == 'true' ? true : false) };

            if (permObj.permission) {
                callback(permObj);
            } else {
                OTOS.Navigation.updateNavigationElementCounter();
            }

        },


        /**
         * Function displays the user box if the UserManager-namespace exists
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        showUserBox: function (permObj) {

            if (!OTOS.UserManager) {
                OTOS.Navigation.updateNavigationElementCounter();
            } else {
                OTOS.Navigation.showBox(permObj, OTOS.UserManager.createUserBox);
            } // else

        },


        /**
         * Displays the view box if the View-namespace exists
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        showViewBox: function (permObj) {

            if (!OTOS.View) {
                OTOS.Navigation.updateNavigationElementCounter();
            } else {
                OTOS.Navigation.showBox(permObj, OTOS.View.getViews);
            } // else

        },


        /**
         * Displays the navigationbox
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        showBrowserBox: function (permObj) {
            OTOS.Navigation.showBox(permObj, OTOS.Navigation.createBrowserBox);
            OTOS.Navigation.updateNavigationElementCounter();
        },


        /**
         * Displays the calendarbox
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        showCalendarBox: function (permObj) {
            OTOS.Navigation.showBox(permObj, OTOS.Navigation.createCalendarBox);
            OTOS.Navigation.updateNavigationElementCounter();
        },


        /**
         * Displays the report type -box
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        showReportTypeBox: function (permObj) {
            OTOS.Navigation.showBox(permObj, OTOS.Navigation.createReportTypeBox);
            OTOS.Navigation.updateNavigationElementCounter();
        },


        /**
         * Creates the navigationbox
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        createBrowserBox: function (perms) {

            if (perms.permission) {

                var treeInfoArray   = OTOS.Tree.createTreeInfoArray(OTOS.ElementConfig.SERVERDATA),
                    browser         = OTOS.Tree.createTree(treeInfoArray),
                    browserBox      = OTOS.Dom.createNavBox('Selain',
                                                            browser,
                                                            'Ohjeet selaimen käyttöön',
                                                            'browserBox');

                OTOS.Navigation.insertNavigationElement(browserBox, 'browserBox');

                // hide all the subitems of the navigation tree
                $A(browser.getElementsByTagName('li')).each(function (item) {
                    OTOS.Tree.toggleSubItems(item, false);
                });

            } // if

        },


        /**
         * Creates the calendarbox
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        createCalendarBox: function (perms) {

            if (perms.permission) {

                var periods     = { 'HOUR':     'Tunti',
                                    'DAY':      'Päivä',
                                    'WEEK':     'Viikko',
                                    'MONTH':    'Kuukausi',
                                    'YEAR':     'Vuosi',
                                    'DAYPRED':  'Päiväennuste',
                                    'WEEKPRED': 'Viikkoennuste' },
                    lstPeriods  = Builder.node('select', { id: 'lstPeriods' }),
                    lstTimes    = Builder.node('select', { id: 'lstTimes' });

                var counter = 0;

                for (var i in periods) {
                    lstPeriods.options[counter] = new Option(periods[i], i);
                    counter++;
                } // for

                for (var i = 0; i < 24; i++) {
                    lstTimes.options[i] = new Option((OTOS.Util.checkTime(i) + ' - ' + OTOS.Util.checkTime(i + 1)), OTOS.Util.checkTime(i));
                } // for

                var frm = Builder.node('form', { action: '', method: 'post' }, [
                                Builder.node('fieldset', { className: 'fstSelect clearfix' }, [
                                    Builder.node('label', { 'for': 'lstPeriods' }, ['Jakso']),
                                        lstPeriods
                                ]),
                                Builder.node('fieldset', { className: 'fstSelect clearfix' }, [
                                    Builder.node('label', { 'for': 'fstTimes' }, ['Aikaväli']),
                                    lstTimes
                                ])]);

                var content = Builder.node('div', [ Builder.node('div', { id: 'calContainer' }), frm ]);

                // event observers

                Event.observe(lstPeriods, 'change', function () {
                    OTOS.Navigation.periodChanged(lstPeriods.value);
                });

                Event.observe(lstTimes, 'change', function () {
                    OTOS.Navigation.timeChanged(lstTimes.value);
                });

                var calendarBox = OTOS.Dom.createNavBox('Kalenteri',
                                                        content,
                                                        'Ohjeet kalenterin käyttöön',
                                                        'calendarBox');

                OTOS.Navigation.insertNavigationElement(calendarBox, 'calendarBox');

                // set the default values for the form elements

                $('lstPeriods').value = OTOS.ElementConfig.PERIOD;
                OTOS.Util.updateHours();

                // create the calendar object

                OTOS.Main.CAL = new YAHOO.widget.Calendar("cal", "calContainer");
                OTOS.Main.CAL.customConfig = function() {
                    this.Config.Locale.MONTHS_SHORT     = ['Tam', 'Hel', 'Maa', 'Huh', 'Tou', 'Kes', 'Hei', 'Elo', 'Syy', 'Lok', 'Mar', 'Jou'];
                    this.Config.Locale.MONTHS_LONG      = ['Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', 'Toukokuu', 'Kesäkuu', 'Heinäkuu', 'Elokuu', 'Syyskuu', 'Lokakuu', 'Marraskuu', 'Joulukuu'];
                    this.Config.Locale.WEEKDAYS_1CHAR   = ['S', 'M', 'T', 'K', 'T', 'P', 'L'];
                    this.Config.Locale.WEEKDAYS_SHORT   = ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'];
                    this.Config.Locale.WEEKDAYS_MEDIUM  = ['Sun', 'Maa', 'Tii', 'Kes', 'Tor', 'Per', 'Lau'];
                    this.Config.Locale.WEEKDAYS_LONG    = ['Sunnuntai', 'Maanantai', 'Tiistai', 'Keskiviikko', 'Torstai', 'Perjantai', 'Lauantai'];
                    this.Config.Options.START_WEEKDAY   = 1;
                }; // customConfig

                OTOS.Main.CAL.setupConfig();
                OTOS.Main.CAL.render();

            } // if

        },


        /**
         * Creates the report type box
         *
         * @param   {object}   permObj      An object containing properties permission, admin and user,
         *                                  and each of those contain a boolean value.
         */
        createReportTypeBox: function (perms) {

            if (perms.permission) {

                var statOpts        = [ 'Keskiarvo',
                                        'Käyttöaste',
                                        'Kävijämäärä',
                                        'Reaaliaikainen tilasto'],
                    lstStatTypes    = Builder.node('select', { id: 'lstStatTypes' }),
                    lstColumnCount  = Builder.node('select', { id: 'lstColumnCount' }),
                    maxColumns      = 4;

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

                    lstStatTypes.options[i] = new Option(statOpts[i], i);

                    if (i == OTOS.ElementConfig.STAT_TYPE) {
                        lstStatTypes.options[i].selected = true;
                    } // if

                } // for

                for (var i = 0; i < maxColumns; i++) {

                    lstColumnCount.options[i] = new Option((i+1), (i+1));

                    if ((i + 1) == OTOS.ElementConfig.COLUMN_COUNT) {
                        lstColumnCount.options[i].selected = true;
                    } // if

                } // for

                var fstStatTypes    = Builder.node('fieldset', { className: 'fstSelect clearfix', id: 'fstStatTypes' }, [
                                            Builder.node('label', { 'for': 'lstStatTypes' }, ['Tilastotyyppi']),
                                            lstStatTypes]),
                    fstChartTypes   = Builder.node('fieldset', { className: 'fstSelect clearfix', id: 'fstChartTypes' }, [
                                            Builder.node('label', { 'for': 'lstChartTypes' }, ['Kaaviotyyppi']),
                                            Builder.node('select', { id: 'lstChartTypes' })]),
                    fstColumnCount  = Builder.node('fieldset', { className: 'fstSelect clearfix', id: 'fstColumnCount' }, [
                                            Builder.node('label', { 'for': 'lstColumnCount' }, ['Sarakkeiden lukumäärä']),
                                            lstColumnCount]),
                    frm             = Builder.node('form', { action: '', method: 'post' }, [
                                            fstStatTypes,
                                            fstChartTypes,
                                            fstColumnCount]),
                    navBox          = OTOS.Dom.createNavBox('Raporttityypit', frm, 'Ohjeet raporttityyppien käyttöön', 'reportTypeBox');

                // event observers

                Event.observe(lstStatTypes, 'change', function () {
                    OTOS.Navigation.statTypeChanged(lstStatTypes.value);
                });

                Event.observe(fstChartTypes.lastChild, 'change', function () {
                    OTOS.Navigation.chartTypeChanged(fstChartTypes.lastChild.value);
                });

                Event.observe(lstColumnCount, 'change', function () {
                    OTOS.Navigation.columnCountChanged(lstColumnCount.value);
                });

                OTOS.Navigation.insertNavigationElement(navBox, 'reportTypeBox');
                OTOS.Main.updateChartTypes();

            } // if

        },


        /**
         * Updates the navigation element counter and displays the content
         * if the counter equals the amount of the available navigation
         * elements.
         */
        updateNavigationElementCounter: function () {

            OTOS.Navigation.NAVIGATION_ELEMENT_COUNTER++;

            if (OTOS.Navigation.NAVIGATION_ELEMENT_COUNTER == OTOS.Util.getObjectSize(OTOS.Navigation.NAVIGATION_ELEMENTS)) {
                OTOS.ElementManager.showContent();
            } // if

        }

    };

}();
