/*
 * 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, document, console, tau*/

/**
 * Filelist module.
 * @requires {@link ArchiveManager/helpers/dom}
 * @requires {@link ArchiveManager/helpers/router}
 * @requires {@link ArchiveManager/model/path}
 * @requires {@link ArchiveManager/model/filesystem}
 * @requires {@link ArchiveManager/model/archive}
 * @requires {@link core/event}
 * @requires {@link core/filesystem}
 * @requires {@link core/template}
 * @namespace ArchiveManager/views/filelist
 * @memberof ArchiveManager/views
 *
 * This module is responsible for displaying the page with list of files
 * in the whole application.
 * Manages list contents, header and footer in different modes.
 */

define({
    name: 'views/filelist',
    requires: [
        'helpers/dom',
        'helpers/router',
        'model/path',
        'model/filesystem',
        'model/archive',
        'core/event',
        'core/filesystem',
        'core/template'
    ],
    def: function viewsFilelist(req) {
        'use strict';

        var

            /**
             * Dom helper module object.
             */
            domHelper = req.helpers.dom,

            /**
             * Router helper module object.
             */
            router = req.helpers.router,

            /**
             * Path module object.
             */
            Path = req.model.path.Path,

            /**
             * Event module object.
             */
            e = req.core.event,

            /**
             * Filesystem module object.
             */
            modelFilesystem = req.model.filesystem,

            /**
             * Archive module object.
             */
            archive = req.model.archive,

            /**
             * Filesystem core module object.
             */
            coreFilesystem = req.core.filesystem,

            /**
             * Template module object.
             */
            template = req.core.template,

            /**
             * Content list.
             * @type {HTMLElement}
             */
            filesList = null,

            /**
             * Row template name.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ROW = 'row',

            /**
             * Row without anchor template name.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ROW_NO_ANCHOR = 'row_no_anchor',

            /**
             * Folder css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            FOLDER_CLASS = 'folder',

            /**
             * File css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            FILE_CLASS = 'file',

            /**
             * Zip css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ZIP_CLASS = 'zip',

            /**
             * ZIP extension name.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ZIP_EXT = 'zip',

            /**
             * Movable css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ANIMATED_CLASS = 'animated',

            /**
             * Hidden css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            HIDDEN_CLASS = 'hidden',

            /**
             * Disabled css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            DISABLED_CLASS = 'ui-disabled',

            /**
             * Button down css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            BTN_DOWN_S_CLASS = 'ui-btn-down-s',

            /**
             * Archive selected css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ARCHIVE_SELECTED_CLASS = 'archive-selected',

            /**
             * Standard mode css class.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            STANDARD_MODE_CLASS = 'standard-mode',

            /**
             * Standard mode flag.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            STANDARD_MODE = 'standard',

            /**
             * Archive mode flag.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            ARCHIVE_MODE = 'archive',

            /**
             * Preview mode flag.
             * @memberof ArchiveManager/views/filelist
             * @const {string}
             */
            PREVIEW_MODE = 'preview',

            /**
             * Current filelist mode flag.
             * @type {string}
             */
            mode = STANDARD_MODE,

            /**
             * All footers in the page.
             * @type {NodeList}
             */
            footers = null,

            /**
             * Home button displayed in application header in standard mode.
             * @type {HTMLElement}
             */
            homeBtn = null,

            /**
             * Up button displayed in application header in standard mode.
             * @type {HTMLElement}
             */
            upBtn = null,

            /**
             * Element which displays current path.
             * @type {HTMLElement}
             */
            navigationText = null,

            /**
             * Parent container of the current path element.
             * @type {HTMLElement}
             */
            navigationPath = null,

            /**
             * Select all checkbox.
             * @type {HTMLElement}
             */
            selectAll = null,

            /**
             * Current path object.
             * @type {Path}
             */
            path = new Path();

        /**
         * Updates main page header. Shows or hides home and up buttons.
         */
        function updateHeader() {
            if ((!path.isHome() && mode === STANDARD_MODE) ||
                    mode === PREVIEW_MODE) {
                homeBtn.classList.remove(HIDDEN_CLASS);
                upBtn.classList.remove(HIDDEN_CLASS);
            } else {
                homeBtn.classList.add(HIDDEN_CLASS);
                upBtn.classList.add(HIDDEN_CLASS);
            }
        }

        /**
         * Adds or removes movable css class to content list.
         * @param {boolean} animate When it is set to true,
         * content list is animated during mode changing, otherwise not.
         */
        function setFileListAnimated(animate) {
            if (animate) {
                filesList.classList.add(ANIMATED_CLASS);
            } else {
                filesList.classList.remove(ANIMATED_CLASS);
            }
        }

        /**
         * Updates UI text which displays current path.
         */
        function updatePath() {
            var element = navigationText.parentNode,
                container = element.parentNode;
            navigationText.innerText = path.toString(true);
        }

        /**
         * Returns a list of selected files.
         * @memberof ArchiveManager/views/filelist
         * @param {object} sizeInfo Information about size of each file.
         * @return {object[]} Information about files.
         */
        function getSelectedFiles(sizeInfo) {
            var sizes = sizeInfo || {},
                checkedElements = filesList.querySelectorAll(
                    'input[type="checkbox"]:checked'
                ),
                list = [],
                element = null,
                url = '',
                label = '',
                len = checkedElements.length,
                i = 0,
                isDirectory = false;

            for (i = 0; i < len; i += 1) {
                element = domHelper.findParent(checkedElements[i], 'li');
                url = element.getAttribute('url');
                label = element.getAttribute('label');
                isDirectory = element.getAttribute('isDirectory') === 'true';
                list.push({
                    path: url,
                    name: label,
                    filesize: sizes[label],
                    isDirectory: isDirectory
                });
            }

            return list;
        }

        /**
         * Selects archive record on content list.
         * @memberof ArchiveManager/views/filelist
         * @param {HTMLElement} element
         */
        function selectArchive(element) {
            if (mode !== ARCHIVE_MODE &&
                    element.classList.contains(ZIP_CLASS)) {
                element.classList.add(BTN_DOWN_S_CLASS);
                element.classList.add(ARCHIVE_SELECTED_CLASS);
            }
        }

        /**
         * Deselects archive record on content list.
         * @memberof ArchiveManager/views/filelist
         */
        function deselectArchive() {
            var element = filesList.querySelector('.' + ARCHIVE_SELECTED_CLASS);

            if (element) {
                element.classList.remove(ARCHIVE_SELECTED_CLASS);
                element.classList.remove(BTN_DOWN_S_CLASS);
            }
        }

        /**
         * Refreshes the files list.
         */
        function refreshFilesList() {
            tau.engine.createWidgets(filesList);
            tau.widget.Listview(filesList).refresh();
        }

        /**
         * Displays storages.
         * @param {array} storages
         */
        function showStorages(storages) {
            var len = storages.length,
                i = 0,
                elements = [];

            for (i; i < len; i += 1) {
                elements.push(
                    template.get(ROW, {
                        index: i,
                        label: storages[i].label,
                        type: FOLDER_CLASS
                    })
                );
            }

            filesList.innerHTML = elements.join('');
            refreshFilesList();
        }

        /**
         * Compares file objects by file type (directory, file) and then
         * alphabetically in the current locale.
         * @param {File} file1
         * @param {File} file2
         * @return {number} Number indicating whether file1 comes before, after
         * or is equal as the file2 in sort order.
         */
        function compareFile(file1, file2) {
            var bothFiles = file1.isFile && file2.isFile,
                bothDirectories = file1.isDirectory && file2.isDirectory;

            if (bothFiles || bothDirectories) {
                // compare names in the current locale
                return file1.name.localeCompare(file2.name);
            }

            // one of them must be directory, directories comes before files
            return file1.isDirectory ? -1 : 1;
        }

        /**
         * Sorts file objects in specified array (in place).
         * Files are sorted by file type (directory, file) first
         * and then alphabetically in the current locale.
         *
         * Returns sorted array.
         * @param {File[]} files Array to sort.
         * @return {File[]}
         */
        function sortFiles(files) {
            return files.sort(compareFile);
        }

        /**
         * Creates file list using specified files array.
         *
         * Files on list are sorted by type (directory, file)
         * and then alphabetically in the current locale.
         * @param {File[]} files
         */
        function showFiles(files) {
            var filesSorted = sortFiles(files.slice(0)),
                len = filesSorted.length,
                i = 0,
                elements = [],
                element = null,
                type = '',
                extension = null,
                rowTpl = '';

            for (i; i < len; i += 1) {
                rowTpl = ROW;
                element = filesSorted[i];
                if (element.isFile) {
                    extension = coreFilesystem.getFileExtension(
                        element.name,
                        false
                    );
                    if (extension && extension.toLowerCase() === ZIP_EXT) {
                        type = ZIP_CLASS;
                    } else {
                        type = FILE_CLASS;
                        rowTpl = ROW_NO_ANCHOR;
                    }
                } else {
                    type = FOLDER_CLASS;
                }
                elements.push(
                    template.get(rowTpl, {
                        index: i,
                        label: element.name,
                        type: type,
                        url: element.fullPath,
                        isDirectory: element.isDirectory
                    })
                );
            }

            filesList.innerHTML = elements.join('');
            refreshFilesList();
        }

        /**
         * Hides all footers on the page.
         */
        function hideAllFooters() {
            var i = footers.length;
            while (i) {
                i -= 1;
                footers[i].classList.add(HIDDEN_CLASS);
            }
        }

        /**
         * Switches view to the given footer.
         * @memberof ArchiveManager/views/filelist
         * @param {HTMLElement} footer
         */
        function showFooter(footer) {
            hideAllFooters();
            footer.classList.remove(HIDDEN_CLASS);
        }

        /**
         * Activates archive mode.
         * @memberof ArchiveManager/views/filelist
         * @param {boolean} animate When it is set to true,
         * content list is animated during mode changing, otherwise not.
         */
        function activateArchiveMode(animate) {
            mode = ARCHIVE_MODE;
            setFileListAnimated(animate);
            filesList.classList.remove(STANDARD_MODE_CLASS);
            updateHeader();
            navigationPath.classList.add(HIDDEN_CLASS);
            selectAll.classList.remove(HIDDEN_CLASS);
        }

        /**
         * Activates standard mode.
         * @memberof ArchiveManager/views/filelist
         * @param {boolean} animate When it is set to true,
         * content list is animated during mode changing, otherwise not.
         */
        function activateStandardMode(animate) {
            mode = STANDARD_MODE;
            setFileListAnimated(animate);
            filesList.classList.add(STANDARD_MODE_CLASS);
            updateHeader();
            updatePath();
            selectAll.classList.add(HIDDEN_CLASS);
            navigationPath.classList.remove(HIDDEN_CLASS);
        }

        /**
         * Activates preview mode.
         * @memberof ArchiveManager/views/filelist
         * @param {File[]} data
         */
        function activatePreviewMode(data) {
            if (!data) {
                console.error('Invalid param, cannot activate preview mode');
                return;
            }
            mode = PREVIEW_MODE;
            path.goDown(data.name, true);
        }

       /**
         * Handles click event on content list.
         * @param {event} ev
         */
        function onFilesListClick(ev) {
            var element = domHelper.findParent(ev.target, 'li'),
                label = element.getAttribute('label'),
                url = element.getAttribute('url'),
                file = null,
                input = null;

            if (mode === ARCHIVE_MODE) {
                // In archive mode only selections are changed,
                // the elements clicked are not active.

                if (ev.target.tagName.toLowerCase() !== 'input') {
                    input = element.querySelector('input');
                    if (input) {
                        input.checked = !input.checked;
                    }
                }

                e.fire('selection.changed');
                return;
            }

            file = {
                label: label,
                url: url,
                type: ''
            };

            if (element.classList.contains(FOLDER_CLASS)) {
                file.type = FOLDER_CLASS;
            } else if (element.classList.contains(FILE_CLASS)) {
                file.type = FILE_CLASS;
            } else if (element.classList.contains(ZIP_CLASS)) {
                file.type = ZIP_CLASS;
            }

            e.fire('selected', {file: file, mode: mode});
        }

        /**
         * Handles click event on home button.
         */
        function onHomeBtnClick() {
            if (mode !== STANDARD_MODE) {
                activateStandardMode(true);
            }
            path.goHome();
        }

        /**
         * Handles click event on up botton.
         */
        function onUpBtnClick() {
            if (mode === PREVIEW_MODE && path.isHome()) {
                router.navigate('views/modes/standard/show');
            }
            path.goUp();
        }

        /**
         * Handles model.path.changed event.
         * @param {Event} ev
         */
        function onPathChanged(ev) {
            var curentPath = ev.detail.toString();

            if (mode === STANDARD_MODE) {
                if (curentPath === '') {
                    modelFilesystem.getStorages();
                } else {
                    modelFilesystem.getFiles(curentPath);
                }
            } else if (mode === PREVIEW_MODE) {
                if (curentPath !== '') {
                    showFiles(archive.getEntry(curentPath).list);
                } else {
                    showFiles(archive.getRootEntries());
                }
            }

            updateHeader();
            updatePath();
        }

        /**
         * Handles model.filesystem.storages.loaded event.
         * @param {CustomEvent} ev
         */
        function onStoragesLoaded(ev) {
            showStorages(ev.detail.storages);
        }

        /**
         * Handles model.filesystem.files.loaded event.
         * @param {CustomEvent} ev
         */
        function onFilesLoaded(ev) {
            showFiles(ev.detail.files);
        }

        /**
         * Returns current path object.
         * @memberof ArchiveManager/views/filelist
         * @return {Path}
         */
        function getPath() {
            return path;
        }

        /**
         * Returns current mode.
         * @memberof ArchiveManager/views/filelist
         * @return {string}
         */
        function getMode() {
            return mode;
        }

        /**
         * Registers view event listeners.
         */
        function bindEvents() {
            filesList.addEventListener('click', onFilesListClick);
            homeBtn.addEventListener('click', onHomeBtnClick);
            upBtn.addEventListener('click', onUpBtnClick);
        }

        /**
         * Initializes module.
         * @memberof ArchiveManager/views/filelist
         */
        function init() {
            filesList = document.getElementById('files-list');
            homeBtn = document.getElementById('home-button');
            upBtn = document.getElementById('up-button');
            navigationText = document.getElementById('navigation-path-text');
            navigationPath = document.getElementById('navigation-path');
            selectAll = document.getElementById('select-all');
            footers = document.querySelectorAll('div[data-role="footer"]');
            bindEvents();
        }

        e.listeners({
            'model.path.changed': onPathChanged,
            'model.filesystem.storages.loaded': onStoragesLoaded,
            'model.filesystem.files.loaded': onFilesLoaded
        });

        return {
            FOLDER_CLASS: FOLDER_CLASS,
            FILE_CLASS: FILE_CLASS,
            ZIP_CLASS: ZIP_CLASS,
            MOVABLE_CLASS: ANIMATED_CLASS,
            HIDDEN_CLASS: HIDDEN_CLASS,
            DISABLED_CLASS: DISABLED_CLASS,
            BTN_DOWN_S_CLASS: BTN_DOWN_S_CLASS,
            ARCHIVE_SELECTED_CLASS: ARCHIVE_SELECTED_CLASS,

            STANDARD_MODE: STANDARD_MODE,
            ARCHIVE_MODE: ARCHIVE_MODE,
            PREVIEW_MODE: PREVIEW_MODE,

            init: init,
            getSelectedFiles: getSelectedFiles,
            selectArchive: selectArchive,
            deselectArchive: deselectArchive,
            showFooter: showFooter,

            getPath: getPath,
            getMode: getMode,

            activateArchiveMode: activateArchiveMode,
            activateStandardMode: activateStandardMode,
            activatePreviewMode: activatePreviewMode
        };
    }

});
