/*
 * Copyright (c) 2016 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 document, window, console, requestAnimationFrame, tizen, THREE*/

// create "app" namespace if not exists.
window.app = window.app || {};

/**
 * Main Application Controller.
 * Manages and renders pages.
 *
 * @module app
 * @requires lib/threejs
 * @namespace app
 */

(function application(app) {

    'use strict';

    /**
     * Total pages count.
     *
     * @memberof app
     * @public
     * @const {number}
     */
    var PAGES_COUNT = 5,

        /**
         * Device radius in pixels.
         *
         * @memberof app
         * @public
         * @const {number}
         */
        DEVICE_RADIUS = 180,

        /**
         * Application HTML elements.
         *
         * @memberof app
         * @private
         * @type {HTMLElement}
         */
        applicationElement = document.getElementById('application'),

        /**
         * Reference to currently displayed page.
         *
         * @memberof app
         * @private
         * @type {object}
         */
        currentPage = null,

        /**
         * Page title element.
         *
         * @memberof app
         * @private
         * @type {HTMLElement}
         */
        pageTitle = document.querySelector('.page-title'),

        /**
         * Common renderer.
         *
         * @memberof app
         * @private
         * @type {THREE.Renderer}
         */
        renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
            transparent: true
        });

    /**
     * Binds events.
     *
     * @memberof app
     * @private
     */
    function bindEvents() {
        document.addEventListener('tizenhwkey', function onTizenhwkey(e) {
            if (e.keyName === 'back') {
                if (!app.currentPage.number) {
                    try {
                        tizen.application.getCurrentApplication().exit();
                    } catch (error) {
                        console.error(error);
                    }
                } else {
                    app.changePage();
                }
            }
        });
    }

    /**
     * Sets up renderer object.
     *
     * @memberof app
     * @private
     */
    function setRenderer() {
        renderer.setSize(DEVICE_RADIUS * 2, DEVICE_RADIUS * 2);
        renderer.domElement.classList.add('renderer');
        renderer.domElement.width = DEVICE_RADIUS * 2;
        renderer.domElement.height = DEVICE_RADIUS * 2;
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.BasicShadowMap;

        applicationElement.appendChild(renderer.domElement);
    }

    /**
     * Finds page by number.
     *
     * @memberof app
     * @private
     * @param {number} pageNumber
     * @returns {object}
     */
    function findPageByNumber(pageNumber) {
        var foundPage = {};

        Object.keys(app.pages).forEach(function testPage(page) {
            if (app.pages[page].number === pageNumber) {
                foundPage = app.pages[page];
            }
        });

        return foundPage;
    }

    /**
     * Display page title if present.
     *
     * @memberof app
     * @private
     * @param {Page} page
     */
    function setPageTitle(page) {
        if (page.title) {
            pageTitle.innerText = page.title;
            pageTitle.style.display = 'block';
        } else {
            pageTitle.style.display = 'none';
        }
    }

    /**
     * Searches for page by given number and sets if as current one when found.
     * Displays page title.
     *
     * If no number is provided as parameter sets menu page as current one.
     *
     * @memberof app
     * @public
     * @param {number} pageNumber
     */
    function changePage(pageNumber) {
        if (currentPage && typeof currentPage.onHide === 'function') {
            currentPage.onHide();
        }

        app.currentPage = currentPage = findPageByNumber(pageNumber || 0);

        if (typeof currentPage.onShow === 'function') {
            currentPage.onShow();
        }

        if (currentPage.backgroundColor) {
            applicationElement.style.backgroundColor =
                currentPage.backgroundColor;
            renderer.setClearColor(currentPage.backgroundColor);
        }

        setPageTitle(currentPage);
    }

    /**
     * Renders scene using currentPage scene and camera.
     *
     * @memberof app
     * @private
     */
    function render() {
        if (currentPage.animate) {
            currentPage.animate();
        }

        renderer.render(currentPage.scene, currentPage.camera);
        requestAnimationFrame(render);
    }

    /**
     * Initializes application.
     *
     * @memberof app
     * @private
     */
    function init() {
        bindEvents();
        setRenderer();
    }

    init();

    Object.assign(app, {
        startRendering: render,
        changePage: changePage,
        pages: {},
        DEVICE_RADIUS: DEVICE_RADIUS,
        TOTAL_PAGES: PAGES_COUNT
    });

}(window.app));
