/* global Controller, Utils, debug, LoadingOverlay, WebviewOverlay,
 Config, ErrorManager, getAppVersion, Status, Config, Sortable, SecurityUI
 */

/**
 *  UIManager.
 *  This code is the one which controls the dom. Will register all listeners
 *  and will forward the actions taken by the user, as rendering methods.
 */

(function (exports) {
    'use strict';
    // List of elements to cache
    var elementIDs = [
        'authenticate',
        'bt-back-button',
        'back-to-startup',
        'main-panel',
        'application-list-empty',
        'refresh-list',
        'applications-list',
        'application-list-submenu',
        'application-list-container',
        'operations-list-container',
        'group-operations-list-container',
        'applications-header-icon-box',
        'applications-header-section',
        'applications-header-log',
        'applications-silent-on',
        'applications-silent-off',
        'back-to-main',
        'add-application',
        'add-application-from-group',
        'lock-all-applications',
        'lock-all-applications-switch',
        'lock-all-operations',
        'lock-all-operations-switch',
        'back-from-pairing',
        'back-from-group',
        'back-from-security',
        'show-pairing-tutorial',
        'back-to-pairing',
        'generate-code',
        'pairing-panel',
        'group-panel',
        'code-generated',
        'code-countdown',
        'code-countdown-remaining-time',
        'open-settings',
        'open-app-settings',
        'close-settings',
        'signout-button',
        'security-button',
        'session-template-container',
        'close-single-session-message',
        'close-all-sessions-confirmation-button',
        'close-single-session-confirmation-button',
        'signin-user',
        'signin-password',
        'signin-error',
        'application-panel',
        'operations-list',
        'group-operations-list',
        'group-operations-list-empty',
        'group-header',
        'applications-header',
        'applications-sub-header',
        'pdm-schedule-toggle',
        'pdm-schedule-header',
        'pdm-autoretrieve-header',
        'pdm-autoclose-toggle',
        'pdm-schedule-start-input',
        'pdm-schedule-start-label',
        'pdm-schedule-end-input',
        'pdm-schedule-end-label',
        'enable-otp-switch',
        'enable-otp-switch-container',
        'enable-schedule-switch',
        'enable-schedule-text',
        'enable-autoclose-switch',
        'enable-autoclose-text',
        'enable-autoclose-by-use-switch',
        'enable-autoclose-by-use-label',
        'enable-autoclose-by-use-text',
        'basic-tutorial-panel',
        'tutorial-navigation',
        'pairing-tutorial-navigation',
        'pairing-tutorial-panel',
        'startup-tutorial-navigation',
        'startup-tutorial-panel',
        'settings-settings-button',
        'resetpassword-button',
        'settings-tutorial-button',
        'settings-support-button',
        'settings-privacy-button',
        'settings-about-button',
        'settings-signed-as',
        'signin-panel',
        'signin-register',
        'signin-forgot-password',
        'submenu-rename',
        'submenu-delete',
        'submenu-silent',
        'submenu-remove-from-group',
        'submenu-delete-confirmed',
        'submenu-delete-group-openModal',
        'submenu-move',
        'submenu-move-name',
        'submenu-move-openModal',
        'submenu-move-create',
        'submenu-move-cancel',
        'submenu-move-move',
        'current-cover',
        'next-cover',
        'pdm-schedule-container',
        'pdm-autoretrieve-container',
        'enable-opt-switch-container',
        'enable-autoclose-container',
        'enable-autoclose-by-use-container',
        'login-version',
        'startup-version',
        'startup-tutorial-step1-login',
        'startup-tutorial-login',
        'startup-step-6-contact',
        'startup-tutorial-register',
        'enable-schedule-container',
        'autolock-label',
        'html',
        'operations-total-lock-info',
        'submenu-log',
        'log-header',
        'back-from-log',
        'log-entries-list',
        'log-entries-list-empty',
        'log-from-date',
        'log-to-date',
        'log-filter',
        'log-filter-close-button',
        'log-filter-openModal',
        'log-statistics-banner',
        'log-statistics-openModal',
        'log-today',
        'log-date-range',
        'log-subheader',
        'rename-openModal',
        'rename-name',
        'rename-rename',
        'rename-cancel',
        'blocked-openModal',
        'blocked-confirmed',
        'blocked-alert-info',
        'blocked-alert-latchon',
        'blue-ribbon',
        'blue-ribbon-from',
        'blue-ribbon-to',
        'change-password-container'
    ];

    // This object is the 'View' itself. UIManager controls the action from/to the
    // 'View' (in this case the DOM)      
    var dom = {};

    // Need to be global to be able to clean it from different functions
    var pairingTimer = null;

    // Fallback image for services 
    var DEFAULT_SERVICE_IMG = '/styles/images/default.png';

    function _cleanPairing() {
        dom.pairingPanel.classList.remove('generate-code');
        dom.codeGenerated.textContent = '';
        dom.generateCode.disabled = false;
        clearInterval(pairingTimer);
    }

    function _getApplicationOrderList(container) {

        var listItems = container.querySelectorAll('li.app, li.group');
        var appList = [];

        Object.keys(listItems).forEach(function (currentIndex) {

            var currentId = listItems[currentIndex].dataset.opid;
            appList.push(currentId);

        });
        return appList;
    }

    function _childrenHaveBeenExternallyUpdatedForGroup(listOfOpIds) {
        var rootOperation = false;
        for (var i = 0; i < listOfOpIds.length; i++) {
            var currentOpId = listOfOpIds[i];

            var updated = _childrenHaveBeenExternallyUpdated(currentOpId, rootOperation);
            if (updated) {
                return true;
            }
        }
        return false;
    }

    function _childrenHaveBeenExternallyUpdated(opId, rootOperation) {

        var operation;

        Controller.getOperations(opId, function (mappedOperation) {
            operation = mappedOperation;
        }, false);

        if (rootOperation) {
            if (!operation.hasOwnProperty('operations') || operation.operations === null || Object.keys(operation.operations).length === 0) {
                return false;
            }
        } else {
            if (operation.hasOwnProperty('externallyUpdated')) {
                return true;
            }
        }
        if (!operation.hasOwnProperty('operations') || operation.operations === null) {
            return false;
        }

        for (var i = 0; i < Object.keys(operation.operations).length; i++) {

            var currentOpId = Object.keys(operation.operations)[i];

            if (_childrenHaveBeenExternallyUpdated(currentOpId, false)) {
                return true;
            }
        }

        return false;

    }
    function _loginPeriodTimedOut(callback) {
        Controller.getPreferences(function (err, data) {
            var passwordAskingTime = data.passwordAskingTime;
            if (passwordAskingTime < 0) {
                callback(false);
                return;
            }

// Use == instead of ===
            if (passwordAskingTime == 0) {
                callback(true);
                return;
            }

            Controller.getLastLogin(function (data) {

                var loginDateMilliseconds = new Date(data);
                var currentDateMilliseconds = new Date();
                callback(currentDateMilliseconds - loginDateMilliseconds > 1000 * passwordAskingTime);
                return;
            });
        });
    }

    function _reorder(appObject) {
        var apps = [];

        Object.keys(appObject).forEach(function (opID) {
            var app = appObject[opID];
            apps.push({opID: opID, app: app});
        });

        _sortByOrder(apps);

        return apps;
    }

    function _sortByOrder(arr) {
        arr.sort(function (a, b) {

            var bothHaveOrder = a.app.hasOwnProperty('order') && b.app.hasOwnProperty('order');

            if (!bothHaveOrder) {
                return 0;
            }

            if (a.app.order > b.app.order) {
                return 1;
            }
            if (a.app.order < b.app.order) {
                return -1;
            }

            return 0;
        });
    }

    function enableReorder(enable, list) {
        var listItems = list.querySelectorAll('li');
        for (var i = 0; i < listItems.length; i++) {
            var currentListItem = listItems[i];
            if (!currentListItem.classList.contains('application-list-submenu')) {
                if (enable) {
                    currentListItem.classList.add('allow-sorting');
                }
                else {
                    currentListItem.classList.remove('allow-sorting');
                }
            }
        }
    }

    var submenuTimeout;
    var reorderTimeout;
    var longClick = false;
    var moving = false;
    var subMenuShown = false;
    var firstClickPerformed = false;

    function _createOperationDOMForGroup(li, group) {
        li.classList.add('group');

        var icon = document.createElement('i');
        var groupName = document.createElement('p');
        groupName.textContent = group.customName;

        var arrow = document.createElement('i');


        if (_childrenHaveBeenExternallyUpdatedForGroup(group.apps)) {
            arrow.classList.add('orange-circle');
        }

        li.appendChild(icon);
        li.appendChild(groupName);
        li.appendChild(arrow);

        var latchonStatus = (Controller.getLocalLatchon() && Controller.getLocalLatchon().status) || 'on';
        if (latchonStatus === 'off') {
            li.classList.add('greyCover');
        }
        else {
            li.classList.remove('greyCover');
        }
    }

    function _createOperationDomForAppOrOperation(li, opID, operation, topOp) {

        li.classList.add('app');

        li.dataset.defaultName = operation.name;

        var aside = document.createElement('aside');
        aside.className = 'pack-end';

        var label = document.createElement('label');
        label.className = 'pack-switch';

        if (operation.status === 'interval') {
            label.classList.add('schedule-switch');
        }

        if (operation.hasOwnProperty('externallyUpdated')) {
            label.classList.add('orange-switch');
        }

        if (operation.skipPush && (operation.skipPush === true || operation.skipPush === 'true')) {
            li.classList.add('silent');
        }

        if (operation.satellite && operation.satellite === 'true') {
            li.classList.add('satellite');
        }

        if (operation.satellite === true || operation.satellite === 'true') {
            li.classList.add('satellite');
        }

        var rootOperation = true;
        if (_childrenHaveBeenExternallyUpdated(opID, rootOperation)) {
            label.classList.add('orange-circle');
        }

        var input = document.createElement('input');
        input.type = 'checkbox';
        input.dataset.opid = opID;

        var onOffStatus = operation.status === 'interval' ? _getStatusFromInterval(operation.from, operation.to) : operation.status;
        input.checked = onOffStatus === 'off';

        var span = document.createElement('span');

        label.appendChild(input);
        label.appendChild(span);

        aside.appendChild(label);

        var a = document.createElement('a');
        a.dataset.opid = opID;

        var pTitle = document.createElement('p');
        pTitle.textContent = Utils.chooseName(operation);
        var pSubtitle = document.createElement('p');
        var _ = navigator.mozL10n.get;
        pSubtitle.dataset.opstatus = operation.status;

        a.appendChild(pTitle);
        a.appendChild(pSubtitle);

        li.appendChild(aside);
        if (topOp) {
            _addLogoToOperation(operation, li);
        }

        if (operation.groupId !== undefined) {
            li.dataset.groupId = operation.groupId;
        }

        li.appendChild(a);

        var silentIcon = document.createElement('i');
        li.appendChild(silentIcon);

        var satelliteIcon = document.createElement('i');
        li.appendChild(satelliteIcon);

        // If latchon app does not exist, latchon UI switch is open
        var latchonStatus = (Controller.getLocalLatchon() && Controller.getLocalLatchon().status) || 'on';
        var operationDisabled = operation.subscription && operation.subscription === 'disabled';

        if (latchonStatus === 'off' || operationDisabled) {
            input.disabled = true;
            li.classList.add('greyCover');
        }
        else {
            input.disabled = false;
            li.classList.remove('greyCover');
        }

        if (operationDisabled) {
            li.classList.add('disabledMark');

        }
        else {
            li.classList.remove('disabledMark');
        }
    }

    function _getParentOfClass(element, type) {
        if (element.classList.contains(type)) {
            return element;
        }
        if (element.parentNode) {
            return _getParentOfClass(element.parentNode, type);
        }
    }

    function _getLiParent(element) {
        if (element.nodeName === 'LI') {
            return element;
        }
        if (element.parentNode) {
            return _getLiParent(element.parentNode);
        }
    }

    function _touchStart(e, operation) {

        var li = _getLiParent(e.target);

        var parentOpSwitch = operation.parent === null ? dom.lockAllApplicationsSwitch : dom.lockAllOperationsSwitch;
        var parentOpBlocked = parentOpSwitch.dataset.checked === 'true';

        if (!parentOpBlocked) {
            reorderTimeout = setTimeout(function () {

                if (!moving) {

                    window.navigator.vibrate(50);
                    enableReorder(true, li.parentNode);

                    submenuTimeout = setTimeout(function () {

                        var liIsBeingReordered = li.getAttribute('draggable') === 'true';

                        if (!liIsBeingReordered) {

                            enableReorder(false, li.parentNode);

                            window.navigator.vibrate(50);
                            longClick = true;
                            var subMenu = dom.applicationListSubmenu;

                            // If subMenu is already being shown, restore previous app visibility
                            if (!subMenu.classList.contains('hide')) {
                                subMenu.nextSibling.classList.remove('hide');
                                firstClickPerformed = false;
                            }

                            var container = li.parentNode;
                            container.insertBefore(subMenu, li);
                            firstClickPerformed = true;

                            _disableEventsInSubmenu();

                            var isGroup = operation.status === undefined;
                            if (isGroup) {
                                subMenu.classList.add('submenu-group');
                                subMenu.classList.remove('submenu-app');
                                subMenu.classList.remove('submenu-app-in-group');
                            }
                            else {

                                var hasGroup = operation.groupId !== undefined;
                                dom.applicationListSubmenu.dataset.opid = li.dataset.opid;

                                if (!hasGroup) {
                                    subMenu.classList.add('submenu-app');
                                    subMenu.classList.remove('submenu-group');
                                    subMenu.classList.remove('submenu-app-in-group');
                                }
                                else {
                                    subMenu.classList.add('submenu-app-in-group');
                                    subMenu.classList.remove('submenu-app');
                                    subMenu.classList.remove('submenu-group');
                                }

                                var hasChildren = operation.operations && Object.keys(operation.operations).length > 0;
                                if (hasChildren) {
                                    dom.submenuLog.classList.add('hide');
                                }
                                else {
                                    dom.submenuLog.classList.remove('hide');
                                }

                            }

                            // Silent icon
                            dom.submenuSilent.classList.add('silent-on');
                            dom.submenuSilent.classList.remove('silent-off');
                            var iconText = dom.applicationListSubmenu.querySelector('#submenu-silent span');
                            iconText.textContent = navigator.mozL10n.get('submenu-silent-on');
                            if ((operation.skipPush === true || operation.skipPush === 'true') && dom.submenuSilent.classList.contains('silent-on')) {
                                _toggleSilentUserInterface();
                            }

                            subMenu.classList.remove('hide');
                            li.classList.add('hide');
                        }
                    }, 1000);
                }

            }, 500);
        }
    }

    function _touchend(e) {
        if (longClick) {
            subMenuShown = true;
            setTimeout(function () {
                _enableEventsInSubmenu();
            }, 500);
        }

        var list = _getLiParent(e.target).parentNode;

        enableReorder(false, list);
        longClick = false;
        moving = false;
        clearTimeout(submenuTimeout);
        clearTimeout(reorderTimeout);
    }

    /**
     *  Private method for creating an 'operation' element in DOM
     *  @parameter opID Application/Operation ID
     *  @parameter operation Operation Object with all the info
     *  @topOp boolean True if is a top operation
     *  @return Element created
     */
    function _createOperationDOM(operation, opID, topOp) {

        debug('_createOperationDOM ' + opID);

        var li = document.createElement('li');
        li.dataset.opid = opID;

        var isGroup = operation.status === undefined;

        if (isGroup) {
            _createOperationDOMForGroup(li, operation);
        } else {
            _createOperationDomForAppOrOperation(li, opID, operation, topOp);
        }

        li.addEventListener('touchmove', function () {
            moving = true;
        });

        li.addEventListener('touchstart', function (e) {
            _touchStart(e, operation);
        });

        li.addEventListener('touchend', function (e) {
            _touchend(e);
        });


        return li;
    }

    // Private function to generate the logo in the
    // applications list.
    function _addLogoToOperation(operation, li) {
        var asideLogo = document.createElement('aside');
        var logoImg = document.createElement('img');

        // preload the default image
        logoImg.src = DEFAULT_SERVICE_IMG;

        // create a new image with the proper source
        if (operation.imageURL) {
            var newImg = new Image();
            newImg.onload = function () {
                logoImg.src = this.src;
            };
            newImg.src = operation.imageURL;
        }

        logoImg.classList.add('operationLogo');
        asideLogo.appendChild(logoImg);
        li.appendChild(asideLogo);
    }


    function _openGroupList(groupID) {

        var forceUpdate = true;
        Controller.loadGroupOperations(
                groupID,
                function (groupName, apps) {

                    debug('UI > _openGroupList');
                    _updateGroupHeader(groupName);

                    // Clear list
                    var listItems = dom.groupOperationsList.querySelectorAll('li');
                    for (var i = 0; i < listItems.length; i++) {
                        var parentNode = listItems[i].parentNode;
                        parentNode.removeChild(listItems[i]);
                    }

                    if (apps && Object.keys(apps).length > 0) {

                        dom.groupOperationsListEmpty.classList.add('hide');
                        dom.groupOperationsList.classList.remove('hide');

                        var orderedApps = _reorder(apps);

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

                            var topOp = true;
                            var operation = orderedApps[i].app;
                            var opId = orderedApps[i].opID;

                            var li = _createOperationDOM(operation, opId, topOp);

                            dom.groupOperationsList.appendChild(li);
                        }

                        var container = dom.groupOperationsList;

                        _orangeRibbonNeeded(container, function (needed) {
                            if (needed && !_isOrangeRibbonShown(container)) {
                                var ribbon = createOrangeRibbon();
                                container.insertBefore(ribbon, container.firstChild);
                            }
                        });
                    }
                    else {
                        dom.groupOperationsListEmpty.classList.remove('hide');
                        dom.groupOperationsList.classList.add('hide');
                    }
                    UIManager.load('group');

                }, forceUpdate);
    }

    /**
     *  Private method for opening an 'operation' list
     *  @parameter opID Application/Operation ID
     */
    function _openOperationsList(opID, forceUpdate) {
        Controller.loadOperations(
                opID,
                function onOperation(err, operation) {
                    if (err) {
                        ErrorManager.checkError(err);
                        debug('Error executing Controller.loadOperations');
                        return;
                    }
                    // Update the style
                    dom.applicationPanel.classList.remove('detail');
                    dom.applicationPanel.classList.add('tree');
                    // Render the operations
                    _renderOperations(operation.operations, dom.operationsList);
                    // Render main lock
                    _renderOperationsLatchon(operation, opID);
                    // Update the header
                    _updateOperationsHeader(operation);
                    // Disable operations if parent operations is locked
                    _updateDisabledOperations(operation.status, dom.operationsList);
                    // Update current operation status
                    if (operation.hasOwnProperty('externallyUpdated')) {
                        dom.lockAllOperationsSwitch.classList.add('orange-switch');
                    } else {
                        dom.lockAllOperationsSwitch.classList.remove('orange-switch');
                    }
                    dom.lockAllOperationsSwitch.dataset.opId = opID;
                    dom.lockAllOperationsSwitch.dataset.checked = operation.status === 'off';
                    if (dom.lockAllOperationsSwitch.dataset.checked === 'true') {
                        _showTotalLock();
                    }
                    else {
                        dom.operationsTotalLockInfo.classList.add('hide');
                    }

                    dom.applicationsHeaderSection.classList.remove('detail');
                    // Go to the right panel
                    UIManager.load('application');

                },
                function onDetail(err, operation, opID) {
                    if (!ErrorManager.checkError(err)) {
                        debug('Error executing Controller.loadOperations');
                        return;
                    }
                    // Update the style
                    dom.applicationPanel.classList.remove('tree');
                    dom.applicationPanel.classList.add('detail');
                    // Render details
                    _renderOpDetails(operation, opID);
                    dom.lockAllOperationsSwitch.dataset.opId = opID;
                    // Update the header
                    _updateOperationsHeader(operation);
                    // Update buttons in header
                    _updateButtonsInHeader(operation);
                    // Go to the right panel
                    dom.applicationsHeaderSection.classList.add('detail');
                    UIManager.load('application');
                }, forceUpdate);
    }


    function _updateGroupHeader(customName) {
        dom.groupHeader.textContent = customName;
    }

    /**
     *  Private method for updating the headers
     *  @parameter operation Object json object representing the op
     */
    function _updateOperationsHeader(operation) {
        debug('_updateOperationsHeader of ' + operation.id);
        var headerbox = dom.applicationsHeader.parentNode;
        if (operation.parent) {
            headerbox.classList.add('subheader');

            dom.applicationsHeader.textContent = Utils.chooseName(operation.parent);
            dom.applicationsSubHeader.textContent = Utils.chooseName(operation);
            dom.applicationsSubHeader.classList.remove('hide');
            dom.applicationsSubHeader.dataset.opid = operation.id;
            dom.applicationsSubHeader.dataset.defaultName = operation.name;
        } else {
            headerbox.classList.remove('subheader');

            dom.applicationsHeader.textContent = Utils.chooseName(operation);
            dom.applicationsHeader.dataset.opid = operation.id;
            dom.applicationsHeader.dataset.defaultName = operation.name;

            dom.applicationsSubHeader.classList.add('hide');
        }
    }

    function _updateButtonsInHeader(operation) {

        function updateButtonVisibility(skipPush) {
            if (skipPush) {
                dom.applicationsSilentOn.classList.add('hide');
                dom.applicationsSilentOff.classList.remove('hide');
            }
            else {
                dom.applicationsSilentOn.classList.remove('hide');
                dom.applicationsSilentOff.classList.add('hide');
            }
        }

        updateButtonVisibility(operation.skipPush);

        _removeAllEvents('applicationsHeaderLog');
        _removeAllEvents('applicationsSilentOn');
        _removeAllEvents('applicationsSilentOff');

        var opId, operationName;

        if (operation.parent) {
            opId = dom.applicationsSubHeader.dataset.opid;
            operationName = dom.applicationsSubHeader.textContent;
        } else {
            opId = dom.applicationsHeader.dataset.opid;
            operationName = dom.applicationsHeader.textContent;
        }

        dom.applicationsHeaderLog.addEventListener('click', function (e) {
            _renderLog(opId, operationName);
            UIManager.load('log');
        });

        dom.applicationsSilentOn.addEventListener('click', function () {
            var skipPush = true;
            updateButtonVisibility(skipPush);
            Controller.skipPush(opId, skipPush, function (err) {
                if (err) {
                    updateButtonVisibility(!skipPush);
                }
            });
        });

        dom.applicationsSilentOff.addEventListener('click', function () {
            var skipPush = false;
            updateButtonVisibility(skipPush);
            Controller.skipPush(opId, skipPush, function (err) {
                if (err) {
                    updateButtonVisibility(!skipPush);
                }
            });
        });
    }

    /**
     *  Private method for disabling or enabling the suboperations 
     *  @parameter operation Object json object representing the parent operation
     */
    function _updateDisabledOperations(status, container) {
        debug('_updateDisabledOperations with status ' + status);

        var listItems = container.querySelectorAll('li');

        Object.keys(listItems).forEach(function (currentIndex) {

            var currentListItem = listItems[currentIndex];

            if (status === 'off') {
                currentListItem.classList.add('greyCover');
                currentListItem.querySelectorAll('input')[0].disabled = true;
            }
            else {
                currentListItem.classList.remove('greyCover');
            }
        });

    }

    function _updateGreyCoverOnApps(latchonStatus, listItems) {
        Object.keys(listItems).forEach(function (currentIndex) {

            var currentListItem = listItems[currentIndex];

            var isGroup = currentListItem.classList.contains('group');

            if (!isGroup) {
                var checkbox = currentListItem.querySelector("input[type='checkbox']");
                var disabled = currentListItem.classList.contains('disabledMark');

                if (!disabled) {
                    if (latchonStatus === 'off') {
                        currentListItem.classList.add('greyCover');
                        checkbox.disabled = true;
                    }
                    else {
                        currentListItem.classList.remove('greyCover');
                        checkbox.disabled = false;
                    }
                }
            }
            else {
                if (latchonStatus === 'off') {
                    currentListItem.classList.add('greyCover');
                }
                else {
                    currentListItem.classList.remove('greyCover');
                }
            }
        });

//        Object.keys(checkboxes).forEach(function (currentIndex) {
//
//            checkboxes[currentIndex].disabled = latchonStatus === 'off';
//
//        });
    }

    function _getMoveLatchonParameters(latchon, status, faster) {
        var parameters = {};
        var latchonLimits = _getLatchonLimits(latchon);
        parameters.currentLimit = status === 'on' ? latchonLimits.minimumLeftMargin : latchonLimits.maximumLeftMargin;
        parameters.opacity = status === 'on' ? 0 : 1;
        parameters.speedMultiplier = faster ? 3 : 1;
        parameters.latchon = latchon;
        parameters.status = status;
        return parameters;
    }

    /**
     * Private function that handles the actions when lock-all checkbox is changed
     * Updates the value of all the operations existing on the container provided
     * with the current value of the target.
     * @parameter target Checkbox that changed status
     * @parameter container Where the checkboxes that need change are placed
     */
    function _updateLockAllApplications(latchon, container) {

        var status = latchon.dataset.checked === 'true' ? 'off' : 'on';
        var opId = latchon.dataset.opId;

        var listItems = container.querySelectorAll('li.app, li.group');

        _updateGreyCoverOnApps(status, listItems);

        Controller.updateStatus(
                opId,
                status,
                function callback(err) {
                    if (!ErrorManager.checkError(err)) {
                        //If error, we show previous status
                        var previousStatus = status === 'on' ? 'off' : 'on';
                        var parameters = _getMoveLatchonParameters(latchon, previousStatus, true);

                        _softlyMoveLatchon(parameters, function () {
                            _updateGreyCoverOnApps(previousStatus, listItems);
                            _performLatchonAnimation(latchon.parentNode, parameters.opacity);
                        });
                        return;
                    }
                });
    }


    function _changeOperationNameFromHeader(target) {

        var previousName = target.textContent;
        var opId = target.dataset.opid;
        var newName = dom.renameName.value.trim();
        target.textContent = newName === '' ? target.dataset.defaultName : newName;

        Controller.updateName(
                opId,
                newName,
                function callback(err) {
                    if (!ErrorManager.checkError(err)) {
                        // Revert
                        target.textContent = previousName;
                        return;
                    }

                });

        // Refresh local map
        Controller.getOperations(null,
                function () {
                    return;
                },
                true);

        UIManager.load('application');
    }

    function _getAppInfoFromListItem(li) {
        var opId = li.dataset.opid;
        var groupId = li.dataset.groupId;
        var nameTextBox = li.querySelector('p');
        var defaultName = li.dataset.defaultName;
        return {
            name: nameTextBox.textContent,
            textbox: nameTextBox,
            opId: opId,
            groupId: groupId,
            defaultName: defaultName};
    }

    function _changeOperationNameFromSubMenu() {

        var li = dom.applicationListSubmenu.nextSibling;

        var infoFromLi = _getAppInfoFromListItem(li);
        var previousName = infoFromLi.name;
        var previousNameTextBox = infoFromLi.textbox;
        var opId = infoFromLi.opId;

        var newName = dom.renameName.value.trim();

        var container = li.parentNode;
        _hideSubMenu(container);

        if (newName === '' && li.classList.contains('group')) {
            Status.show(navigator.mozL10n.get('groups-none-selected'));
            return;
        }

        previousNameTextBox.textContent = newName !== '' ? newName : infoFromLi.defaultName;

        Controller.updateName(
                opId,
                newName,
                function callback(err) {
                    if (!ErrorManager.checkError(err)) {
                        // Revert
                        previousNameTextBox.textContent = previousName;
                        return;
                    }

                });

        // Refresh local map
        Controller.getOperations(null,
                function () {
                    return;
                },
                true);
    }

    function _addAppToGroup() {
        var opId = dom.applicationListSubmenu.nextSibling.dataset.opid;

        Controller.getOperations(opId, function (operation) {

            var checkedListItem = dom.submenuMoveOpenModal.querySelector('li.checked');

            var aGroupIsSelected = checkedListItem !== null;

            if (aGroupIsSelected) {
                var groupID = checkedListItem.dataset.opId;

                var hadGroup = _removeAppFromGroupIfAny(opId, operation);
                var previousGroup = operation.groupId;

                Controller.addAppToGroup(opId, groupID);

                if (hadGroup) {
                    _openGroupList(previousGroup);
                    // Refresh main panel but do not show
                    _renderRootOperations(true);
                }
                else {
                    _renderRootOperations();
                }
            }
            else {
                var groupId = operation.groupId;
                Controller.removeAppFromGroup(opId, groupId);
                _openGroupList(groupId);
            }
        });

    }

    function _removeAppFromGroupIfAny(opId, operation) {
        var hasGroup = operation.groupId !== undefined;
        if (hasGroup) {
            Controller.removeAppFromGroup(opId, operation.groupId);
        }
        return hasGroup;
    }

    function _createNewGroup() {
        var newName = dom.submenuMoveName.value.trim();

        if (!newName) {
            Status.show(navigator.mozL10n.get('groups-none-selected'));
            _hideSubMenu(dom.applicationListContainer);
            return;
        }

        var opId = dom.applicationListSubmenu.dataset.opid;

        Controller.getOperations(opId, function (operation) {

            var hadGroup = _removeAppFromGroupIfAny(opId, operation);
            Controller.createGroup(newName, opId, function () {
                if (hadGroup) {
                    var groupID = operation.groupId;
                    _openGroupList(groupID);

                    // Refresh main panel but do not show
                    _renderRootOperations(true);
                }
                else {
                    _renderRootOperations();
                }
            });
        });
    }

    function _deleteGroup(groupId) {

        Controller.deleteGroup(groupId, function () {
            _renderRootOperations();
        });
    }

    function _createGroupModalEntry(name, opId) {
        var node = document.createElement("li");
        node.dataset.opId = opId;

        var icon = document.createElement("i");

        var text = document.createElement("p");
        text.textContent = name;

        var checkedIcon = document.createElement("i");

        node.appendChild(icon);
        node.appendChild(text);
        node.appendChild(checkedIcon);

        return node;
    }

    var groupModalShown = false;

    function _hideGroupModal() {
        dom.submenuMoveOpenModal.classList.add('hide');
        groupModalShown = false;
    }

    function _unhideGroupModal() {
        dom.submenuMoveOpenModal.classList.remove('hide');
        groupModalShown = true;
    }

    function _clearAllCheckedElementsInModal(ul) {
        var childNodes = ul.childNodes;
        for (var i = 0; i < childNodes.length; i++) {
            childNodes[i].dataset.selected = false;
            childNodes[i].classList.remove('checked');
        }
    }

    function _displayGroupModal(target) {

        window.location = "#submenu-move-openModal";

        var li = _getLiParent(target).nextSibling;
        var appInfo = _getAppInfoFromListItem(li);
        var opId = appInfo.opId;
        var ul = dom.submenuMoveOpenModal.querySelector('ul');
        dom.submenuMoveName.value = '';

        ul.innerHTML = '';

        Controller.getOperations(opId, function (operation) {
            Controller.loadGroups(function (groups) {

                var groupList = Object.keys(groups);

                // Show create button
                dom.submenuMoveMove.classList.add('hide');
                dom.submenuMoveCreate.classList.remove('hide');

                groupList.forEach(function (currentGroupId) {
                    var name = groups[currentGroupId].customName;
                    var newNode = _createGroupModalEntry(name, currentGroupId);
                    if (operation.groupId && operation.groupId === currentGroupId) {
                        newNode.classList.add('checked');
                        dom.submenuMoveCreate.classList.add('hide');
                        dom.submenuMoveMove.classList.remove('hide');
                    }
                    ul.appendChild(newNode);

                    newNode.addEventListener('click', function () {

                        dom.submenuMoveName.value = '';
                        var previousNode = ul.querySelector('.checked');
                        _clearAllCheckedElementsInModal(ul);

                        if (previousNode !== newNode) {
                            dom.submenuMoveCreate.classList.add('hide');
                            dom.submenuMoveMove.classList.remove('hide');
                            newNode.classList.add('checked');
                        }
                    });
                });

                _unhideGroupModal();

            });
        });
    }

    function _displayDeleteGroupModal(target) {
        var modal = dom.submenuDeleteGroupOpenModal;
        var message = modal.querySelector('p');
        var li = _getLiParent(target).nextSibling;
        var info = _getAppInfoFromListItem(li);
        var opId = info.opId;

        var forceUpdate = false;
        Controller.loadGroupOperations(opId, function (groupName, appList) {
            
            var maxGroupNameLength = 20;
            var shortenedGroupName = groupName.length < maxGroupNameLength ? groupName : groupName.substr(0, maxGroupNameLength) + '(...)';

            // Set message
            var l10nKey = Object.keys(appList).length === 0 ? 'submenu-delete-group-confirmation-empty' : 'submenu-delete-group-confirmation-nonempty';
            navigator.mozL10n.localize(
                    message, // Element
                    l10nKey, // l10n Key
                    {
                        group: shortenedGroupName        // Params
                    }
            );

            window.location = "#submenu-delete-group-openModal";
        }, forceUpdate);
    }

    function _removeOrangeRibbon(container) {

        var orangeRibbon = container.querySelector('.orangeRibbon');

        if (orangeRibbon) {
            orangeRibbon.parentNode.removeChild(orangeRibbon);
        }
    }

    function _renderLog(opId, operationName) {

        dom.logEntriesList.setAttribute('scope', 'today');
        dom.logEntriesList.setAttribute('opId', opId);
        dom.logDateRange.classList.remove('selected');
        dom.logToday.classList.add('selected');

        dom.logEntriesList.innerHTML = "";

        var from = Utils.getBeginningOfDay();
        var to = Utils.getEndOfDay();

        _createAndAppendLogNodes(from, to, opId);


        dom.logHeader.textContent = navigator.mozL10n.get('log-title') + ' ' + operationName;
        debug('Log loaded!');
    }

    function _reloadLog() {

        var scope = dom.logEntriesList.getAttribute('scope');
        var opId = dom.logEntriesList.getAttribute('opid');

        var from, to;

        if (scope === 'today') {
            from = Utils.getBeginningOfDay();
            to = Utils.getEndOfDay();
        }
        else {

            var fromTimestamp = parseInt(dom.logFromDate.getAttribute('timestamp'));
            var toTimestamp = parseInt(dom.logToDate.getAttribute('timestamp'));

            from = Utils.getBeginningOfDay(new Date(fromTimestamp));
            to = Utils.getEndOfDay(new Date(toTimestamp));
        }

        dom.logEntriesList.innerHTML = "";

        _createAndAppendLogNodes(from, to, opId);
    }

    function _reloadLogToday() {
        dom.logEntriesList.setAttribute('scope', 'today');
        dom.logDateRange.classList.remove('selected');
        dom.logToday.classList.add('selected');

        _reloadLog();
    }

    function _reloadLogRange() {
        if (_fromAndToSetInLogDateRange()) {
            dom.logEntriesList.setAttribute('scope', 'range');
            dom.logToday.classList.remove('selected');
            dom.logDateRange.classList.add('selected');

            _reloadLog();
        }
    }

    function _createAndAppendLogNodes(from, to, opId) {

        function translateStatNames(serverName) {
            switch (serverName) {
                case 'disabled':
                    return 'disabledByProvider';
                case 'enabled':
                    return 'restored';
                case 'extUpdatesOff':
                case 'extUpdatesOn':
                    return 'modified';
                case 'statusOff' :
                    return 'attempt';
                case 'statusOn':
                    return 'accessed';
                case 'updatesOff' :
                    return 'locked';
                case 'updatesOn':
                    return 'unlocked';
            }
        }

        Controller.getLog(from, to, opId, function (err, data) {
            if (!ErrorManager.checkError(err)) {
                debug('Error ocurred while loading log');
                return;
            }
            else {

                var empty = true;

                var logEntries = data.history;
                debug('Filtered entries: ' + JSON.stringify(logEntries));
                var numberOfLogEntries = logEntries.length;
                for (var i = 0; i < numberOfLogEntries; i++) {
                    var currentEntry = logEntries[i];
                    dom.logEntriesList.appendChild(_createSingleLogEntryNode(currentEntry));
                    empty &= currentEntry.hide;
                }

                if (empty) {
                    dom.logEntriesList.classList.add('hide');
                    dom.logEntriesListEmpty.classList.remove('hide');
                }
                else {
                    dom.logEntriesList.classList.remove('hide');
                    dom.logEntriesListEmpty.classList.add('hide');
                }

                delete data.history;
                delete data.count;

                var modifiedCount = 0;

                Object.keys(data).forEach(function (currentType) {
                    var currentTranslatedType = translateStatNames(currentType);
                    if (currentTranslatedType !== 'modified') {
                        dom.logStatisticsOpenModal.dataset[currentTranslatedType] = data[currentType];
                    }
                    else {
                        modifiedCount += data[currentType];
                    }
                    dom.logStatisticsOpenModal.dataset['modified'] = modifiedCount;
                });
            }
        });
    }

    function _createSingleLogEntryNode(logEntry) {
        var hide = logEntry.hide;
        var node = document.createElement("li");
        node.classList.add('logEntry');
        node.classList.add(logEntry.type);
        if (hide) {
            node.classList.add('hide');
        }
        else {
            node.classList.remove('hide');
        }

        var icon = document.createElement("div");
        icon.classList.add('icon');

        var text = document.createElement("div");
        text.classList.add('text');
        text.textContent = navigator.mozL10n.get('log-type-' + logEntry.type);

        var dateTime = document.createElement("div");
        dateTime.classList.add('dateTime');
        dateTime.textContent = logEntry.dateTime.date + ' ';

        var span = document.createElement("span");
        span.textContent = logEntry.dateTime.time;
        dateTime.appendChild(span);

        node.appendChild(icon);
        node.appendChild(text);
        node.appendChild(dateTime);

        return node;
    }

    function _displayLogFilter() {
        debug('Displaying log filter');

        var list = dom.logFilterOpenModal.querySelector('ul');
        list.innerHTML = '';

        var logEntryTypes = Controller.getLogEntryTypes();

        Controller.retrieveLogFilter(function (filter) {

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

                var currentType = logEntryTypes[i];
                var currentListItem = document.createElement('li');
                currentListItem.classList.add(currentType);

                var icon = document.createElement('i');
                currentListItem.appendChild(icon);

                var text = document.createElement('p');
                text.classList.add('text');
                text.textContent = navigator.mozL10n.get('log-type-' + currentType);
                currentListItem.appendChild(text);

                var check = document.createElement('i');
                currentListItem.appendChild(check);

                currentListItem.addEventListener('click', function (e) {
                    _getLiParent(e.target).classList.toggle('checked');
                });

                var checked = filter.indexOf(currentType) >= 0;
                if (checked) {
                    currentListItem.classList.add('checked');
                } else {
                    currentListItem.classList.remove('checked');
                }

                list.appendChild(currentListItem);
            }
        });

    }

    function _updateLog(selectedOptions) {
        debug('Updating log');

        var empty = true;
        var allEntries = dom.logEntriesList.querySelectorAll('.logEntry');
        for (var i = 0; i < allEntries.length; i++) {
            var currentEntry = allEntries[i];
            var currentType = currentEntry.className.replace('logEntry', '').trim().replace('hide', '').trim();

            var hideThisEntry = selectedOptions.indexOf(currentType) === -1;
            if (hideThisEntry) {
                currentEntry.classList.add('hide');
            }
            else {
                currentEntry.classList.remove('hide');
            }

            empty &= hideThisEntry;
        }

        if (empty) {
            dom.logEntriesList.classList.add('hide');
            dom.logEntriesListEmpty.classList.remove('hide');
        }
        else {
            dom.logEntriesList.classList.remove('hide');
            dom.logEntriesListEmpty.classList.add('hide');
        }
    }

    function _displayStatsDialog() {

        var header = dom.logStatisticsOpenModal.querySelector('h2');

        var selectedPeriod = '';
        if (dom.logEntriesList.getAttribute('scope') === 'today') {
            selectedPeriod = navigator.mozL10n.get('today');
        }
        else {
            var fromDate = dom.logFromDate.textContent;
            var toDate = dom.logToDate.textContent;

            selectedPeriod = fromDate + ' - ' + toDate;
        }

        header.textContent = navigator.mozL10n.get('log-statistics') + ' (' + selectedPeriod + ')';

        Controller.retrieveLogFilter(function (filteredTypes) {
            var list = dom.logStatisticsOpenModal.querySelector('ul');
            list.innerHTML = '';

            var allTypes = Controller.getLogEntryTypes();

            for (var i = 0; i < allTypes.length; i++) {
                var currentType = allTypes[i];
                var currentListItem = document.createElement('li');
                currentListItem.classList.add(currentType);

                var icon = document.createElement('i');
                currentListItem.appendChild(icon);

                var text = document.createElement('p');
                text.classList.add('text');
                text.textContent = navigator.mozL10n.get('log-type-' + currentType);
                currentListItem.appendChild(text);

                var amount = document.createElement('p');
                amount.classList.add('amount');
                var amountNumber = filteredTypes.indexOf(currentType) === -1 ? 0 : dom.logStatisticsOpenModal.dataset[currentType];
                amount.textContent = amountNumber;
                currentListItem.appendChild(amount);

                list.appendChild(currentListItem);
            }
        });
    }

    function _updateLogRangeValue(target, callback) {

        var dateChooser = document.createElement('input');
        dateChooser.type = 'date';
        dateChooser.classList.add('invisible');
        dom.logStatisticsBanner.appendChild(dateChooser);

        dateChooser.focus();

        dateChooser.addEventListener('blur', function () {

            var newValue = dateChooser.value;
            if (newValue) {

                _setDateInFilter(target, newValue);
                callback();
            }
            dateChooser.remove();
        });
    }

    function _clearLogFromTo() {
        dom.logFromDate.textContent = navigator.mozL10n.get('log-from');
        dom.logFromDate.removeAttribute('timestamp');
        dom.logToDate.textContent = navigator.mozL10n.get('log-to');
        dom.logToDate.removeAttribute('timestamp');
    }

    function _setDateInFilter(target, newValue) {
        var hoursMinutes = target === dom.logFromDate ? '00:00' : '23:59';

        var newDate = newValue + ' ' + hoursMinutes;
        var newDateObject = Utils.parseGMTDate(newDate);
        
        if (target === dom.logFromDate && Utils.isInFuture(newDateObject)) {
             newDateObject = Utils.getBeginningOfDay();
        }
        
        var shownDate = Utils.dateToDayString(newDateObject, '/');

        target.textContent = shownDate;
        target.setAttribute('timestamp', newDateObject.getTime());
    }

    function _fromAndToSetInLogDateRange() {

        var from = dom.logFromDate.textContent;
        var to = dom.logToDate.textContent;

        var regex = new RegExp('/.*\\d+.*/');

        var fromIsSet = regex.test(from);
        var toIsSet = regex.test(to);

        return fromIsSet && toIsSet;

    }

    function _orangeRibbonNeeded(container, callback) {
        var allSwitchesWithOrangeRibbonOrCircle = container.querySelectorAll('li > aside > label.orange-switch, li > aside > label.orange-circle, li.group > i.orange-circle');
        var numberOfSwitchesWithOrangeCircle = Object.keys(allSwitchesWithOrangeRibbonOrCircle).length;
        var orangeRibbonOnceClosed = false;
        Controller.getOrangeRibbonClosed(function (data) {
            orangeRibbonOnceClosed = data;
            callback(numberOfSwitchesWithOrangeCircle > 0 && !orangeRibbonOnceClosed);
        });
    }
    /**
     *  Private method for updating the status of an operation in the list
     *  @parameter checkbox DOM input to update
     */
    function _changeOperationStatus(checkbox, container) {
        var opID = checkbox.dataset.opid;
        var status = checkbox.checked ? 'off' : 'on';

        dom.operationsTotalLockInfo.classList.add('hide');

        // Remove orange switch
        var parentNode = checkbox.parentNode;
        var containsOrangeSwitch = parentNode.classList.contains('orange-switch');
        parentNode.classList.remove('orange-switch');

        _orangeRibbonNeeded(container, function (needed) {
            if (!needed) {
                _removeOrangeRibbon(container);
            }
        });

        // Remove schedule switch
        var containsScheduleSwitch = parentNode.classList.contains('schedule-switch');
        parentNode.classList.remove('schedule-switch');

        Controller.updateStatus(
                opID,
                status,
                function callback(err) {
                    if (!ErrorManager.checkError(err)) {
                        // Revert
                        checkbox.checked = !checkbox.checked;

                        // Revert the UI changes
                        _updateGreyCoverOnAllSubOperations(status === 'off');

                        if (containsOrangeSwitch) {
                            parentNode.classList.add('orange-switch');
                        }
                        if (containsScheduleSwitch) {
                            parentNode.classList.add('schedule-switch');
                        }
                        return;
                    }

                });
    }

    /**
     * This function just adds / removes grey cover and enable / disable
     * the switches when needed
     * @param {type} status: true or false
     */
    function _updateGreyCoverOnAllSubOperations(enable) {
        var subOperations = dom.operationsList.querySelectorAll('li');

        for (var i = 0; i < subOperations.length; i++) {
            var currentSubOperation = subOperations[i];
            var subscriptionDisabled = currentSubOperation.subscription && currentSubOperation.subscription === 'disabled';

            var disabled = currentSubOperation.classList.contains('disabledMark');

            if (!disabled) {

                if (enable && !subscriptionDisabled) {
                    currentSubOperation.classList.remove('greyCover');
                    currentSubOperation.querySelector('input').disabled = false;
                }
                else {
                    currentSubOperation.classList.add('greyCover');
                    currentSubOperation.querySelector('input').disabled = true;

                }
            }
        }
    }

    /**
     * Private method for controlling the actions in the different lists
     * @parameter e Event when tapping
     * @parameter container Where the action took part
     */
    function _genericListHandler(e, container) {

        if (subMenuShown) {
            return;
        }

        var li = _getLiParent(e.target);
        if (li !== undefined && li.classList.contains('greyCover')) {
            return;
        }

        // Is the user tapping on the checkbox?
        // This could be fired by a change in the input of the element
        if (e.target.tagName === 'INPUT') {
            _changeOperationStatus(e.target, container);
            return;
        }

        // There is no need to search for ID, because
        // this event is captured twice
        if (e.target.tagName === 'LABEL') {
            return;
        }

        // If the user is not tapping on the checkbox, we need to
        // navigate through the tree.



        // Retrieve the operation ID
        var opID;
        if (e.target.tagName === 'P') {
            opID = e.target.parentNode.dataset.opid;
        } else if (e.target.tagName === 'LI' || e.target.tagName === 'A') {
            opID = e.target.dataset.opid;
        }
        if (!opID) {
            debug('Error while retrieving the operation ID');
            return;
        }

        var isGroup = li.classList.contains('group');
        if (isGroup) {
            _openGroupList(opID);
            return;
        }

        // Go to the operation if needed
        _openOperationsList(opID);
    }

    /**
     *  Private method for controlling the actions in the applications list
     *  @parameter e Event when tapping
     */
    function _applicationsListHandler(e) {
        _genericListHandler(e, dom.mainPanel);
    }

    /**
     *  Private method for controlling the actions in the operations list
     *  @parameter e Event when tapping
     */
    function _operationsListHandler(e) {
        _genericListHandler(e, dom.operationsListContainer);
    }

    /**
     *  Private method for controlling the actions in the group list
     *  @parameter e Event when tapping
     */
    function _groupListHandler(e) {
        _genericListHandler(e, dom.groupOperationsListContainer);
    }

    /**
     *  Private method rendering the details of an operation
     *  @parameter operation Operation event
     *  @parameter opID      Operation ID
     */
    function _renderOpDetails(operation, opID) {

        function _showAllElements() {
            var listOfElements = [
                dom.pdmAutoretrieveContainer,
                dom.enableOtpSwitchContainer,
                dom.enableOtpSwitch.parentNode,
                dom.enableAutocloseByUseContainer,
                dom.enableAutocloseByUseSwitch,
                dom.pdmScheduleContainer,
                dom.enableScheduleContainer,
                dom.enableAutocloseByUseLabel,
                dom.blueRibbon
            ];

            for (var i = 0; i < listOfElements.length; i++) {
                listOfElements[i].classList.remove('hide');
            }
        }
        function _enableAllSwitches() {
            dom.enableAutocloseSwitch.disabled = false;
            dom.enableAutocloseByUseSwitch.disabled = false;
            dom.enableScheduleSwitch.disabled = false;
            dom.enableOtpSwitch.disabled = false;
        }
        function _setDataInElements() {

            // Set from and to
            operation.from = operation.from || Utils.dateToUTCString(Utils.getBeginningOfDay());
            operation.to = operation.to || Utils.dateToUTCString(Utils.getEndOfDay());

            var from = operation.from || Utils.dateToUTCString(Utils.getBeginningOfDay());
            var to = operation.to || Utils.dateToUTCString(Utils.getEndOfDay());

            // Set OTP data
            dom.enableOtpSwitch.dataset.opId = opID;
            dom.enableOtpSwitch.dataset.statusOperation = operation.status;

            // Set autoclose data
            dom.enableAutocloseSwitch.dataset.opId = opID;
            dom.enableAutocloseSwitch.dataset.statusOperation = operation.status;
            dom.enableAutocloseSwitch.dataset.fromOperation = operation.from;
            dom.enableAutocloseSwitch.dataset.toOperation = operation.to;
            dom.enableAutocloseSwitch.dataset.two_factor =
                    operation.two_factor === 'DISABLED' ? 'off' : 'on';
            dom.enableAutocloseSwitch.checked = operation.autoclose > 0;



            // Set values of scheduler
            var fromGMT = Utils.dateToGMTString(Utils.parseUTCDate(from));
            var toGMT = Utils.dateToGMTString(Utils.parseUTCDate(to));

            var fromShown = fromGMT.split(' ')[1] || '';
            var toShown = toGMT.split(' ')[1] || '';

            dom.pdmScheduleStartLabel.dataset.timestamp = from;
            dom.pdmScheduleStartLabel.textContent = fromShown;
            dom.pdmScheduleStartInput.value = fromShown;

            dom.pdmScheduleEndLabel.dataset.timestamp = to;
            dom.pdmScheduleEndLabel.textContent = toShown;
            dom.pdmScheduleEndInput.value = toShown;

            dom.blueRibbonFrom.textContent = fromShown;
            dom.blueRibbonTo.textContent = toShown;

            dom.blueRibbonFrom.textContent = fromShown;
            dom.blueRibbonTo.textContent = toShown;

            dom.pdmScheduleContainer.classList.remove('pdm-on');
        }
        function _showMainLatch() {
            _renderOperationsLatchon(operation, opID);
        }
        function _showExternalUpdates() {
            if (operation.hasOwnProperty('externallyUpdated')) {
                dom.lockAllOperationsSwitch.classList.add('orange-switch');
            }
            else {
                dom.lockAllOperationsSwitch.classList.remove('orange-switch');
            }

        }
        function _showAutocloseByTime() {
            Controller.getPreferences(function (err, preferences) {
                renderAutolockByTimeDetails(preferences.autolock);
            });
        }
        function _showAutocloseByUse() {
            switch (operation.lock_on_request) {
                case 'DISABLED':
                    dom.enableAutocloseByUseContainer.classList.add('hide');
                    break;
                case 'MANDATORY':
                    dom.enableAutocloseByUseSwitch.parentNode.classList.add('hide');
                    dom.pdmScheduleContainer.classList.add('hide');
                    dom.blueRibbon.classList.add('hide');
                    dom.enableAutocloseByUseLabel.classList.add('hide');
                    dom.enableAutocloseByUseContainer.querySelector('li').classList.add('mandatory');
                    break;
                default:
                    dom.enableAutocloseByUseContainer.querySelector('li').classList.remove('mandatory');
                    if (operation.status !== 'interval') {
                        dom.enableAutocloseByUseSwitch.checked = operation.lock_on_request === 'on';
                    }
                    else {
                        dom.enableAutocloseByUseSwitch.checked = false;
                    }
                    break;
            }
        }
        function _showScheduler() {
            dom.enableScheduleSwitch.checked = operation.status === 'interval';
            if (operation.status !== 'interval') {
                dom.pdmScheduleContainer.classList.add('hide');
                dom.blueRibbon.classList.add('hide');
            }
            if (operation.lock_on_request === 'MANDATORY') {
                dom.enableScheduleContainer.classList.add('hide');
            }

            if (operation.satellite && operation.satellite === 'true') {
                dom.blueRibbon.classList.add('satellite');
            }
            else {
                dom.blueRibbon.classList.remove('satellite');
            }
        }
        function _showOTP() {
            if (operation.two_factor === 'DISABLED') {
                dom.pdmAutoretrieveContainer.classList.add('hide');
                dom.enableOtpSwitchContainer.classList.add('hide');
            }
            else if (operation.two_factor === 'MANDATORY') {
                dom.enableOtpSwitch.parentNode.classList.add('hide');
            }
            else {

                dom.enableOtpSwitch.checked = operation.two_factor === 'on';
                if (!dom.enableOtpSwitch.checked) {
                    dom.pdmAutoretrieveContainer.classList.add('hide');
                }
            }
        }

        _showAllElements();
        _enableAllSwitches();

        _setDataInElements();

        _showMainLatch();
        _showExternalUpdates();
        _showAutocloseByTime();
        _showAutocloseByUse();
        _showScheduler();
        _showOTP();
    }

    function renderAutolockByTimeDetails(time) {
        dom.autolockLabel.textContent = navigator.mozL10n.get('autolock' + time + 'minutes');
        dom.autolockLabel.dataset.minutes = time;
    }

    function _getStatusFromInterval(from, to) {

        /*If from or to are not received, the latch is always blocked*/
        if (from === undefined || to === undefined) {
            return 'off';
        }

        var fromDate = Utils.parseUTCDate(from);
        var toDate = Utils.parseUTCDate(to);

        var sameDay = fromDate.toLocaleDateString() === toDate.toLocaleDateString();
        var bounded = isHourlyBounded(fromDate, toDate);

        return sameDay !== bounded ? 'on' : 'off';
    }

    function isHourlyBounded(fromDate, toDate) {
        var currentDate = new Date();

        var todayFromDate = new Date();
        todayFromDate.setHours(fromDate.getHours());
        todayFromDate.setMinutes(fromDate.getMinutes());
        var todayFromMilliseconds = todayFromDate.getTime();

        var todayToDate = new Date();
        todayToDate.setHours(toDate.getHours());
        todayToDate.setMinutes(toDate.getMinutes());
        var todayToMilliseconds = todayToDate.getTime();

        var minDate = todayFromMilliseconds < todayToMilliseconds ? todayFromDate : todayToDate;
        var maxDate = minDate === todayFromDate ? todayToDate : todayFromDate;

        return currentDate.getTime() > minDate && currentDate.getTime() < maxDate;
    }

    function _getSchedulerDate() {
        var from = dom.pdmScheduleStartInput.value;
        var to = dom.pdmScheduleEndInput.value;

        var fromTMP = from.split(':');
        var toTMP = to.split(':');

        var fromHours = +fromTMP[0];
        var fromMinutes = +fromTMP[1];

        var toHours = +toTMP[0];
        var toMinutes = +toTMP[1];

        var fromDate = new Date();
        fromDate.setHours(fromHours);
        fromDate.setMinutes(fromMinutes);

        var toDate = new Date();
        toDate.setHours(toHours);
        toDate.setMinutes(toMinutes);
        // If time 'to < from', we need to update the day
        if (toHours < fromHours ||
                (toHours === fromHours && toMinutes < fromMinutes)) {
            toDate.setDate(toDate.getDate() + 1);
        }

        var fromCompleteUTC = Utils.dateToUTCString(fromDate);
        var toCompleteUTC = Utils.dateToUTCString(toDate);

        var fromCompleteGMT = Utils.dateToGMTString(fromDate);
        var toCompleteGMT = Utils.dateToGMTString(toDate);

        dom.pdmScheduleStartLabel.dataset.timestamp = fromCompleteUTC;
        dom.pdmScheduleEndLabel.dataset.timestamp = toCompleteUTC;

        var fromShown = fromCompleteGMT.split(' ')[1] || '';
        var toShown = toCompleteGMT.split(' ')[1] || '';

        dom.pdmScheduleStartLabel.textContent = fromShown;
        dom.pdmScheduleEndLabel.textContent = toShown;

        dom.blueRibbonFrom.textContent = fromShown;
        dom.blueRibbonTo.textContent = toShown;

        Controller.updateSchedulingRange(
                dom.lockAllOperationsSwitch.dataset.opId,
                fromCompleteUTC,
                toCompleteUTC,
                function callback(err) {
                    if (!ErrorManager.checkError(err)) {
                        // Revert
                        dom.pdmScheduleStartInput.value = from;
                        dom.pdmScheduleEndInput.value = to;
                        return;
                    }
                });

        var newStatus = _getStatusFromInterval(fromCompleteUTC, toCompleteUTC);
        dom.lockAllOperationsSwitch.dataset.checked = newStatus === 'off';
        var latchon = dom.lockAllOperationsSwitch;
        var checked = newStatus === 'off';
        latchon.dataset.checked = checked;

        var parameters = _getMoveLatchonParameters(latchon, newStatus, true);

        _softlyMoveLatchon(parameters, function () {
            _performLatchonAnimation(latchon.parentNode, parameters.opacity);
        });
    }

    function updateOperationsLatchonTexts(longText) {

        var latchon = dom.lockAllOperations;

        var textOn1 = latchon.querySelector('.latchonTextOn p:first-of-type');
        var textOn2 = latchon.querySelector('.latchonTextOn p:last-of-type');
        var textOff1 = latchon.querySelector('.latchonTextOff p:first-of-type');
        var textOff2 = latchon.querySelector('.latchonTextOff p:last-of-type');

        var localizationBase = longText ? 'latchon' : 'latchon-single';
        var _ = navigator.mozL10n.get;

        textOn1.textContent = _(localizationBase + '-off-1');
        textOn2.textContent = _(localizationBase + '-off-2');
        textOff1.textContent = _(localizationBase + '-on-1');
        textOff2.textContent = _(localizationBase + '-on-2');

    }

    function _renderOperationsLatchon(operation, opID) {

        var hasSubOperations = operation.operations && Object.keys(operation.operations).length > 0;
        updateOperationsLatchonTexts(hasSubOperations);

        var currentClassName = document.body.classList[0];
        var isRefresh = dom.lockAllOperationsSwitch.dataset.opId === opID && currentClassName === 'application';

        var latchon = dom.lockAllOperationsSwitch;
        var status = operation.status;
        if (status === 'interval') {
            status = _getStatusFromInterval(operation.from, operation.to);
        }
        var checked = status === 'off';
        latchon.dataset.checked = checked;

        if (operation.satellite === true || operation.satellite === 'true') {
            dom.lockAllOperations.classList.add('satellite');
        }
        else {
            dom.lockAllOperations.classList.remove('satellite');
        }

        var parameters = _getMoveLatchonParameters(latchon, status, true);

        if (isRefresh) {
            _softlyMoveLatchon(parameters, function () {
                _performLatchonAnimation(latchon.parentNode, parameters.opacity);
            });
        } else {
            latchon.style.marginLeft = parameters.currentLimit + 'px';
            _setLatchonOpacity(latchon.parentNode, parameters.opacity);
            _updateLatchonTextOpacity(latchon, parameters.currentLimit);
        }
    }

    /**
     *  Private method for rendering the operations list
     *  @parameter operations Operations to render
     *  @parameter container  Container where append the operations
     */
    function _renderOperations(operations, container) {
        debug('_renderOperations ');
        // Clean container
        container.innerHTML = '';

        var orderedOperations = _reorder(operations);

        // Do we need to show a 'list is empty screen'
        if (Object.keys(operations).length === 0) {
            // TODO Render screen of 'no operations available'
            // TODO Check with UX
            debug('There are no operations');
            return;
        }

        orderedOperations.forEach(function (currentAppObject) {
            var operation = currentAppObject.app;
            var opId = currentAppObject.opID;
            container.appendChild(_createOperationDOM(operation, opId));

        });

        var container = dom.operationsList;
        var orangeRibbonAlreadyShown = _isOrangeRibbonShown(container);

        _orangeRibbonNeeded(container, function (needed) {
            if (needed && !orangeRibbonAlreadyShown) {
                var ribbon = createOrangeRibbon();
                container.insertBefore(ribbon, container.firstChild);
            }
        });
    }

    /**
     *  Private method for show all options in main-panel. Are
     *  hidden by default to avoid UI weird effects
     */
    function _showMainPanelSections() {
        var childrens = dom.mainPanel.children;
        for (var i = 0; i < childrens.length; i++) {
            childrens[i].classList.remove('hide');
        }
    }

    /**
     *  Private method to load the preferences from controller
     */
    function _getPreferences(callback) {
        Controller.getPreferences(function (err, preferences) {

            callback(err, preferences);
        });
    }

    /**
     *  Private method for rendering the main operations list
     */
    function _renderRootOperations(doNotLoad) {

        subMenuShown = false;

        // Get root operations, the main list of them
        Controller.getRootOperations(
                function onRetrieved(rootOperations) {

                    var numberOfOperations = Object.keys(rootOperations).length;

                    if (numberOfOperations > 1 || (numberOfOperations === 1 && Object.keys(rootOperations)[0] !== 'Ash0Latch1Durbatuluk')) {
                        dom.mainPanel.classList.remove('empty');
                    }
                    else {
                        dom.mainPanel.classList.add('empty');
                    }
                    // Render the list
                    UIManager.renderApplicationsList(rootOperations);
                    // Go to main
                    if (!doNotLoad) {
                        UIManager.load('main');
                    }
                    // Hide the overlay of 'loading'
                    LoadingOverlay.hide();
                    // Clear form
                    UIManager.clearSigninForm();
                    // Avoid refresh
                    _showMainPanelSections();
                    // Show message if needed that we are offline
                    Controller.checkOnline();
                },
                function onEmtpy() {
                    // Go to main
                    if (!doNotLoad) {
                        UIManager.load('main');
                    }
                    // Add emtpy style
                    dom.mainPanel.classList.add('empty');
                    // Avoid refresh
                    _showMainPanelSections();
                });
    }

    /**
     *  Private method for initialize the pairing tutorial
     *  @parameter step Step number to set
     */
    function _setPairingTutorialStep(step) {
        dom.pairingTutorialPanel.dataset.currentStep = step;
        dom.pairingTutorialPanel.querySelector('.tutorial-step-current')
                .classList.remove('tutorial-step-current');

        dom.pairingTutorialPanel.querySelector('section[data-step="' + step + '"]')
                .classList.add('tutorial-step-current');
    }

    /**
     *  Private method for initialize the startup tutorial
     *  @parameter step Step number to set
     */
    function _setStartupTutorialStep(step) {
        dom.startupTutorialPanel.dataset.currentStep = step;
        dom.startupTutorialPanel.querySelector('.tutorial-step-current')
                .classList.remove('tutorial-step-current');

        dom.startupTutorialPanel.querySelector('section[data-step="' + step + '"]')
                .classList.add('tutorial-step-current');
    }

    /**
     *  Private method for handling the navigation of the pairing Tuto
     *  @parameter e Event from UI
     */
    function _handleNavigationPairingTutorial(e) {
        var step = +dom.pairingTutorialPanel.dataset.currentStep;
        if (e.target.tagName === 'BUTTON') {
            switch (e.target.dataset.action) {
                case 'right':
                    step += 1;
                    break;
                case 'left':
                    step -= 1;
                    break;
            }
            // Udpate properly
            _setPairingTutorialStep(step);
        }
    }
    /**
     *  Private method for handling the navigation of the startup Tuto
     *  @parameter e Event from UI
     */
    function _handleNavigationStartupTutorial(e) {
        var step = +dom.startupTutorialPanel.dataset.currentStep;
        if (e.target.tagName === 'BUTTON') {
            switch (e.target.dataset.action) {
                case 'right':
                    step += 1;
                    break;
                case 'left':
                    step -= 1;
                    break;
            }
            // Udpate properly
            _setStartupTutorialStep(step);
        }
    }

    /**
     *  Private method for initialize the pairing tutorial
     */
    function _initPairingTutorial() {
        dom.pairingTutorialNavigation.addEventListener('click', function (e) {
            _handleNavigationPairingTutorial(e);
        });

        dom.backToPairing.addEventListener('click', function () {
            UIManager.load('pairing');
            setTimeout(_setPairingTutorialStep, 1000, 1);
        });
    }

    /**
     *  Private method for initialize the startup tutorial
     */
    function _initStartupTutorial() {
        dom.startupTutorialNavigation.addEventListener('click', function (e) {
            _handleNavigationStartupTutorial(e);
        });

        dom.startupTutorialStep1Login.addEventListener('click', function (e) {
            UIManager.load('signin');
        });
        dom.startupTutorialLogin.addEventListener('click', function (e) {
            UIManager.load('signin');
            setTimeout(_setStartupTutorialStep, 1000, 1); // Delay 1 second
        });

        var versionText = navigator.mozL10n.get('startup-version') + ' ' + Config.environment.clientVersion;
        if (Config.environment.versionExtra !== undefined) {
            versionText += ' ' + Config.environment.versionExtra;
        }

        dom.startupVersion.textContent = versionText;
        dom.loginVersion.textContent = versionText;

        dom.startupStep6Contact.href = "mailto:" + Config.environment.contactEmail;

        dom.startupTutorialRegister.addEventListener('click', function (e) {
            loadPageOnBrowser(Config.environment.registerURL + "?hideCloseButton=true");
        });

    }

    /**
     *  Private method for handling the navigation
     *  @parameter e Event from UI
     */
    function _handleNavigationBasicTutorial(e) {
        var step = +dom.basicTutorialPanel.dataset.currentStep;
        if (e.target.tagName === 'BUTTON') {
            switch (e.target.dataset.action) {
                case 'right':
                    step += 1;
                    break;
                case 'left':
                    step -= 1;
                    break;
            }
            // Udpate properly
            _setTutorialStep(step);
        }
    }

    /**
     *  Private method for initialize the basic tutorial
     */
    function _initBasicTutorial() {
        dom.tutorialNavigation.addEventListener('mousedown', function (e) {
            _handleNavigationBasicTutorial(e);
        });
    }

    /**
     *  Private method for initialize the basic tutorial
     *  @parameter step Step number to set
     */
    function _setTutorialStep(step) {
        dom.basicTutorialPanel.dataset.currentStep = step;
        dom.basicTutorialPanel.querySelector('.tutorial-step-current')
                .classList.remove('tutorial-step-current');

        dom.basicTutorialPanel.querySelector('section[data-step="' + step + '"]')
                .classList.add('tutorial-step-current');
    }

    function loadPageOnBrowser(url) {
        if (!Controller.checkOnline()) {
            return;
        }
        window.open(url, "_blank");
    }

    /**
     * Setup the dom actions for the settings drawer
     */
    function _initSettingsPanel(bindTo) {
        dom.openSettings.addEventListener('click', function () {

            Controller.getUserEmail(function (data) {
                dom.settingsSignedAs.innerHTML = navigator.mozL10n.get('signed-as') + (' ' + data);
            });


            this.load('settings');
        }.bind(bindTo));

        dom.openAppSettings.addEventListener('click', function () {
            this.load('settings');
        }.bind(bindTo));

        dom.closeSettings.addEventListener('click', function () {
            Controller.getPreferences(function (err, preferences) {
                renderAutolockByTimeDetails(preferences.autolock);
            });
            if (document.body.classList.contains('main')) {
                this.load('main');
            } else {
                this.load('application');
            }
        }.bind(bindTo));

        dom.settingsTutorialButton.addEventListener('click', function () {
            this.load('basic-tutorial');
        }.bind(bindTo));

        dom.signoutButton.addEventListener('click', function () {
            // Clear user email from menu
            dom.settingsSignedAs.innerHTML = navigator.mozL10n.get('signed-as');
            Controller.logout();
            this.load('signin');
        }.bind(bindTo));

        dom.securityButton.addEventListener('click', function () {
            if (Controller.checkOnline()) {
                SecurityUI.listSessions(function () {
                    UIManager.load('security');
                });
            }
        }.bind(bindTo));

        dom.settingsSupportButton.addEventListener('click', function () {
            WebviewOverlay.show(navigator.mozL10n.get('support'), '/support.html');
        });

        dom.settingsPrivacyButton.addEventListener('click', function () {
            WebviewOverlay.show(navigator.mozL10n.get('privacy'), '/privacy.html');
        });

        dom.settingsAboutButton.addEventListener('click', function () {
            WebviewOverlay.show(navigator.mozL10n.get('aboutWindowTitle'),
                    '/about.html');
        });
        dom.settingsSettingsButton.addEventListener('click', function () {
            if (Controller.checkOnline()) {
                WebviewOverlay.hide(navigator.mozL10n.get('settings'), '/settings.html');
                WebviewOverlay.show(navigator.mozL10n.get('settings'), '/settings.html');
            }
        });
    }

    function _hideSubMenu(container) {
        if (subMenuShown) {
            if (firstClickPerformed) {

                var listItems = container.querySelectorAll('li.hide');
                var numberOfListItems = listItems.length;
                for (var i = 0; i < numberOfListItems; i++) {
                    var currentListItem = listItems[i];
                    currentListItem.classList.remove('hide');
                }
                dom.applicationListSubmenu.classList.add('hide');
                firstClickPerformed = false;
                subMenuShown = false;
            }
            else {
                firstClickPerformed = true;
            }
        }
    }

    /**
     * Private methot to remove all events in a dom object
     */
    function _removeAllEvents(currentTargetName) {
        var currentTarget = dom[currentTargetName];
        var parentNode = currentTarget.parentNode;

        var deepClone = true;
        var clone = currentTarget.cloneNode(deepClone);

        parentNode.replaceChild(clone, currentTarget);
        dom[currentTargetName] = clone;
    }

    function _disableEventsInSubmenu() {

        debug('_disableEventsInSubmenu');

        // Add dom object names to this list in order to remove all its events
        var subMenuEventTargetNames = [
            'submenuRename',
            'submenuDelete',
            'submenuMove',
            'submenuSilent',
            'submenuLog'
        ];

        Object.keys(subMenuEventTargetNames).forEach(function (currentTargetIndex) {
            var currentTargetName = subMenuEventTargetNames[currentTargetIndex];
            _removeAllEvents(currentTargetName);
        });
    }

    function _toggleSilentUserInterface() {
        var submenuSilent = dom.submenuSilent;

        submenuSilent.classList.toggle('silent-on');
        submenuSilent.classList.toggle('silent-off');

        var skipPush = submenuSilent.classList.contains('silent-off');

        var _ = navigator.mozL10n.get;

        var iconText = dom.applicationListSubmenu.querySelector('#submenu-silent span');
        iconText.textContent = skipPush ? _('submenu-silent-off') : _('submenu-silent-on');

        return skipPush;

    }

    function _enableEventsInSubmenu() {
        debug('_enableEventsInSubmenu');

        dom.submenuRename.addEventListener('click', function (e) {

            var operationName = _getLiParent(e.target).nextSibling.querySelector('p:first-of-type').textContent.trim();

            dom.renameName.value = operationName;

            var header = dom.renameOpenModal.querySelector('h2');
            header.textContent = navigator.mozL10n.get('submenu-rename');

            dom.renameOpenModal.dataset.origin = 'submenu';
            window.location = '#rename-openModal';

            e.stopPropagation();
        });

        dom.submenuMove.addEventListener('click', function (e) {
            e.stopPropagation();
            _displayGroupModal(e.target);
        });

        dom.submenuDelete.addEventListener('click', function (e) {
            e.stopPropagation();
            _displayDeleteGroupModal(e.target);
        });

        dom.submenuSilent.addEventListener('click', function (e) {

            var li = _getLiParent(e.target).nextSibling;
            var info = _getAppInfoFromListItem(li);

            var skipPush = _toggleSilentUserInterface();

            if (skipPush) {
                li.classList.add('silent');
            }
            else {
                li.classList.remove('silent');
            }

            var opId = info.opId;

            Controller.skipPush(opId, skipPush, function (err) {
                if (err) {
                    _toggleSilentUserInterface();
                }
            });

            _hideSubMenu(li.parentNode);
        });
        // Log function
        dom.submenuLog.addEventListener('click', function (e) {
            e.stopPropagation();
            var container = e.target.parentNode.parentNode.parentNode;

            var opId = dom.applicationListSubmenu.dataset.opid;
            var operationName = e.target.parentNode.parentNode.nextSibling.querySelector('a > p').textContent;

            _renderLog(opId, operationName);

            UIManager.load('log');

            setTimeout(function () {
                _hideSubMenu(container);
            }, 1000);
        });


    }

    function _getLatchonLimits(latchon) {
        var canal = latchon.parentNode.querySelector('.canalOff');

        // Get parent width
        var canalStyle = canal.currentStyle || window.getComputedStyle(canal);
        var canalWidthString = canalStyle.width;
        var canalWidth = parseInt(canalWidthString.replace('px', ''));

        // Get limits
        var minimumLeftMargin = 0;
        var maximumLeftMargin = canalWidth - latchon.offsetWidth - 3; // Visual fix
        return {minimumLeftMargin: minimumLeftMargin, maximumLeftMargin: maximumLeftMargin};
    }

    function _isOrangeRibbonShown(container) {
        return container.querySelector('.orangeRibbon') !== null;
    }

    /**
     *  Private method for initialize the sign in
     */
    function _initSigninPanel() {
        dom.authenticate.addEventListener('click', function () {
            var credentials = UIManager.getCredentials();

            // Check form

            if (!credentials || credentials.user === '') {
                UIManager.showEmptyUsernameError(null);
                return;
            }
            if (!credentials || credentials.password === '') {
                UIManager.showEmptyPasswordError(null);
                return;
            }

            if (credentials && !Utils.validateEmail(credentials.user)) {
                UIManager.showNotAnEmailError(null);
                return;
            }

            if (!Controller.checkOnline()) {
                return;
            }

            // Show loading screen
            LoadingOverlay.show(navigator.mozL10n.get('signingIn'));
            // Call to controller for getting the info
            Controller.authenticate(credentials, function onAuthenticate(err) {
                // Hide loading screen
                LoadingOverlay.hide();

                if (!ErrorManager.checkError(err)) {
                    return;
                }

                // Get root operations, the main list of them
                _renderRootOperations();

            });
        });

        dom.backToStartup.addEventListener('click', function () {
            UIManager.load('startup-tutorial');
        });

        dom.btBackButton.addEventListener('click', function () {
            UIManager.load('main');
        });

        dom.signinUser.addEventListener('focus', function () {
            dom.signinPanel.classList.add('typing');
        });

        dom.signinUser.addEventListener('blur', function () {
            dom.signinPanel.classList.remove('typing');
        });

        dom.signinPassword.addEventListener('focus', function () {
            dom.signinPanel.classList.add('typing');
        });

        dom.signinPassword.addEventListener('blur', function () {
            dom.signinPanel.classList.remove('typing');
        });

        dom.signinForgotPassword.addEventListener('click', function () {
            loadPageOnBrowser(Config.environment.resetURL + "?hideCloseButton=true");
        });

        dom.signinRegister.addEventListener('click', function () {
            loadPageOnBrowser(Config.environment.registerURL + "?hideCloseButton=true");
        });
    }

    function _softlyMoveLatchon(parameters, cb) {

        var finalLeftMargin = parameters.currentLimit;
        var speedMultiplier = parameters.speedMultiplier;
        var latchon = parameters.latchon;

        var initialMargin = parseInt(latchon.style.marginLeft.replace('px', ''));
        if (isNaN(initialMargin)) {
            initialMargin = 0;
        }

        var refreshTime = 20;
        var step = initialMargin > finalLeftMargin ? -3 : 3;
        step *= speedMultiplier;

        var difference = Math.abs(initialMargin - finalLeftMargin);
        if (difference >= Math.abs(step)) {

            setTimeout(function () {
                var finalX = initialMargin + step;
                latchon.style.marginLeft = parseInt(finalX) + 'px';
                _updateLatchonTextOpacity(latchon, finalX);
                _softlyMoveLatchon(parameters, cb);
            }, refreshTime);
        }
        else {
            latchon.style.marginLeft = finalLeftMargin + 'px';
            _updateLatchonTextOpacity(latchon, finalLeftMargin);
            latchon.classList.remove('orange-switch');

            if (typeof cb === 'function') {
                cb();
            }
        }
    }

    function _setLatchonOpacity(latchonContainer, value) {

        var latchonSwitch = latchonContainer.querySelector('.latchonSwitchOn');
        var canal = latchonContainer.parentNode.querySelector('.canalOn');
        var background = latchonContainer.parentNode.querySelector('.latchonOn');

        latchonSwitch.style.opacity = value;
        canal.style.opacity = value;
        background.style.opacity = value;
    }
    function _performLatchonAnimation(latchonContainer, targetOpacity) {

        var latchonSwitch = latchonContainer.querySelector('.latchonSwitchOn');
        var refreshTime = 50;

        var defaultOpacity = latchonSwitch.parentNode.style.marginLeft < 10 ? 1 : 0;
        var currentOpacity = latchonSwitch.style.opacity === '' ? defaultOpacity : parseFloat(latchonSwitch.style.opacity);
        var step = targetOpacity > currentOpacity ? 0.1 : -0.1;

        if (currentOpacity !== targetOpacity) {

            _setLatchonOpacity(latchonContainer, currentOpacity + step);

            setTimeout(function () {
                _performLatchonAnimation(latchonContainer, targetOpacity);
            }, refreshTime);
        }
    }

    function _updateLatchonTextOpacity(latchon, finalX) {

        // Latchon
        var latchonWidth = latchon.offsetWidth;

        var textOn = latchon.parentNode.querySelector('.latchonTextOn');
        var arrowOn = latchon.parentNode.querySelector('.latchonArrowOn');
        var textOff = latchon.parentNode.querySelector('.latchonTextOff');
        var arrowOff = latchon.parentNode.querySelector('.latchonArrowOff');

        // Container
        var canal = latchon.parentNode.querySelector('.canalOff');

        var canalStyle = canal.currentStyle || window.getComputedStyle(canal);
        var canalLeftString = canalStyle.left;
        var canalWidthString = canalStyle.width;

        var canalLeft = parseInt(canalLeftString.replace('px', ''));
        var canalWidth = parseInt(canalWidthString.replace('px', ''));


        var x = finalX + latchonWidth / 2 + canalLeft;

        // Limits 
        var leftLimit = canalLeft + latchonWidth / 2;
        var rightLimit = leftLimit + canalWidth - latchonWidth;

        // Percentage
        var threshold = 0.3;
        var percentage = (x - leftLimit) / (rightLimit - leftLimit);

        var textOnOpacity = percentage < (1 - threshold) ? 0 : 1 + (percentage - 1) / threshold;
        var textOffOpacity = percentage > threshold ? 0 : 1 - percentage / threshold;

        textOn.style.opacity = textOnOpacity;
        arrowOn.style.opacity = textOnOpacity;
        textOff.style.opacity = textOffOpacity;
        arrowOff.style.opacity = textOffOpacity;
    }

    function _onLatchonMove(latchon, e) {
        var latchonWidth = latchon.offsetWidth;

        // Container
        var canal = latchon.parentNode.querySelector('.canalOff');

        var canalStyle = canal.currentStyle || window.getComputedStyle(canal);
        var canalLeftString = canalStyle.left;
        var canalWidthString = canalStyle.width;

        var canalLeft = parseInt(canalLeftString.replace('px', ''));
        var canalWidth = parseInt(canalWidthString.replace('px', ''));


        // Limits
        var leftLimit = canalLeft + latchonWidth / 2;
        var rightLimit = leftLimit + canalWidth - latchonWidth;

        var touch = e.touches[0];
        var x = touch.pageX;

        x = x >= leftLimit ? x : leftLimit;
        x = x <= rightLimit ? x : rightLimit;

        var finalX = x - latchonWidth / 2 - canalLeft;

        latchon.style.marginLeft = finalX + 'px';

        _updateLatchonTextOpacity(latchon, finalX);
    }

    function _onLatchonMoveEnd(latchon) {
        var limits = _getLatchonLimits(latchon);
        var minimumLeftMargin = limits.minimumLeftMargin;
        var maximumLeftMargin = limits.maximumLeftMargin;

        // Get current status
        var currentLeftMargin = parseInt(latchon.style.marginLeft.replace('px', ''));

        var distanceToLeftMargin = currentLeftMargin - minimumLeftMargin;
        var distanceToRightMargin = maximumLeftMargin - currentLeftMargin;

        var status = distanceToLeftMargin <= distanceToRightMargin ? 'on' : 'off';
        var checked = status === 'off';
        latchon.dataset.checked = checked;

        var parameters = _getMoveLatchonParameters(latchon, status, false);

        _softlyMoveLatchon(parameters, function () {
            _performLatchonAnimation(latchon.parentNode, parameters.opacity);

            var renderApplications = latchon === dom.lockAllApplicationsSwitch;
            var container = renderApplications ? dom.applicationsList : dom.operationsList;
            if (!renderApplications) {
                dom.enableScheduleSwitch.checked = false;
                dom.pdmScheduleContainer.classList.add('hide');
                dom.blueRibbon.classList.add('hide');

                if (checked) {
                    _showTotalLock();
                }
                else {
                    dom.operationsTotalLockInfo.classList.add('hide');
                }
            }

            _updateLockAllApplications(latchon, container);
        });
    }

    function _showTotalLock() {
        dom.operationsTotalLockInfo.classList.remove('hide');
        setTimeout(function () {
            dom.operationsTotalLockInfo.classList.add('hide');
        }, 10000);
    }

    function _hideSettingsMenu() {
        if (document.body.classList.contains('settings')) {
            document.body.classList.remove('settings');
        }
    }

    function createOrangeRibbon() {
        var ribbon = document.createElement('div');
        ribbon.className = 'orangeRibbon';

        var ribbonImage = document.createElement('div');
        ribbonImage.className = 'ribbonImage';

        var ribbonText = document.createElement('span');
        ribbonText.innerHTML = navigator.mozL10n.get('ribbon-text');

        var ribbonClose = document.createElement('i');

        ribbon.appendChild(ribbonImage);
        ribbon.appendChild(ribbonText);
        ribbon.appendChild(ribbonClose);

        ribbonClose.addEventListener('click', function () {
            var container = ribbon.parentNode;
            _removeOrangeRibbon(container);
            Controller.setOrangeRibbonClosed(true);
        });

        return ribbon;
    }

    var isInitialized = false;
    var UIManager = {
        init: function (authenticated) {
            if (isInitialized) {
                return;
            }
            // Cache all DOM Elements in our 'dom' object
            elementIDs.forEach(function (name) {
                dom[Utils.camelCase(name)] = document.getElementById(name);
            }, this);

            // Basic tutorial
            _initBasicTutorial();

            // Settings drawer
            _initSettingsPanel(this);

            // Sign in panel
            _initSigninPanel();

            // Main panel
            dom.applicationListEmpty.addEventListener('click', function () {
                this.load('pairing-tutorial');
            }.bind(this));

            dom.submenuMoveName.setAttribute('placeholder', navigator.mozL10n.get('group-move-to-new-group'));

            dom.applicationsList.addEventListener('click',
                    _applicationsListHandler.bind(this));

            dom.applicationListContainer.addEventListener('click', function () {
                if (!groupModalShown) {
                    _hideSubMenu(dom.applicationListContainer);
                }
            }.bind(this));

            dom.operationsListContainer.addEventListener('click', function () {
                _hideSubMenu(dom.operationsListContainer);
            }.bind(this));

            dom.groupOperationsListContainer.addEventListener('click', function () {
                _hideSubMenu(dom.groupOperationsListContainer);
            }.bind(this));

            dom.applicationListSubmenu.addEventListener('click', function (evt) {
                evt.stopPropagation();
            });

            dom.refreshList.addEventListener('click', function () {
                _renderRootOperations();
            }.bind(this));

            dom.addApplication.addEventListener('click', function () {
                this.load('pairing');
            }.bind(this));

            dom.addApplicationFromGroup.addEventListener('click', function () {
                this.load('pairing');
            }.bind(this));

            dom.lockAllApplicationsSwitch.dataset.opId = Config.environment.latchonID;
            dom.lockAllApplicationsSwitch.addEventListener('touchmove', function (e) {
                var latchon = dom.lockAllApplicationsSwitch;
                _onLatchonMove(latchon, e);
            });

            dom.lockAllOperationsSwitch.addEventListener('touchmove', function (e) {
                var latchon = dom.lockAllOperationsSwitch;
                _onLatchonMove(latchon, e);
            });

            dom.lockAllApplicationsSwitch.addEventListener('touchend', function () {
                var latchon = dom.lockAllApplicationsSwitch;
                _onLatchonMoveEnd(latchon);
            });

            dom.lockAllOperationsSwitch.addEventListener('touchend', function () {
                var latchon = dom.lockAllOperationsSwitch;
                _onLatchonMoveEnd(latchon);
            });

            dom.submenuMoveCreate.addEventListener('click', function () {
                _createNewGroup();
            }.bind(this));

            dom.submenuMoveMove.addEventListener('click', function () {
                _addAppToGroup();
                _hideGroupModal();
            }.bind(this));

            dom.submenuDeleteConfirmed.addEventListener('click', function (e) {
                e.stopPropagation();

                var li = dom.applicationListSubmenu.nextSibling;
                var groupId = _getAppInfoFromListItem(li).opId;
                _deleteGroup(groupId);
            });

            dom.renameRename.addEventListener('click', function () {

                var origin = dom.renameOpenModal.dataset.origin;

                switch (origin) {
                    case 'submenu' :
                        _changeOperationNameFromSubMenu();
                        break;
                    case 'header':
                        var target = dom.applicationsSubHeader.classList.contains('hide') ? dom.applicationsHeader : dom.applicationsSubHeader;
                        _changeOperationNameFromHeader(target);
                        break;
                }
            });

            dom.renameCancel.addEventListener('click', function (e) {
                var container = _getLiParent(e.target).parentNode;
                _hideSubMenu(container);
            });

            dom.submenuMoveName.addEventListener('keypress', function () {

                dom.submenuMoveCreate.classList.remove('hide');
                dom.submenuMoveMove.classList.add('hide');

                var ul = dom.submenuMoveOpenModal.querySelector('ul');
                _clearAllCheckedElementsInModal(ul);
            });

            dom.submenuMoveCancel.addEventListener('click', _hideGroupModal);


            dom.logToday.addEventListener('click', function () {

                dom.logEntriesList.setAttribute('scope', 'today');
                dom.logDateRange.classList.remove('selected');
                dom.logToday.classList.add('selected');
                _clearLogFromTo();
                _reloadLogToday();
            });

            dom.logDateRange.addEventListener('click', function (evt) {
                _reloadLogRange();
            });

            // Application
            dom.backToMain.addEventListener('click', function () {
                Controller.loadParentOperation(
                        function onLoadOperation(err, parentID) {
                            if (err) {
                                // no handling, this error just means no parent
                                _renderRootOperations();
                                this.load('main');
                                return;
                            }
                            debug('Render the operations of ' + parentID);
                            _openOperationsList(parentID);
                        }.bind(this),
                        function onLoadGroup(groupId) {
                            _openGroupList(groupId);
                        });
            }.bind(this));

            function _clickOnHeaderOrSubheader() {
                var target = dom.applicationsSubHeader.classList.contains('hide') ? dom.applicationsHeader : dom.applicationsSubHeader;

                var operationName = target.textContent;

                dom.renameName.value = operationName;

                var header = dom.renameOpenModal.querySelector('h2');
                header.textContent = navigator.mozL10n.get('submenu-rename');

                window.location = '#rename-openModal';
                dom.renameOpenModal.dataset.origin = 'header';
            }

            dom.applicationsHeader.addEventListener('click', _clickOnHeaderOrSubheader);
            dom.applicationsSubHeader.addEventListener('click', _clickOnHeaderOrSubheader);


            // Detail

            dom.pdmAutoretrieveHeader.addEventListener('click', function () {
                Controller.loadOTP(dom.lockAllOperationsSwitch.dataset.opId);
            }.bind(this));

            dom.pdmScheduleStartInput.addEventListener('input', _getSchedulerDate);
            dom.pdmScheduleEndInput.addEventListener('input', _getSchedulerDate);

            dom.enableOtpSwitch.addEventListener('click', function (e) {

                // Show or hide AutoRetrievePassword button
                if (e.target.checked) {
                    dom.pdmAutoretrieveContainer.classList.remove('hide');
                }
                else {
                    dom.pdmAutoretrieveContainer.classList.add('hide');
                }

                // Call to Controller for udpating the two_factor
                Controller.updateTwoFactor(
                        dom.enableOtpSwitch.dataset.opId,
                        e.target.checked ? 'on' : 'off',
                        function callback(err) {
                            if (!ErrorManager.checkError(err)) {
                                // Revert
                                dom.enableOtpSwitch.checked = !dom.enableOtpSwitch.checked;
                                return;
                            }
                        });
            });

            var scheduleSwitchListener = function (e) {

                // Backup switch status
                var autocloseChecked = dom.enableAutocloseSwitch.checked;
                var autocloseByUseChecked = dom.enableAutocloseByUseSwitch.checked;
                var previousMinutesInAutolock = dom.lockAllOperationsSwitch.dataset.autoclose;

                // Update UI switches
                dom.enableAutocloseSwitch.checked = false;
                dom.enableAutocloseByUseSwitch.checked = false;

                // Update autoclose UI elements
                var newAutocloseValue = 0;
                dom.lockAllOperationsSwitch.dataset.autoclose = newAutocloseValue;

                // Show / hide hour selector
                if (dom.enableScheduleSwitch.checked) {
                    dom.pdmScheduleContainer.classList.remove('hide');
                    dom.blueRibbon.classList.remove('hide');
                }
                else {
                    dom.pdmScheduleContainer.classList.add('hide');
                    dom.blueRibbon.classList.add('hide');
                }

                // Update status in server

                var id = dom.enableAutocloseSwitch.dataset.opId;

                var nonIntervalOpStatus = dom.lockAllOperationsSwitch.dataset.checked === 'true' ? 'off' : 'on';
                var newStatus = dom.enableScheduleSwitch.checked ? 'interval' : nonIntervalOpStatus;
                var checked;
                var parameters;
                var latchon = dom.lockAllOperationsSwitch;

                if (newStatus === 'interval') {
                    var from = dom.pdmScheduleStartLabel.dataset.timestamp;
                    var to = dom.pdmScheduleEndLabel.dataset.timestamp;
                    var statusFromInterval = _getStatusFromInterval(from, to);
                    checked = statusFromInterval === 'off';
                    parameters = parameters = _getMoveLatchonParameters(latchon, statusFromInterval, true);
                }
                else {
                    checked = newStatus === 'off';
                    parameters = _getMoveLatchonParameters(latchon, newStatus, true);
                }


                latchon.dataset.checked = checked;

                _softlyMoveLatchon(parameters, function () {
                    _performLatchonAnimation(latchon.parentNode, parameters.opacity);
                });

                var autocloseByUse = false;
                Controller.updateDetailsWithMutualExclusion(id, newAutocloseValue, autocloseByUse, newStatus, function (err) {
                    if (!ErrorManager.checkError(err)) {

                        // Revert 
                        dom.enableScheduleSwitch.checked = !dom.enableScheduleSwitch.checked;

                        dom.enableAutocloseSwitch.checked = autocloseChecked;
                        dom.lockAllOperationsSwitch.dataset.autoclose = previousMinutesInAutolock;

                        dom.enableAutocloseByUseSwitch.checked = autocloseByUseChecked;
                    }
                });
            };

            dom.enableScheduleSwitch.addEventListener('click', scheduleSwitchListener);

            var autocloseListener = function (e) {

                // Backup scheduler data
                var previousScheduleSwitchStatus = dom.enableScheduleSwitch.checked;
                var previousPdmScheduleContainerVisibility = !dom.pdmScheduleContainer.classList.contains('hide');

                // Update scheduler UI
                dom.enableScheduleSwitch.checked = false;
                dom.pdmScheduleContainer.classList.add('hide');
                dom.blueRibbon.classList.add('hide');

                Controller.getPreferences(function (err, preferences) {

                    var autolockValueInServer = preferences.autolock;
                    var newAutoCloseAmount = dom.enableAutocloseSwitch.checked ? autolockValueInServer : 0;
                    dom.lockAllOperationsSwitch.dataset.autoclose = newAutoCloseAmount;

                    // Update autolock UI
                    renderAutolockByTimeDetails(preferences.autolock);

                    // Update info in server
                    var id = dom.enableAutocloseSwitch.dataset.opId;
                    var status = dom.lockAllOperationsSwitch.dataset.checked === 'true' ? 'off' : 'on';
                    var autocloseByUse = null; // Does not change

                    Controller.updateDetailsWithMutualExclusion(id, newAutoCloseAmount, autocloseByUse, status, function (err) {
                        if (!ErrorManager.checkError(err)) {

                            // Revert scheduler UI
                            dom.enableScheduleSwitch.checked = previousScheduleSwitchStatus;
                            if (previousPdmScheduleContainerVisibility) {
                                dom.pdmScheduleContainer.classList.remove('hide');
                                dom.blueRibbon.classList.remove('hide');
                            }

                            // Revert autolock UI
                            dom.enableAutocloseSwitch.checked = !dom.enableAutocloseSwitch.checked;
                        }
                    });
                });
            };
            dom.enableAutocloseSwitch.addEventListener('click', autocloseListener);


            var autocloseByUseListener = function (e) {

                // Backup scheduler data
                var previousScheduleSwitchStatus = dom.enableScheduleSwitch.checked;
                var previousPdmScheduleContainerVisibility = !dom.pdmScheduleContainer.classList.contains('hide');

                // Update scheduler UI
                dom.enableScheduleSwitch.checked = false;
                dom.pdmScheduleContainer.classList.add('hide');
                dom.blueRibbon.classList.add('hide');

                var newAutocloseByUseStatus = dom.enableAutocloseByUseSwitch.checked;
                dom.lockAllOperationsSwitch.dataset.lock_on_request = newAutocloseByUseStatus;

                // Update info in server
                var id = dom.enableAutocloseSwitch.dataset.opId;
                var status = dom.lockAllOperationsSwitch.dataset.checked === 'true' ? 'off' : 'on';
                var autoclose = null; // Does not change

                Controller.updateDetailsWithMutualExclusion(id, autoclose, newAutocloseByUseStatus, status, function (err) {
                    if (!ErrorManager.checkError(err)) {

                        // Revert scheduler UI
                        dom.enableScheduleSwitch.checked = previousScheduleSwitchStatus;
                        if (previousPdmScheduleContainerVisibility) {
                            dom.pdmScheduleContainer.classList.remove('hide');
                            dom.blueRibbon.classList.remove('hide');
                        }

                        // Revert autolock by use UI
                        dom.enableAutocloseSwitch.checked = !dom.enableAutocloseSwitch.checked;
                        dom.lockAllOperationsSwitch.dataset.lock_on_request = !newAutocloseByUseStatus;
                    }
                });
            };
            dom.enableAutocloseByUseSwitch.addEventListener('click', autocloseByUseListener);

            // Pairing panel
            dom.backFromPairing.addEventListener('click', function () {
                this.load('main');
            }.bind(this));
            dom.showPairingTutorial.addEventListener('click', function () {
                this.load('pairing-tutorial');
            }.bind(this));
            dom.generateCode.addEventListener('click', function () {
                var refreshTime = 100; // ms
                dom.generateCode.disabled = true; // to avoid double click
                Controller.getCode(function showCode(error, code) {
                    if (!ErrorManager.checkError(error)) {
                        return;
                    }
                    dom.codeGenerated.textContent = code.token;
                    dom.codeCountdown.value = code.expires;
                    dom.pairingPanel.classList.toggle('generate-code');
                    pairingTimer = setInterval(function () {
                        var value = +dom.codeCountdown.value - (refreshTime / 1000);
                        dom.codeCountdown.value = value;
                        dom.codeCountdownRemainingTime.innerHTML = Math.ceil(value) + ' ' + navigator.mozL10n.get('second');
                        if (value === 0) {
                            _cleanPairing();
                        }
                    }, refreshTime); // update value every second
                    dom.codeCountdownRemainingTime.innerHTML = '';
                });
            });

            // Application panel
            dom.operationsList.addEventListener('click',
                    _operationsListHandler.bind(this));

            // Pairing Tutorial
            _initPairingTutorial();

            // Startup Tutorial
            _initStartupTutorial();

            // Security panel
            SecurityUI.init(dom);

            // Log
            dom.backFromLog.addEventListener('click', function () {
                this.load('main');
                setTimeout(_clearLogFromTo, 1000);
            }.bind(this));

            dom.logFilter.addEventListener('click', function () {
                _displayLogFilter();
                window.location = '#log-filter-openModal';
            }.bind(this));

            dom.logFilterCloseButton.addEventListener('click', function () {

                function getSelectedLogTypes() {
                    var types = [];
                    var selectedLi = dom.logFilterOpenModal.querySelectorAll('li.checked');
                    for (var i = 0; i < selectedLi.length; i++) {
                        var currentLi = selectedLi[i];

                        var currentType = currentLi.className.replace('checked', '').trim();
                        types.push(currentType);

                        setTimeout(function () {
                            currentLi.classList.remove('checked');
                        }, 1000);

                    }
                    return types;
                }
                var selectedLogTypes = getSelectedLogTypes();
                _updateLog(selectedLogTypes);
                Controller.storeLogFilter(selectedLogTypes);
            });

            dom.logStatisticsBanner.addEventListener('click', function () {
                _displayStatsDialog();
            }.bind(this));

            dom.logFromDate.addEventListener('click', function (evt) {
                evt.stopPropagation();
                _updateLogRangeValue(evt.target, function () {
                    var toTimeStamp = dom.logToDate.getAttribute('timestamp');
                    if (toTimeStamp === undefined || toTimeStamp === null) {
                        _setDateInFilter(dom.logToDate, Utils.getTodayString());
                    }
                    else {
                        var fromTimeStamp = dom.logFromDate.getAttribute('timestamp');
                        if (parseInt(fromTimeStamp) > parseInt(toTimeStamp)) {
                            dom.logToDate.setAttribute('timestamp', fromTimeStamp);
                            dom.logToDate.textContent = dom.logFromDate.textContent;
                        }
                    }
                    _reloadLogRange();
                });
            }.bind(this));

            dom.logToDate.addEventListener('click', function (evt) {
                evt.stopPropagation();
                _updateLogRangeValue(evt.target, function () {
                    var fromTimeStamp = dom.logFromDate.getAttribute('timestamp');
                    if (fromTimeStamp === undefined || fromTimeStamp === null) {
                        dom.logFromDate.setAttribute('timestamp', dom.logToDate.getAttribute('timestamp'));
                        dom.logFromDate.textContent = dom.logToDate.textContent;
                    }
                    else {
                        var toTimeStamp = dom.logToDate.getAttribute('timestamp');
                        if (parseInt(fromTimeStamp) > parseInt(toTimeStamp)) {
                            dom.logFromDate.setAttribute('timestamp', toTimeStamp);
                            dom.logFromDate.textContent = dom.logToDate.textContent;
                        }
                    }
                    _reloadLogRange();
                });
            }.bind(this));

            // Once everything is loaded, load right panel

            if (!authenticated) {
                this.load('startup-tutorial');
            } else {
                _renderRootOperations();
                /* A second call to this method is required in order to properly
                 * display Latchon. During the first call the UI elements have not
                 * been rendered yet, so Latchon background dimensions are not 
                 * right. In consequence, the Latchon switch is not displayed in
                 * one of the sides, it is displayed in the middle*/
                _renderRootOperations(true);
            }

            document.addEventListener('mozvisibilitychange', function () {

                if (document.hidden) {
                    _loginPeriodTimedOut(function (timedOut) {
                        if (timedOut) {
                            WebviewOverlay.hide();
                            UIManager.load('signin');
                            Controller.logout();
                        }
                    });
                }
            }, false);

            var localizationCode = navigator.mozL10n.language.code;
            var localizationCodeTwoLetters = localizationCode.substr(0, 2);

            dom.html.setAttribute('locale', localizationCodeTwoLetters);

            // Set draggable list of applications
            Sortable.create(dom.applicationsList, {
                scroll: false,
                draggable: '.allow-sorting'
            });

            Sortable.create(dom.operationsList, {
                scroll: false,
                draggable: '.allow-sorting'
            });

            Sortable.create(dom.groupOperationsList, {
                scroll: false,
                draggable: '.allow-sorting'
            });

            Sortable.utils.on(dom.applicationsList, 'end', function () {
                var orderList = _getApplicationOrderList(dom.applicationsList);
                Controller.updateOrder(orderList);
            });

            Sortable.utils.on(dom.operationsList, 'end', function () {
                var orderList = _getApplicationOrderList(dom.operationsList);
                Controller.updateOrder(orderList);
            });

            Sortable.utils.on(dom.groupOperationsList, 'end', function () {
                var orderList = _getApplicationOrderList(dom.groupOperationsList);
                Controller.updateOrder(orderList);
            });

            // Groups

            dom.groupOperationsList.addEventListener('click',
                    _groupListHandler.bind(this));

            dom.backFromGroup.addEventListener('click', function () {
                _hideGroupModal();
                _renderRootOperations();
            });
        },
        clearSigninForm: function () {
            dom.signinUser.value = '';
            dom.signinPassword.value = '';
        },
        getCredentials: function () {
            return {
                user: dom.signinUser.value.trim(),
                password: dom.signinPassword.value
            };
        },
        showEmptyUsernameError: function (err) {
            debug('Empty username ' + err);
            Status.show(navigator.mozL10n.get('login_empty_username'));
        },
        showEmptyPasswordError: function (err) {
            debug('Empty password ' + err);
            Status.show(navigator.mozL10n.get('login_empty_password'));
        },
        showNotAnEmailError: function (err) {
            debug('Error: username is not a valid email' + err);
            Status.show(navigator.mozL10n.get('login_invalid_email'));
        },
        showRegister: function () {
            debug('> show register url');
            if (!Controller.checkOnline()) {
                return;
            }
            var url = Config.environment.registerURL;
            if (!url) {
                return;
            }
            loadPageOnBrowser(url + "?hideCloseButton=true");
        },
        load: function (view) {
            var className;
            var previousClassName = document.body.className;
            var direction, coverStatus;
            switch (view) {
                case 'signin':
                    className = 'signin';
                    _hideSettingsMenu();
                    if (document.body.className === 'startup-tutorial') {
                        direction = 'down';
                        coverStatus = 'down';
                    } else {
                        direction = 'right';
                        coverStatus = 'right';
                    }
                    break;
                case 'main':
                    className = 'main';
                    // If settings was shown, hide and that's all!
                    if (document.body.classList.contains('settings')) {
                        document.body.classList.remove('settings');
                        return;
                    }
                    // If Settings is not shown

                    if (previousClassName === 'signin') {
                        direction = 'left';
                        coverStatus = 'left';
                    } else if (previousClassName === 'application' || previousClassName === 'group' || previousClassName === 'log' || previousClassName === 'security') {
                        direction = 'right';
                        coverStatus = 'right';
                    } else {
                        direction = 'down';
                        coverStatus = 'down';
                    }
                    break;
                case 'basic-tutorial':
                    // Go to page 1
                    _setTutorialStep(1);
                    _hideSettingsMenu();
                    className = 'basic-tutorial';
                    direction = 'up';
                    coverStatus = 'up';
                    break;
                case 'pairing':
                    // Everytime we enter on pairing, we need to start again
                    _cleanPairing();
                    className = 'pairing';
                    if (document.body.className === 'main' || document.body.className === 'group') {
                        direction = 'up';
                        coverStatus = 'up';
                    } else {
                        direction = 'down';
                        coverStatus = 'down';
                    }
                    break;
                case 'application':
                    className = 'application';
                    direction = 'left';
                    coverStatus = 'left';
                    break;
                case 'group':
                    className = 'group';
                    if (document.body.className === 'main') {
                        direction = 'left';
                        coverStatus = 'left';
                    }
                    else {
                        direction = 'right';
                        coverStatus = 'right';
                    }
                    break;
                case 'pairing-tutorial':
                    className = 'pairing-tutorial';
                    direction = 'up';
                    coverStatus = 'up';
                    break;
                case 'startup-tutorial':
                    className = 'startup-tutorial';
                    direction = 'up';
                    coverStatus = 'up';
                    break;
                case 'settings':
                    document.body.classList.add('settings');
                    break;
                case 'log':
                    className = 'log';
                    direction = 'left';
                    coverStatus = 'left';
                    break;
                case 'security':
                    _hideSettingsMenu();
                    className = 'security';
                    direction = 'left';
                    coverStatus = 'left';
                    break;
            }
            if (!className) {
                return;
            }

            if (previousClassName === '' ||
                    previousClassName.length === 0 ||
                    document.body.classList.contains(className)) {
                document.body.className = className;
                return;
            }

            // Do we need a transition?
            if (!document.body.classList.contains(className)) {
                // Upgrade the moz element for showing the transition
                dom.currentCover.style.background =
                        '-moz-element(#' + previousClassName + '-panel)';
                dom.nextCover.style.background =
                        '-moz-element(#' + className + '-panel)';
                // Status the cover previous status
                document.body.dataset.coverStatus = coverStatus;
                // And apply the transition
                setTimeout(function () {
                    document.body.dataset.transitionEffect = direction;
                    dom.currentCover.addEventListener('transitionend',
                            function onTransition() {
                                dom.currentCover.removeEventListener('transitionend', onTransition);
                                // Clean all transition styles
                                document.body.dataset.transitionEffect = '';
                                document.body.dataset.coverStatus = '';
                                // Show the right non-mockup panel
                                document.body.className = className;

                                if (previousClassName === 'basic-tutorial') {
                                    document.body.classList.add('settings');
                                }
                            });
                }, 100); // This is for avoiding flickering. Workaround
            }
        },
        renderApplicationsList: function (apps) {
            // Clean the DOM
            var listItems = dom.applicationsList.querySelectorAll('li');
            var numberOfListItems = listItems.length;
            for (var i = 0; i < numberOfListItems; i++) {
                var currentListItem = listItems[i];
                if (!currentListItem.classList.contains('application-list-submenu')) {
                    currentListItem.parentNode.removeChild(currentListItem);
                }
            }

            if (!dom.applicationListSubmenu.classList.contains('hide')) {
                dom.applicationListSubmenu.classList.add('hide');
            }

            var orderedApps = _reorder(apps);

            orderedApps.forEach(function (currentApp) {
                var opID = currentApp.opID;
                var app = currentApp.app;

                var isLatchon = opID === Config.environment.latchonID;
                var isInGroup = app.groupId !== undefined;

                var displayCurrentApp = !isLatchon && !isInGroup;
                if (displayCurrentApp) {
                    // Create structure
                    dom.applicationsList.appendChild(_createOperationDOM(app, opID, true));

                } else if (isLatchon) {
                    var latchon = dom.lockAllApplicationsSwitch;
                    var checked = app.status === 'off';
                    latchon.dataset.checked = checked;

                    var parameters = _getMoveLatchonParameters(latchon, app.status, true);

                    _softlyMoveLatchon(parameters, function () {
                        _performLatchonAnimation(latchon.parentNode, parameters.opacity);
                    });
                }
            });

            var container = dom.applicationsList;
            var orangeRibbonAlreadyShown = _isOrangeRibbonShown(container);

            _orangeRibbonNeeded(container, function (needed) {
                if (needed) {
                    if (!orangeRibbonAlreadyShown) {
                        var ribbon = createOrangeRibbon();
                        dom.applicationsList.insertBefore(ribbon, dom.applicationsList.firstChild);
                    }
                }
                else {
                    _removeOrangeRibbon(dom.applicationsList);
                }
            });
        },
        addNewOperation: function (appId, app) {
            debug('.. creating new app: ' + appId + ' - ' + app);
            debug(JSON.stringify(app));
            dom.applicationsList.appendChild(_createOperationDOM(app, appId, true));
        },
        updateOperation: function (opId) {
            debug('--- updating state of operation ' + opId);
            _openOperationsList(opId, true);
        },
        removeOperation: function (opId, operation) {
            debug('-- removing app from DOM ' + opId + '/' + operation);
            // TODO need to remove it (or load again the full tree?)
        },
        renderAllOperations: function () {
            _renderRootOperations();
        },
        updateOpDetails: function (operation, opID) {
            dom.lockAllOperationsSwitch.dataset.checked = operation.status === 'off';
        },
        getPreferences: function (callback) {

            _getPreferences(function (err, preferences) {

                debug("UI > getPreferences: return " + JSON.stringify(preferences));
                callback(preferences);

            });
        },
        loadPageOnBrowser: function (url) {
            loadPageOnBrowser(url);
        },
        getParentOfClass: _getParentOfClass,
        getCurrentOperationId: function () {
            var className = document.body.className;
            if (className === 'main') {
                return 'main';
            }
            else if (className === 'application') {

                var h2 = dom.applicationPanel.querySelector('header h2');

                if (h2.className !== 'hide') {
                    // Watching operations
                    return h2.getAttribute('data-opid');
                }
                else {
                    // Watching applications
                    var h1 = dom.applicationPanel.querySelector('header h1');
                    return h1.dataset.opid;
                }
            }
        },
        logoutRequired: function (callback) {
            _loginPeriodTimedOut(function (timedOut) {
                callback(timedOut);
            });
        },
        enableLatchonUI: function (status) {
            dom.lockAllApplicationsSwitch.dataset.checked = status;

            var listItems = dom.applicationsList.querySelectorAll('li.app');

            _updateGreyCoverOnApps(status, listItems);
        },
        updateSwitchBlur: function () {

            // Schedule switch
            if (dom.enableAutocloseByUseSwitch.checked || dom.enableAutocloseSwitch.checked) {
                dom.enableScheduleSwitch.disabled = true;
                dom.enableScheduleText.classList.add('blurred');
            }
            else {
                dom.enableScheduleSwitch.disabled = false;
                dom.enableScheduleText.classList.remove('blurred');
            }

            // Autoclose and autoclose by use switch
            if (dom.enableScheduleSwitch.checked) {
                dom.enableAutocloseSwitch.disabled = true;
                dom.enableAutocloseByUseSwitch.disabled = true;
                dom.enableAutocloseText.classList.add('blurred');
                dom.enableAutocloseByUseText.classList.add('blurred');
            }
            else {
                dom.enableAutocloseSwitch.disabled = false;
                dom.enableAutocloseByUseSwitch.disabled = false;
                dom.enableAutocloseText.classList.remove('blurred');
                dom.enableAutocloseByUseText.classList.remove('blurred');
            }
        },
        showLockedAncestorsDialog: function (ancestors, onUnlockAncestors) {
            var numberOfLockedAncestors = Object.keys(ancestors).length;
            var numberOfLockedAncestorsExcludingLatchon = numberOfLockedAncestors;

            var list = dom.blockedOpenModal.querySelector('ul');
            list.innerHTML = '';

            Object.keys(ancestors).forEach(function (opId) {

                if (opId !== Config.environment.latchonID) {
                    var li = document.createElement('li');
                    li.innerHTML = Utils.chooseName(ancestors[opId]);
                    list.appendChild(li);
                }
                else {
                    numberOfLockedAncestorsExcludingLatchon--;
                }
            });

            if (numberOfLockedAncestorsExcludingLatchon > 0) {
                dom.blockedAlertInfo.classList.remove('hide');
                list.classList.remove('hide');
            }
            else {
                dom.blockedAlertInfo.classList.add('hide');
                list.classList.add('hide');
            }

            if (numberOfLockedAncestorsExcludingLatchon !== numberOfLockedAncestors) {
                dom.blockedAlertLatchon.classList.remove('hide');
            }
            else {
                dom.blockedAlertLatchon.classList.add('hide');
            }

            window.location = '#blocked-openModal';
            _removeAllEvents('blockedConfirmed');
            dom.blockedConfirmed.addEventListener('click', function () {
                onUnlockAncestors();
            });
        }
    };

    exports.UIManager = UIManager;
}(this));
