/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*global define, console, document, setInterval, window, tau*/

/**
 * Main page module.
 *
 * @module views/main
 * @requires {@link core/event}
 * @requires {@link core/application}
 * @requires {@link core/storage/widgetstorage}
 * @requires {@link models/sensor}
 * @requires {@link helpers/time}
 * @requires {@link helpers/string}
 * @namespace views/main
 * @memberof views
 */

define({
    name: 'views/main',
    requires: [
        'core/event',
        'core/application',
        'core/storage/widgetstorage',
        'models/sensor',
        'helpers/time',
        'helpers/string'
    ],
    def: function viewsMain(req) {
        'use strict';

        /**
         * Core event module object.
         *
         * @private
         * @type {Module}
         */
        var e = req.core.event,

            /**
             * Core application module object.
             *
             * @private
             * @type {Module}
             */
            app = req.core.application,

            /**
             * Core storage.widgetstorage module object.
             *
             * @private
             * @type {Module}
             */
            widgetstorage = req.core.storage.widgetstorage,

            /**
             * Models sensor module object.
             *
             * @private
             * @type {Module}
             */
            sensor = req.models.sensor,

            /**
             * Time helper module object.
             *
             * @private
             * @type {Module}
             */
            time = req.helpers.time,

            /**
             * String helper module object.
             *
             * @private
             * @type {Module}
             */
            string = req.helpers.string,

            /**
             * Background color.
             *
             * @private
             * @const {string}
             */
            BACKGROUND_COLOR = '#0064ff',

            /**
             * Array of strings containing background colors
             * that correspond to level of absorbed radiation.
             *
             * @private
             * @const {string[]}
             */
            BACKGROUND_COLORS_FOR_LEVELS =
                ['#ffb400', '#ffb400', '#ff3c00', '#ff0000'],

            /**
             * Text of the message when sun radiation is low.
             *
             * @private
             * @const {string}
             */
            LOW_RADIATION_MSG = 'a lot of time',

            /**
             * Text of the message when sun radiation is harmful.
             *
             * @private
             * @const {string}
             */
            FINAL_COUNTDOWN_MSG = 'less than minute',

            /**
             * Text of the message when sun radiation is too high.
             *
             * @private
             * @const {string}
             */
            FINISH_MSG = 'run away',

            /**
             * The threshold of absorbed radiation for level 0.
             *
             * @private
             * @const {number}
             */
            ABSORBED_RADIATION_LEVEL_0 = 5000000,

            /**
             * The threshold of absorbed radiation for level 1.
             *
             * @private
             * @const {number}
             */
            ABSORBED_RADIATION_LEVEL_1 = 10000000,

            /**
             * The threshold of absorbed radiation for level 2.
             *
             * @private
             * @const {number}
             */
            ABSORBED_RADIATION_LEVEL_2 = 15000000,

            /**
             * Name of storage widget.
             *
             * @private
             * @const {string}
             */
            WIDGET_STORAGE_NAME = 'manual',

            /**
             * Value of storage widget.
             *
             * @private
             * @const {object}
             */
            WIDGET_STORAGE_VALUE = {},

            /**
             * Application page.
             *
             * @private
             * @type {HTMLElement}
             */
            page = null,

            /**
             * Main HTML element for animated sun image
             * and remaining time value.
             *
             * @private
             * @type {HTMLElement}
             */
            workingSpace = null,

            /**
             * Element for animated sun image.
             *
             * @private
             * @type {HTMLElement}
             */
            sun = null,

            /**
             * Image element for rays of the sun.
             *
             * @private
             * @type {HTMLElement}
             */
            sunLight = null,

            /**
             * Element for remaining sunburn time information.
             *
             * @private
             * @type {HTMLElement}
             */
            timeEnd = null,

            /**
             * Reset popup accepting button.
             *
             * @private
             * @type {HTMLElement}
             */
            yesBtn = null,

            /**
             * Reset popup canceling button.
             *
             * @private
             * @type {HTMLElement}
             */
            noBtn = null,

            /**
             * Alert popup accepting button.
             *
             * @private
             * @type {HTMLElement}
             */
            okBtn = null,

            /**
             * Reset popup.
             *
             * @private
             * @type {HTMLElement}
             */
            popupReset = null,

            /**
             * Manual popup.
             *
             * @private
             * @type {HTMLElement}
             */
            popupManual = null,

            /**
             * Level of absorbed radiation.
             *
             * @private
             * @type {number}
             */
            sunburnLevel = 0,

            /**
             * Previous level of absorbed radiation.
             *
             * @private
             * @type {number}
             */
            oldSunburnLevel = 0,

            /**
             * Start time of absorbed radiation.
             *
             * @private
             * @type {number}
             */
            startTime = 0,
            /**
             * Elapsed time of absorbed radiation.
             *
             * @private
             * @type {number}
             */
            elapsedTime = 0,

            /**
             * Remaining time for safe stay to solar radiation.
             *
             * @private
             * @type {number}
             */
            remainingTime = -1,

            /**
             * Counted value of absorbed radiation.
             *
             * @private
             * @type {number}
             */
            absorbedRadiation = 0,

            /**
             * Value of read sensor ultraviolet level.
             *
             * @private
             * @type {number}
             */
            ultravioletLevel = 0,

            /**
             * Counted radial speed.
             *
             * @private
             * @type {number}
             */
            radialSpeed = 0,

            /**
             * Counted current radius for animation.
             *
             * @private
             * @type {number}
             */
            currentRadius = 0,

            /**
             * Time of last frame for animation.
             *
             * @private
             * @type {number}
             */
            animationLastFrameTime = null;

        /**
         * Sets start time.
         *
         * @private
         */
        function setStartTime() {
            startTime = new Date().getTime();
        }

        /**
         * Obtains ultraviolet level.
         *
         * @private
         */
        function getUltravioletLevel() {
            ultravioletLevel = sensor.getSensorValue();
        }

        /**
         * Counts absorbed radiation.
         *
         * @private
         * @param {number} deltaTime
         */
        function countAbsorbedRadiation(deltaTime) {
            absorbedRadiation += deltaTime * ultravioletLevel;
        }

        /**
         * Counts remaining time of safe sunbath.
         *
         * @private
         */
        function countRemainingTime() {
            var rawMilis = (ABSORBED_RADIATION_LEVEL_2 - absorbedRadiation) /
                ultravioletLevel;

            remainingTime = rawMilis > 0 ? rawMilis : 0;
        }

        /**
         * Checks absorbed radiation
         * and updates value of the sunburnLevel variable.
         *
         * @private
         */
        function checkAbsorbedRadiation() {
            oldSunburnLevel = sunburnLevel;
            if (absorbedRadiation < ABSORBED_RADIATION_LEVEL_0) {
                sunburnLevel = 0;
            } else if (absorbedRadiation < ABSORBED_RADIATION_LEVEL_1) {
                sunburnLevel = 1;
            } else if (absorbedRadiation < ABSORBED_RADIATION_LEVEL_2) {
                sunburnLevel = 2;
            } else {
                sunburnLevel = 3;
            }
        }

        /**
         * Updates background color.
         *
         * @private
         */
        function updateBackgroundColor() {
            page.style.backgroundImage =
                '-webkit-linear-gradient(' + BACKGROUND_COLOR + ', ' +
                BACKGROUND_COLORS_FOR_LEVELS[sunburnLevel] + ')';
        }

        /**
         * Updates sun face.
         *
         * @private
         */
        function updateSunFace() {
            sun.classList.remove('sun-' + oldSunburnLevel);
            sun.classList.add('sun-' + sunburnLevel);
        }

        /**
         * Performs sun light animation step.
         *
         * @private
         */
        function animationStep() {
            var currentTime = new Date().getTime(),
                timeDiff = 0;

            if (animationLastFrameTime !== null) {
                timeDiff = currentTime - animationLastFrameTime;
                currentRadius += radialSpeed * (timeDiff / 1000);
                currentRadius = currentRadius % 360;
                sunLight.style.webkitTransform =
                    'rotate(' + currentRadius + 'deg)';
            }

            animationLastFrameTime = currentTime;
            window.webkitRequestAnimationFrame(animationStep);
        }

        /**
         * Updates sun lights rotation speed.
         *
         * @private
         */
        function updateSunLightsRotationSpeed() {
            radialSpeed = ultravioletLevel * 10;
        }

        /**
         * Updates remaining time.
         *
         * @private
         */
        function updateRemainingTime() {
            var timeObject = time.getTimeComponents(remainingTime),
                hours = timeObject.hours,
                minutes = timeObject.minutes,
                seconds = timeObject.seconds;

            if (remainingTime >= 0) {
                if (hours > 9) {
                    timeEnd.classList.add('text');
                    timeEnd.innerText = LOW_RADIATION_MSG;
                } else if (hours === 0 && minutes === 0 && seconds !== 0) {
                    timeEnd.classList.add('text');
                    timeEnd.innerText = FINAL_COUNTDOWN_MSG;
                } else if (hours === 0 && minutes === 0 && seconds === 0) {
                    timeEnd.classList.add('text');
                    timeEnd.innerText = FINISH_MSG;
                } else {
                    timeEnd.classList.remove('text');
                    timeEnd.innerText =
                        hours + ':' + string.pad(minutes.toFixed(0));
                }
            } else {
                timeEnd.innerText = '';
            }
        }

        /**
         * Updates UI.
         *
         * @private
         */
        function updateUI() {
            updateBackgroundColor();
            updateSunFace();
            updateSunLightsRotationSpeed();
            updateRemainingTime();
        }

        /**
         * Shows reset popup.
         *
         * @private
         */
        function showResetPopup() {
            tau.openPopup(popupReset);
        }

        /**
         * Hides reset popup.
         *
         * @private
         */
        function hideResetPopup() {
            tau.closePopup();
        }

        /**
         * Resets application.
         *
         * @private
         */
        function resetApp() {
            elapsedTime = 0;
            remainingTime = -1;
            absorbedRadiation = 0;
            checkAbsorbedRadiation();
            setStartTime();
            updateUI();
        }

        /**
         * Handles click event on working space element.
         *
         * @private
         */
        function onWorkingSpaceClick() {
            showResetPopup();
        }

        /**
         * Handles click event on yes button.
         *
         * @private
         */
        function onYesBtnClick() {
            resetApp();
            hideResetPopup();
        }

        /**
         * Handles click event on no button.
         *
         * @private
         */
        function onNoBtnClick() {
            hideResetPopup();
        }

        /**
         * Handles click event on ok button.
         *
         * @private
         */
        function onOkBtnClick() {
            app.exit();
        }

        /**
         * Handles models.sensor.error event.
         *
         * @private
         */
        function onSensorError() {
            console.error('MAIN: onSensorError()');
        }

        /**
         * Updates application state.
         *
         * @private
         */
        function updateApplicationState() {
            var currentTime = new Date().getTime(),
                newEpalsedTime = 0,
                deltaTime = 0;

            newEpalsedTime = currentTime - startTime;
            deltaTime = newEpalsedTime - elapsedTime;
            elapsedTime = newEpalsedTime;

            countAbsorbedRadiation(deltaTime);
            countRemainingTime();
            checkAbsorbedRadiation();
            updateUI();
        }

        /**
         * Handles models.sensor.change event.
         *
         * @private
         * @type {Event}
         */
        function onSensorChange(ev) {
            ultravioletLevel = ev.detail.ultravioletLevel;
            updateApplicationState();
        }

        /**
         * Starts timer flashing.
         *
         * @private
         */
        function startTimerFlashing() {
            setInterval(function onInterval() {
                timeEnd.classList.toggle('semitransparent');
            }, 1000);
        }

        /**
         * Handles popuphide event on popup-manual element.
         *
         * @private
         */
        function onPopupManualHide() {
            if (document.getElementById('dont-display').checked) {
                widgetstorage.set(WIDGET_STORAGE_NAME, WIDGET_STORAGE_VALUE);
            }
        }

        /**
         * Shows manual popup if it is needed.
         *
         * @private
         */
        function showManual() {
            if (!widgetstorage.get(WIDGET_STORAGE_NAME)) {
                tau.openPopup(popupManual);
            }
        }

        /**
         * Registers view event listeners.
         *
         * @private
         */
        function bindEvents() {
            workingSpace.addEventListener('click', onWorkingSpaceClick);
            yesBtn.addEventListener('click', onYesBtnClick);
            noBtn.addEventListener('click', onNoBtnClick);
            okBtn.addEventListener('click', onOkBtnClick);
            popupManual.addEventListener('popuphide', onPopupManualHide);
        }

        /**
         * Initializes module.
         *
         * @memberof views/main
         * @public
         */
        function init() {
            page = document.getElementById('main');
            workingSpace = document.getElementById('main-working-space');
            sun = document.getElementById('sun');
            sunLight = document.getElementById('sun-light');
            timeEnd = document.getElementById('remaining-time-value');
            yesBtn = document.getElementById('popup-reset-button-yes');
            noBtn = document.getElementById('popup-reset-button-no');
            okBtn = document.getElementById('alert-button-ok');
            popupReset = document.getElementById('popup-reset');
            popupManual = document.getElementById('popup-manual');
            bindEvents();
            showManual();
            startTimerFlashing();
            setStartTime();
            getUltravioletLevel();
            window.webkitRequestAnimationFrame(animationStep);
            updateApplicationState();
            sensor.setChangeListener();
            sensor.start();
        }

        e.listeners({
            'models.sensor.error': onSensorError,
            'models.sensor.change': onSensorChange
        });

        return {
            init: init
        };
    }

});
