/*
 * Copyright (c) 2013 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 Config, Model, Helpers, Ui, $, tizen, app, console*/

var App = null;

(function strict() { // strict mode wrapper
    'use strict';

    /**
     * Creates a new application object
     *
     * @class Application
     */
    App = function App() {
        this.configData = {};
    };

    App.prototype = {
        /**
         * @type Array
         */
        requires: [
            'js/app.config.js',
            'js/app.helpers.js',
            'js/app.model.js',
            'js/app.ui.js',
            'js/app.ui.events.js',
            'js/app.ui.templateManager.js',
            'js/app.ui.templateManager.modifiers.js'
        ],

        /**
         * @type Model
         */
        model: null,

        /**
         * @type Ui
         */
        ui: null,

        /**
         * @type Config
         */
        config: null,

        /**
         * @type Helpers
         */
        helpers: null,

        /**
         * Initialization function
         */
        init: function App_init() {
            this.config = new Config();
            this.helpers = new Helpers();
            this.model = new Model();
            this.ui = new Ui();
            this.ui.init(this.onUiInitialized.bind(this));
        },

        /**
         * Executes when UI is initialized.
         */
        onUiInitialized: function App_onUiInitialized() {
            this.ui.showList(this.model.getDownloadList());
        },

        /**
         * Application exit
         */
        exit: function App_exit() {
            console.log('App_exit');
            app.pauseAllActiveDownloads(function onPauseCompleted() {
                tizen.application.getCurrentApplication().exit();
            });
        },

        /**
         * Action for start file downloading
         *
         * @param {string} url File URL
         * @param {number} oldId
         */
        startDownloading: function App_startDownloading(url, oldId) {
            console.log('App_startDownloading: ' + url, oldId);

            var eventHandlers = {
                onprogress: this.onDownloadProgress.bind(this),
                oncompleted: this.onDownloadCompleted.bind(this),
                onpaused: this.onDownloadPaused.bind(this),
                oncanceled: this.onDownloadCanceled.bind(this),
                onfailed: this.onDownloadFailed.bind(this)
            };

            this.model.startDownloading(url, eventHandlers,
                this.onDownloadStarted.bind(this)
            );
        },

        /**
         * Performs operation when download operation is started.
         * Triggers refreshing for UI and data in LocalStorage database.
         *
         * @param {number} id Download ID.
         * @param {string} url File URL.
         */
        onDownloadStarted: function App_onDownloadStarted(
            id,
            url
        ) {
            console.log('App_onDownloadStarted: ', id);
            var fileName = this.helpers.getSourceName(url);

            this.ui.onDownloadStarted(id, url, fileName);
            this.updateBadge();
        },

        /**
         * Performs operations when download progress event occurs.
         * Triggers progress bar refreshing (UI) and
         * refreshing data in LocalStorage database.
         * @param {number} id Download ID.
         * @param {number} receivedSize Number of received bytes.
         * @param {number} totalSize Total size of downloading file.
         */
        onDownloadProgress: function App_onDownloadProgress(
            id,
            receivedSize,
            totalSize
        ) {
            console.log(
                'App_onDownloadProgress: ',
                receivedSize,
                totalSize
            );

            this.ui.onDownloadProgress(
                id,
                receivedSize,
                totalSize
            );
        },

        /**
         * Performs operations when download operation is completed.
         * Triggers displaying notification for user and
         * refreshing data in LocalStorage database.
         *
         * @param {number} id Download ID
         * @param {string} url File URL
         */
        onDownloadCompleted: function App_onDownloadCompleted(id, url) {
            console.log('App_onDownloadCompleted: ' + id + ', ' + url);
            var fileName = this.helpers.getSourceName(url);

            this.sendNotification(fileName);
            this.ui.onDownloadCompleted(id, fileName);
            this.updateBadge();
        },

        /**
         * Handler for paused download operation.
         * @param {number} id
         */
        onDownloadPaused: function App_onDownloadPaused(id) {
            console.log('App_onDownloadPaused: ' + id);
            this.ui.onDownloadPaused(id);
        },

        /**
         * Handler for cancelled download operation.
         * @param {number} id Download ID
         */
        onDownloadCanceled: function App_onDownloadCanceled(id) {
            console.log('App_onDownloadCanceled: ' + id);
            this.ui.onDownloadCanceled(id);
            this.updateBadge();
        },

        /**
         * Handler for failed download operation.
         * @param {number} id Download ID
         * @param {object} error Error object
         */
        onDownloadFailed: function App_onDownloadFailed(id, error) {
            console.log('App_onDownloadFailed: ' + id + ', ' + error.message);
            this.ui.onDownloadFailed(id, error.message);
            this.updateBadge();
        },

        /**
         * Updates badge counter.
         */
        updateBadge: function App_updateBadge() {
            console.log('App_updateBadge.');
            this.model.setBadgeCount(this.model.getActiveDownloadsCount());
        },

        /**
         * Pauses active download operation with the given ID.
         * @param {number} downloadId Download id.
         */
        pauseDownloading: function App_pauseDownloading(downloadId) {
            console.log('App_pauseDownloading: ' + downloadId);
            this.model.pauseDownloading(downloadId);
        },

        /**
         * Aborts downloading file and starts downloading again.
         * @param {number} downloadId
         */
        redownload: function App_redownload(downloadId) {
            var url = this.model.getDownloadUrl(downloadId);
            this.deleteDownloading(downloadId);
            this.startDownloading(url);
        },

        /**
         * Resumes or restarts paused download operation with the specified ID.
         *
         * @param {string} url File URL.
         * @param {number} downloadId Download ID
         * @param {boolean} listenerFlag
         */
        resumeDownloading: function App_resumeDownloading(
            url,
            downloadId,
            listenerFlag
        ) {
            console.log(
                'App_resumeDownloading: ',
                url,
                downloadId,
                listenerFlag
            );

            if (this.model.fileNeedsRestart(downloadId)) {
                this.redownload(downloadId);
                return;
            }

            var eventHandlers = {
                onprogress: this.onDownloadProgress.bind(this),
                oncompleted: this.onDownloadCompleted.bind(this),
                onpaused: this.onDownloadPaused.bind(this),
                oncanceled: this.onDownloadCanceled.bind(this),
                onfailed: this.onDownloadFailed.bind(this)
            };

            this.model.resumeDownloading(
                downloadId,
                eventHandlers,
                this.ui.onDownloadResumed.bind(this.ui)
            );
        },

        /**
         * Cancels active download operation with the specified ID.
         * @param {number} downloadId Download id.
         */
        cancelDownloading: function App_cancelDownloading(downloadId) {
            console.log('App_cancelDownloading: ' + downloadId);
            this.model.cancelDownloading(downloadId);
        },

        /**
         * Deletes download operation with the specified id.
         * @param {number} downloadId Download id.
         */
        deleteDownloading: function App_deleteDownloading(downloadId) {
            console.log('App_deleteDownloading: ' + downloadId);
            if (this.model.deleteDownloading(downloadId)) {
                this.ui.deleteDownloading(downloadId);
                this.updateBadge();
            }
        },

        /**
         * Show folder action
         */
        showFolder: function App_showFolder() {
            console.log('App_showFolder');
            this.model.showFolder();
        },

        /**
         * Launch file action
         * @param {string} fileName
         */
        launchFile: function App_launchFile(fileName) {
            console.log('App_launchFile: ' + fileName);
            var ext = this.helpers.getFileExtension(fileName),
                mime = this.helpers.resolveMimeType(ext);
            this.model.launchFile(fileName, mime);
        },

        /**
         * Pauses all active downloads.
         * @param {function} callback
         */
        pauseAllActiveDownloads: function App_pauseAllActiveDownloads(
            callback
        ) {
            console.log('App_pauseAllActiveDownloads');
            this.model.pauseAllActiveDownloads(callback);
        },

        /**
         * Refreshes download list.
         */
        refreshDownloadsList: function App_refreshDownloadsList() {
            console.log('App_refreshDownloadsList');
            var downloads = this.model.getDownloadList();

            this.model.getDownloads(
                this.ui.refreshDownloadsList.bind(this.ui, downloads)
            );
        },

        /**
         * Removes from list all downloads that are finished or failed.
         */
        clearAllFinished: function App_clearAllFinished() {
            var removed = this.model.clearAllFinished(),
                ui = this.ui,
                i = 0,
                len = removed.length;

            for (i = 0; i < len; i += 1) {
                ui.deleteDownloading(removed[i]);
            }
        },

        /**
         * Displays notification for user when file was downloaded.
         * @param {string} fileName Name of file which was downloaded.
         */
        sendNotification: function App_sendNotification(fileName) {
            var notificationDict, notification, fileExt, iconSrcPath;

            fileExt = this.helpers.getFileExtension(fileName);
            iconSrcPath = 'images/' + this.helpers.resolveFileIcon(fileExt);
            try {
                notificationDict = {
                    content: 'File ' + fileName +
                        ' was successfully downloaded.',
                    iconPath: null,
                    subIconPath: iconSrcPath,
                    vibration: true,
                    appControl: null,
                    ledColor: '#FF9900',
                    ledOnPeriod: 1000,
                    ledOffPeriod: 500
                };

                notification = new tizen.StatusNotification('SIMPLE',
                              'Download completed', notificationDict);

                tizen.notification.post(notification);
            } catch (err) {
                console.error(err.name + ': ' + err.message);
            }

        }
    };
}());
