// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Legacy supervised user creation flow screen.
 */

login.createScreen('SupervisedUserCreationScreen',
                   'supervised-user-creation', function() {
  var MAX_NAME_LENGTH = 50;
  var UserImagesGrid = options.UserImagesGrid;
  var ButtonImages = UserImagesGrid.ButtonImages;

  var ManagerPod = cr.ui.define(function() {
    var node = $('supervised-user-creation-manager-template').cloneNode(true);
    node.removeAttribute('id');
    node.removeAttribute('hidden');
    return node;
  });

  ManagerPod.userImageSalt_ = {};

  /**
   * UI element for displaying single account in list of possible managers for
   * new supervised user.
   * @type {Object}
   */
  ManagerPod.prototype = {
    __proto__: HTMLDivElement.prototype,

    /** @override */
    decorate: function() {
      // Mousedown has to be used instead of click to be able to prevent 'focus'
      // event later.
      this.addEventListener('mousedown',
                            this.handleMouseDown_.bind(this));
      var screen = $('supervised-user-creation');
      var managerPod = this;
      var managerPodList = screen.managerList_;
      var hideManagerPasswordError = function(element) {
        managerPod.passwordElement.classList.remove('password-error');
        $('bubble').hide();
      };

      screen.configureTextInput(
          this.passwordElement,
          screen.updateNextButtonForManager_.bind(screen),
          screen.validIfNotEmpty_.bind(screen),
          function(element) {
            screen.getScreenButton('next').focus();
          },
          hideManagerPasswordError);

      this.passwordElement.addEventListener('keydown', function(e) {
        switch (e.keyIdentifier) {
          case 'Up':
            managerPodList.selectNextPod(-1);
            e.stopPropagation();
            break;
          case 'Down':
            managerPodList.selectNextPod(+1);
            e.stopPropagation();
            break;
        }
      });
    },

    /**
     * Updates UI elements from user data.
     */
    update: function() {
      this.imageElement.src = 'chrome://userimage/' + this.user.username +
          '?id=' + ManagerPod.userImageSalt_[this.user.username];

      this.nameElement.textContent = this.user.displayName;
      this.emailElement.textContent = this.user.emailAddress;
    },

    showPasswordError: function() {
      this.passwordElement.classList.add('password-error');
      $('bubble').showTextForElement(
          this.passwordElement,
          loadTimeData.getString(
              'createSupervisedUserWrongManagerPasswordText'),
          cr.ui.Bubble.Attachment.BOTTOM,
          24, 4);
    },

    /**
     * Brings focus to password field.
     */
    focusInput: function() {
      this.passwordElement.focus();
    },

    /**
     * Gets image element.
     * @type {!HTMLImageElement}
     */
    get imageElement() {
      return this.querySelector('.supervised-user-creation-manager-image');
    },

    /**
     * Gets name element.
     * @type {!HTMLDivElement}
     */
    get nameElement() {
      return this.querySelector('.supervised-user-creation-manager-name');
    },

    /**
     * Gets e-mail element.
     * @type {!HTMLDivElement}
     */
    get emailElement() {
      return this.querySelector('.supervised-user-creation-manager-email');
    },

    /**
     * Gets password element.
     * @type {!HTMLDivElement}
     */
    get passwordElement() {
      return this.querySelector('.supervised-user-creation-manager-password');
    },

    /**
     * Gets password enclosing block.
     * @type {!HTMLDivElement}
     */
    get passwordBlock() {
      return this.querySelector('.password-block');
    },

    /** @override */
    handleMouseDown_: function(e) {
      this.parentNode.selectPod(this);
      // Prevent default so that we don't trigger 'focus' event.
      e.preventDefault();
    },

    /**
     * The user that this pod represents.
     * @type {!Object}
     */
    user_: undefined,
    get user() {
      return this.user_;
    },
    set user(userDict) {
      this.user_ = userDict;
      this.update();
    },
  };

  var ManagerPodList = cr.ui.define('div');

  /**
   * UI element for selecting manager account for new supervised user.
   * @type {Object}
   */
  ManagerPodList.prototype = {
    __proto__: HTMLDivElement.prototype,

    selectedPod_: null,

    /** @override */
    decorate: function() {
    },

    /**
     * Returns all the pods in this pod list.
     * @type {NodeList}
     */
    get pods() {
      return this.children;
    },

    addPod: function(manager) {
      var managerPod = new ManagerPod({user: manager});
      this.appendChild(managerPod);
      managerPod.update();
    },

    clearPods: function() {
      this.innerHTML = '';
      this.selectedPod_ = null;
    },

    selectPod: function(podToSelect) {
      if ((this.selectedPod_ == podToSelect) && !!podToSelect) {
        podToSelect.focusInput();
        return;
      }
      this.selectedPod_ = podToSelect;
      for (var i = 0, pod; pod = this.pods[i]; ++i) {
        if (pod != podToSelect) {
          pod.classList.remove('focused');
          pod.passwordElement.value = '';
          pod.passwordBlock.hidden = true;
        }
      }
      if (!podToSelect)
        return;
      podToSelect.classList.add('focused');
      podToSelect.passwordBlock.hidden = false;
      podToSelect.passwordElement.value = '';
      podToSelect.focusInput();
      chrome.send('managerSelectedOnSupervisedUserCreationFlow',
          [podToSelect.user.username]);
    },

    /**
     * Select pod next to currently selected one in given |direction|.
     * @param {integer} direction - +1 for selecting pod below current, -1 for
     *     selecting pod above current.
     * @type {boolean} returns if selected pod has changed.
     */
    selectNextPod: function(direction) {
      if (!this.selectedPod_)
        return false;
      var index = -1;
      for (var i = 0, pod; pod = this.pods[i]; ++i) {
        if (pod == this.selectedPod_) {
          index = i;
          break;
        }
      }
      if (-1 == index)
        return false;
      index = index + direction;
      if (index < 0 || index >= this.pods.length)
        return false;
      this.selectPod(this.pods[index]);
      return true;
    }
  };

  var ImportPod = cr.ui.define(function() {
    var node = $('supervised-user-creation-import-template').cloneNode(true);
    node.removeAttribute('id');
    node.removeAttribute('hidden');
    return node;
  });

  /**
   * UI element for displaying single supervised user in list of possible users
   * for importing existing users.
   * @type {Object}
   */
  ImportPod.prototype = {
    __proto__: HTMLDivElement.prototype,

    /** @override */
    decorate: function() {
      // Mousedown has to be used instead of click to be able to prevent 'focus'
      // event later.
      this.addEventListener('mousedown', this.handleMouseDown_.bind(this));
      var screen = $('supervised-user-creation');
      var importList = screen.importList_;
    },

    /**
     * Updates UI elements from user data.
     */
    update: function() {
      this.imageElement.src = this.user.avatarurl;
      this.nameElement.textContent = this.user.name;
      if (this.user.exists) {
        if (this.user.conflict == 'imported') {
          this.nameElement.textContent =
              loadTimeData.getStringF('importUserExists', this.user.name);
        } else {
          this.nameElement.textContent =
              loadTimeData.getStringF('importUsernameExists', this.user.name);
        }
      }
      this.classList.toggle('imported', this.user.exists);
    },

    /**
     * Gets image element.
     * @type {!HTMLImageElement}
     */
    get imageElement() {
      return this.querySelector('.import-pod-image');
    },

    /**
     * Gets name element.
     * @type {!HTMLDivElement}
     */
    get nameElement() {
      return this.querySelector('.import-pod-name');
    },

    /** @override */
    handleMouseDown_: function(e) {
      this.parentNode.selectPod(this);
      // Prevent default so that we don't trigger 'focus' event.
      e.preventDefault();
    },

    /**
     * The user that this pod represents.
     * @type {Object}
     */
    user_: undefined,

    get user() {
      return this.user_;
    },

    set user(userDict) {
      this.user_ = userDict;
      this.update();
    },
  };

  var ImportPodList = cr.ui.define('div');

  /**
   * UI element for selecting existing supervised user for import.
   * @type {Object}
   */
  ImportPodList.prototype = {
    __proto__: HTMLDivElement.prototype,

    selectedPod_: null,

    /** @override */
    decorate: function() {
      this.setAttribute('tabIndex', 0);
      this.classList.add('nofocus');
      var importList = this;
      var screen = $('supervised-user-creation');

      this.addEventListener('focus', function(e) {
        if (importList.selectedPod_ == null) {
          if (importList.pods.length > 0)
            importList.selectPod(importList.pods[0]);
        }
      });

      this.addEventListener('keydown', function(e) {
        switch (e.keyIdentifier) {
          case 'Up':
            importList.selectNextPod(-1);
            e.stopPropagation();
            break;
          case 'Enter':
            if (importList.selectedPod_ != null)
              screen.importSupervisedUser_();
            e.stopPropagation();
            break;
          case 'Down':
            importList.selectNextPod(+1);
            e.stopPropagation();
            break;
        }
      });
    },

    /**
     * Returns all the pods in this pod list.
     * @type {NodeList}
     */
    get pods() {
      return this.children;
    },

    /**
     * Returns selected pod.
     * @type {Node}
     */
    get selectedPod() {
      return this.selectedPod_;
    },

    addPod: function(user) {
      var importPod = new ImportPod({user: user});
      this.appendChild(importPod);
      importPod.update();
    },

    clearPods: function() {
      this.innerHTML = '';
      this.selectedPod_ = null;
    },

    scrollIntoView: function(pod) {
      scroller = this.parentNode;
      var itemHeight = pod.getBoundingClientRect().height;
      var scrollTop = scroller.scrollTop;
      var top = pod.offsetTop - scroller.offsetTop;
      var clientHeight = scroller.clientHeight;

      var self = scroller;

      // Function to adjust the tops of viewport and row.
      function scrollToAdjustTop() {
        self.scrollTop = top;
        return true;
      };
      // Function to adjust the bottoms of viewport and row.
      function scrollToAdjustBottom() {
        var cs = getComputedStyle(self);
        var paddingY = parseInt(cs.paddingTop, 10) +
                       parseInt(cs.paddingBottom, 10);

        if (top + itemHeight > scrollTop + clientHeight - paddingY) {
          self.scrollTop = top + itemHeight - clientHeight + paddingY;
          return true;
        }
        return false;
      };

      // Check if the entire of given indexed row can be shown in the viewport.
      if (itemHeight <= clientHeight) {
        if (top < scrollTop)
          return scrollToAdjustTop();
        if (scrollTop + clientHeight < top + itemHeight)
          return scrollToAdjustBottom();
      } else {
        if (scrollTop < top)
          return scrollToAdjustTop();
        if (top + itemHeight < scrollTop + clientHeight)
          return scrollToAdjustBottom();
      }
      return false;
    },

    /**
     * @param {Element} podToSelect - pod to select, can be null.
     */
    selectPod: function(podToSelect) {
      if ((this.selectedPod_ == podToSelect) && !!podToSelect) {
        return;
      }
      this.selectedPod_ = podToSelect;
      for (var i = 0; i < this.pods.length; i++) {
        var pod = this.pods[i];
        if (pod != podToSelect)
          pod.classList.remove('focused');
      }
      if (!podToSelect)
        return;
      podToSelect.classList.add('focused');
      podToSelect.focus();
      var screen = $('supervised-user-creation');
      if (!this.selectedPod_) {
        screen.getScreenButton('import').disabled = true;
      } else {
        screen.getScreenButton('import').disabled =
            this.selectedPod_.user.exists;
        if (!this.selectedPod_.user.exists) {
          chrome.send('userSelectedForImportInSupervisedUserCreationFlow',
                      [podToSelect.user.id]);
        }
      }
    },

    selectNextPod: function(direction) {
      if (!this.selectedPod_)
        return false;
      var index = -1;
      for (var i = 0, pod; pod = this.pods[i]; ++i) {
        if (pod == this.selectedPod_) {
          index = i;
          break;
        }
      }
      if (-1 == index)
        return false;
      index = index + direction;
      if (index < 0 || index >= this.pods.length)
        return false;
      this.selectPod(this.pods[index]);
      return true;
    },

    selectUser: function(user_id) {
      for (var i = 0, pod; pod = this.pods[i]; ++i) {
        if (pod.user.id == user_id) {
          this.selectPod(pod);
          this.scrollIntoView(pod);
          break;
        }
      }
    },
  };

  return {
    EXTERNAL_API: [
      'loadManagers',
      'setCameraPresent',
      'setDefaultImages',
      'setExistingSupervisedUsers',
      'showErrorPage',
      'showIntroPage',
      'showManagerPage',
      'showManagerPasswordError',
      'showPage',
      'showPasswordError',
      'showProgress',
      'showStatusError',
      'showTutorialPage',
      'showUsernamePage',
      'supervisedUserNameError',
      'supervisedUserNameOk',
      'supervisedUserSuggestImport',
    ],

    lastVerifiedName_: null,
    lastIncorrectUserName_: null,
    managerList_: null,
    importList_: null,

    currentPage_: null,
    imagesRequested_: false,

    // Contains data that can be auto-shared with handler.
    context_: {},

    /** @override */
    decorate: function() {
      this.managerList_ = new ManagerPodList();
      $('supervised-user-creation-managers-pane').appendChild(
          this.managerList_);

      this.importList_ = new ImportPodList();
      $('supervised-user-creation-import-pane').appendChild(this.importList_);

      var userNameField = $('supervised-user-creation-name');
      var passwordField = $('supervised-user-creation-password');
      var password2Field = $('supervised-user-creation-password-confirm');

      var creationScreen = this;

      var hideUserPasswordError = function(element) {
        $('bubble').hide();
        $('supervised-user-creation-password').classList.remove(
            'password-error');
      };

      this.configureTextInput(userNameField,
                              this.checkUserName_.bind(this),
                              this.validIfNotEmpty_.bind(this),
                              function(element) {
                                passwordField.focus();
                              },
                              this.clearUserNameError_.bind(this));
      this.configureTextInput(passwordField,
                              this.updateNextButtonForUser_.bind(this),
                              this.validIfNotEmpty_.bind(this),
                              function(element) {
                                password2Field.focus();
                              },
                              hideUserPasswordError);
      this.configureTextInput(password2Field,
                              this.updateNextButtonForUser_.bind(this),
                              this.validIfNotEmpty_.bind(this),
                              function(element) {
                                creationScreen.getScreenButton('next').focus();
                              },
                              hideUserPasswordError);

      this.getScreenButton('error').addEventListener('click', function(e) {
        creationScreen.handleErrorButtonPressed_();
        e.stopPropagation();
      });

      /*
      TODO(antrim) : this is an explicit code duplications with UserImageScreen.
      It should be removed by issue 251179.
      */
      var imageGrid = this.getScreenElement('image-grid');
      UserImagesGrid.decorate(imageGrid);

      // Preview image will track the selected item's URL.
      var previewElement = this.getScreenElement('image-preview');
      previewElement.oncontextmenu = function(e) { e.preventDefault(); };

      imageGrid.previewElement = previewElement;
      imageGrid.selectionType = 'default';
      imageGrid.flipPhotoElement = this.getScreenElement('flip-photo');

      imageGrid.addEventListener('activate',
                                 this.handleActivate_.bind(this));
      imageGrid.addEventListener('select',
                                 this.handleSelect_.bind(this));
      imageGrid.addEventListener('phototaken',
                                 this.handlePhotoTaken_.bind(this));
      imageGrid.addEventListener('photoupdated',
                                 this.handlePhotoUpdated_.bind(this));
      // Set the title for camera item in the grid.
      imageGrid.setCameraTitles(
          loadTimeData.getString('takePhoto'),
          loadTimeData.getString('photoFromCamera'));

      this.getScreenElement('take-photo').addEventListener(
          'click', this.handleTakePhoto_.bind(this));
      this.getScreenElement('discard-photo').addEventListener(
          'click', this.handleDiscardPhoto_.bind(this));

      // Toggle 'animation' class for the duration of WebKit transition.
      this.getScreenElement('flip-photo').addEventListener(
          'click', this.handleFlipPhoto_.bind(this));
      this.getScreenElement('image-stream-crop').addEventListener(
          'webkitTransitionEnd', function(e) {
            previewElement.classList.remove('animation');
          });
      this.getScreenElement('image-preview-img').addEventListener(
          'webkitTransitionEnd', function(e) {
            previewElement.classList.remove('animation');
          });

      $('supervised-user-creation-close-button-item').addEventListener(
          'click', function(e) {
            this.cancel();
            e.preventDefault();
          }.bind(this));
    },

    buttonIds: [],

    /**
     * Creates button for adding to controls.
     * @param {string} buttonId -- id for button, have to be unique within
     *   screen. Actual id will be prefixed with screen name and appended with
     *   '-button'. Use getScreenButton(buttonId) to find it later.
     * @param {string} i18nPrefix -- screen prefix for i18n values.
     * @param {function} callback -- will be called on button press with
     *   buttonId parameter.
     * @param {array} pages -- list of pages where this button should be
     *   displayed.
     * @param {array} classes -- list of additional CSS classes for button.
     */
    makeButton: function(buttonId, i18nPrefix, callback, pages, classes) {
      var capitalizedId = buttonId.charAt(0).toUpperCase() + buttonId.slice(1);
      this.buttonIds.push(buttonId);
      var result = this.ownerDocument.createElement('button');
      result.id = this.name() + '-' + buttonId + '-button';
      result.classList.add('screen-control-button');
      for (var i = 0; i < classes.length; i++) {
        result.classList.add(classes[i]);
      }
      result.textContent = loadTimeData.
          getString(i18nPrefix + capitalizedId + 'ButtonTitle');
      result.addEventListener('click', function(e) {
        callback(buttonId);
        e.stopPropagation();
      });
      result.pages = pages;
      return result;
    },

    /**
     * Simple validator for |configureTextInput|.
     * Element is considered valid if it has any text.
     * @param {Element} element - element to be validated.
     * @return {boolean} - true, if element has any text.
     */
    validIfNotEmpty_: function(element) {
      return (element.value.length > 0);
    },

    /**
     * Configure text-input |element|.
     * @param {Element} element - element to be configured.
     * @param {function(element)} inputChangeListener - function that will be
     *    called upon any button press/release.
     * @param {function(element)} validator - function that will be called when
     *    Enter is pressed. If it returns |true| then advance to next element.
     * @param {function(element)} moveFocus - function that will determine next
     *    element and move focus to it.
     * @param {function(element)} errorHider - function that is called upon
     *    every button press, so that any associated error can be hidden.
     */
    configureTextInput: function(element,
                                 inputChangeListener,
                                 validator,
                                 moveFocus,
                                 errorHider) {
      element.addEventListener('keydown', function(e) {
        if (e.keyIdentifier == 'Enter') {
          var dataValid = true;
          if (validator)
            dataValid = validator(element);
          if (!dataValid) {
            element.focus();
          } else {
            if (moveFocus)
              moveFocus(element);
          }
          e.stopPropagation();
          return;
        }
        if (errorHider)
          errorHider(element);
        if (inputChangeListener)
          inputChangeListener(element);
      });
      element.addEventListener('keyup', function(e) {
        if (inputChangeListener)
          inputChangeListener(element);
      });
    },

    /**
     * Makes element from template.
     * @param {string} templateId -- template will be looked up within screen
     * by class with name "template-<templateId>".
     * @param {string} elementId -- id for result, uinque within screen. Actual
     *   id will be prefixed with screen name. Use getScreenElement(id) to find
     *   it later.
     */
    makeFromTemplate: function(templateId, elementId) {
      var templateClassName = 'template-' + templateId;
      var templateNode = this.querySelector('.' + templateClassName);
      var screenPrefix = this.name() + '-';
      var result = templateNode.cloneNode(true);
      result.classList.remove(templateClassName);
      result.id = screenPrefix + elementId;
      return result;
    },

    /**
     * @param {string} buttonId -- id of button to be found,
     * @return {Element} button created by makeButton with given buttonId.
     */
    getScreenButton: function(buttonId) {
      var fullId = this.name() + '-' + buttonId + '-button';
      return this.getScreenElement(buttonId + '-button');
    },

    /**
     * @param {string} elementId -- id of element to be found,
     * @return {Element} button created by makeFromTemplate with elementId.
     */
    getScreenElement: function(elementId) {
      var fullId = this.name() + '-' + elementId;
      return $(fullId);
    },

    /**
     * Screen controls.
     * @type {!Array} Array of Buttons.
     */
    get buttons() {
      var links = this.ownerDocument.createElement('div');
      var buttons = this.ownerDocument.createElement('div');
      links.classList.add('controls-links');
      buttons.classList.add('controls-buttons');

      var importLink = this.makeFromTemplate('import-supervised-user-link',
                                             'import-link');
      importLink.hidden = true;
      links.appendChild(importLink);

      var linkElement = importLink.querySelector('.signin-link');
      linkElement.addEventListener('click',
          this.importLinkPressed_.bind(this));

      var createLink = this.makeFromTemplate('create-supervised-user-link',
                                             'create-link');
      createLink.hidden = true;
      links.appendChild(createLink);

      var status = this.makeFromTemplate('status-container', 'status');
      buttons.appendChild(status);

      linkElement = createLink.querySelector('.signin-link');
      linkElement.addEventListener('click',
          this.createLinkPressed_.bind(this));

      buttons.appendChild(this.makeButton(
          'start',
          'supervisedUserCreationFlow',
          this.startButtonPressed_.bind(this),
          ['intro'],
          ['custom-appearance', 'button-fancy', 'button-blue']));

      buttons.appendChild(this.makeButton(
          'prev',
          'supervisedUserCreationFlow',
          this.prevButtonPressed_.bind(this),
          ['manager'],
          []));

      buttons.appendChild(this.makeButton(
          'next',
          'supervisedUserCreationFlow',
          this.nextButtonPressed_.bind(this),
          ['manager', 'username'],
          []));

      buttons.appendChild(this.makeButton(
          'import',
          'supervisedUserCreationFlow',
          this.importButtonPressed_.bind(this),
          ['import', 'import-password'],
          []));

      buttons.appendChild(this.makeButton(
          'gotit',
          'supervisedUserCreationFlow',
          this.gotItButtonPressed_.bind(this),
          ['created'],
          ['custom-appearance', 'button-fancy', 'button-blue']));
      return [links, buttons];
    },

    /**
     * Does sanity check and calls backend with current user name/password pair
     * to authenticate manager. May result in showManagerPasswordError.
     * @private
     */
    validateAndLogInAsManager_: function() {
      var selectedPod = this.managerList_.selectedPod_;
      if (null == selectedPod)
        return;

      var managerId = selectedPod.user.username;
      var managerDisplayId = selectedPod.user.emailAddress;
      var managerPassword = selectedPod.passwordElement.value;
      if (managerPassword.length == 0)
        return;
      if (this.disabled)
        return;
      this.disabled = true;
      this.context_.managerId = managerId;
      this.context_.managerDisplayId = managerDisplayId;
      this.context_.managerName = selectedPod.user.displayName;
      chrome.send('authenticateManagerInSupervisedUserCreationFlow',
          [managerId, managerPassword]);
    },

    /**
     * Does sanity check and calls backend with user display name/password pair
     * to create a user.
     * @private
     */
    validateAndCreateSupervisedUser_: function() {
      var firstPassword = $('supervised-user-creation-password').value;
      var secondPassword =
          $('supervised-user-creation-password-confirm').value;
      var userName = $('supervised-user-creation-name').value;
      if (firstPassword != secondPassword) {
        this.showPasswordError(loadTimeData.getString(
            'createSupervisedUserPasswordMismatchError'));
        return;
      }
      if (this.disabled)
        return;
      this.disabled = true;

      this.context_.supervisedName = userName;
      chrome.send('specifySupervisedUserCreationFlowUserData',
          [userName, firstPassword]);
    },

    /**
     * Does sanity check and calls backend with selected existing supervised
     * user id to import user.
     * @private
     */
    importSupervisedUser_: function() {
      if (this.disabled)
        return;
      if (this.currentPage_ == 'import-password') {
        var firstPassword = this.getScreenElement('password').value;
        var secondPassword = this.getScreenElement('password-confirm').value;
        if (firstPassword != secondPassword) {
          this.showPasswordError(loadTimeData.getString(
              'createSupervisedUserPasswordMismatchError'));
          return;
        }
        var userId = this.context_.importUserId;
        this.disabled = true;
        chrome.send('importSupervisedUserWithPassword',
            [userId, firstPassword]);
        return;
      } else {
        var selectedPod = this.importList_.selectedPod_;
        if (!selectedPod)
          return;
        var user = selectedPod.user;
        var userId = user.id;

        this.context_.importUserId = userId;
        this.context_.supervisedName = user.name;
        this.context_.selectedImageUrl = user.avatarurl;
        if (!user.needPassword) {
          this.disabled = true;
          chrome.send('importSupervisedUser', [userId]);
        } else {
          this.setVisiblePage_('import-password');
        }
      }
    },

    /**
     * Calls backend part to check if current user name is valid/not taken.
     * Results in a call to either supervisedUserNameOk or
     * supervisedUserNameError.
     * @private
     */
    checkUserName_: function() {
      var userName = this.getScreenElement('name').value;

      // Avoid flickering
      if (userName == this.lastIncorrectUserName_ ||
          userName == this.lastVerifiedName_) {
        return;
      }
      if (userName.length > 0) {
        chrome.send('checkSupervisedUserName', [userName]);
      } else {
        this.nameErrorVisible = false;
        this.lastVerifiedName_ = null;
        this.lastIncorrectUserName_ = null;
        this.updateNextButtonForUser_();
      }
    },

    /**
     * Called by backend part in case of successful name validation.
     * @param {string} name - name that was validated.
     */
    supervisedUserNameOk: function(name) {
      this.lastVerifiedName_ = name;
      this.lastIncorrectUserName_ = null;
      if ($('supervised-user-creation-name').value == name)
        this.clearUserNameError_();
      this.updateNextButtonForUser_();
    },

    /**
     * Called by backend part in case of name validation failure.
     * @param {string} name - name that was validated.
     * @param {string} errorText - reason why this name is invalid.
     */
    supervisedUserNameError: function(name, errorText) {
      this.disabled = false;
      this.lastIncorrectUserName_ = name;
      this.lastVerifiedName_ = null;

      var userNameField = $('supervised-user-creation-name');
      if (userNameField.value == this.lastIncorrectUserName_) {
        this.nameErrorVisible = true;
        $('bubble').showTextForElement(
            $('supervised-user-creation-name'),
            errorText,
            cr.ui.Bubble.Attachment.RIGHT,
            12, 4);
        this.setButtonDisabledStatus('next', true);
      }
    },

    supervisedUserSuggestImport: function(name, user_id) {
      this.disabled = false;
      this.lastIncorrectUserName_ = name;
      this.lastVerifiedName_ = null;

      var userNameField = $('supervised-user-creation-name');
      var creationScreen = this;

      if (userNameField.value == this.lastIncorrectUserName_) {
        this.nameErrorVisible = true;
        var link = this.ownerDocument.createElement('div');
        link.innerHTML = loadTimeData.getStringF(
            'importBubbleText',
            '<a class="signin-link" href="#">',
            name,
            '</a>');
        link.querySelector('.signin-link').addEventListener('click',
            function(e) {
              creationScreen.handleSuggestImport_(user_id);
              e.stopPropagation();
            });
        $('bubble').showContentForElement(
            $('supervised-user-creation-name'),
            cr.ui.Bubble.Attachment.RIGHT,
            link,
            12, 4);
        this.setButtonDisabledStatus('next', true);
      }
    },

    /**
     * Clears user name error, if name is no more guaranteed to be invalid.
     * @private
     */
    clearUserNameError_: function() {
      // Avoid flickering
      if ($('supervised-user-creation-name').value ==
              this.lastIncorrectUserName_) {
        return;
      }
      this.nameErrorVisible = false;
    },

    /**
     * Called by backend part in case of password validation failure.
     * @param {string} errorText - reason why this password is invalid.
     */
    showPasswordError: function(errorText) {
      $('bubble').showTextForElement(
          $('supervised-user-creation-password'),
          errorText,
          cr.ui.Bubble.Attachment.RIGHT,
          12, 4);
      $('supervised-user-creation-password').classList.add('password-error');
      $('supervised-user-creation-password').focus();
      this.disabled = false;
      this.setButtonDisabledStatus('next', true);
    },

    /**
     * True if user name error should be displayed.
     * @type {boolean}
     */
    set nameErrorVisible(value) {
      $('supervised-user-creation-name').
          classList.toggle('duplicate-name', value);
      if (!value)
        $('bubble').hide();
    },

    /**
     * Updates state of Continue button after minimal checks.
     * @return {boolean} true, if form seems to be valid.
     * @private
     */
    updateNextButtonForManager_: function() {
      var selectedPod = this.managerList_.selectedPod_;
      canProceed = null != selectedPod &&
                   selectedPod.passwordElement.value.length > 0;

      this.setButtonDisabledStatus('next', !canProceed);
      return canProceed;
    },

    /**
     * Updates state of Continue button after minimal checks.
     * @return {boolean} true, if form seems to be valid.
     * @private
     */
    updateNextButtonForUser_: function() {
      var firstPassword = this.getScreenElement('password').value;
      var secondPassword = this.getScreenElement('password-confirm').value;
      var userName = this.getScreenElement('name').value;

      var passwordOk = (firstPassword.length > 0) &&
          (firstPassword.length == secondPassword.length);

      if (this.currentPage_ == 'import-password') {
        this.setButtonDisabledStatus('import', !passwordOk);
        return passwordOk;
      }
      var imageGrid = this.getScreenElement('image-grid');
      var imageChosen = !(imageGrid.selectionType == 'camera' &&
                          imageGrid.cameraLive);
      var canProceed =
          passwordOk &&
          (userName.length > 0) &&
          this.lastVerifiedName_ &&
          (userName == this.lastVerifiedName_) &&
          imageChosen;

      this.setButtonDisabledStatus('next', !canProceed);
      return canProceed;
    },

    showSelectedManagerPasswordError_: function() {
      var selectedPod = this.managerList_.selectedPod_;
      selectedPod.showPasswordError();
      selectedPod.passwordElement.value = '';
      selectedPod.focusInput();
      this.updateNextButtonForManager_();
    },

    /**
     * Enables one particular subpage and hides the rest.
     * @param {string} visiblePage - name of subpage.
     * @private
     */
    setVisiblePage_: function(visiblePage) {
      this.disabled = false;
      this.updateText_();
      $('bubble').hide();
      if (!this.imagesRequested_) {
        chrome.send('supervisedUserGetImages');
        this.imagesRequested_ = true;
      }
      var pageNames = ['intro',
                       'manager',
                       'username',
                       'import',
                       'error',
                       'created'];
      var pageButtons = {'intro' : 'start',
                         'error' : 'error',
                         'import' : 'import',
                         'import-password' : 'import',
                         'created' : 'gotit'};
      this.hideStatus_();
      var pageToDisplay = visiblePage;
      if (visiblePage == 'import-password')
        pageToDisplay = 'username';

      for (i in pageNames) {
        var pageName = pageNames[i];
        var page = $('supervised-user-creation-' + pageName);
        page.hidden = (pageName != pageToDisplay);
        if (pageName == pageToDisplay)
          $('step-logo').hidden = page.classList.contains('step-no-logo');
      }

      for (i in this.buttonIds) {
        var button = this.getScreenButton(this.buttonIds[i]);
        button.hidden = button.pages.indexOf(visiblePage) < 0;
        button.disabled = false;
      }

      var pagesWithCancel = ['intro', 'manager', 'username', 'import-password',
          'error', 'import'];
      $('login-header-bar').allowCancel =
          pagesWithCancel.indexOf(visiblePage) > -1;
      $('cancel-add-user-button').disabled = false;

      this.getScreenElement('import-link').hidden = true;
      this.getScreenElement('create-link').hidden = true;

      if (pageButtons[visiblePage])
        this.getScreenButton(pageButtons[visiblePage]).focus();

      this.currentPage_ = visiblePage;

      if (visiblePage == 'manager' || visiblePage == 'intro') {
        $('supervised-user-creation-password').classList.remove(
            'password-error');
        if (this.managerList_.pods.length > 0)
          this.managerList_.selectPod(this.managerList_.pods[0]);
        $('login-header-bar').updateUI_();
      }

      if (visiblePage == 'username' || visiblePage == 'import-password') {
        var elements = this.getScreenElement(pageToDisplay).
            querySelectorAll('.hide-on-import');
        for (var i = 0; i < elements.length; i++) {
          elements[i].classList.toggle('hidden-on-import',
              visiblePage == 'import-password');
        }
      }
      if (visiblePage == 'username') {
        var imageGrid = this.getScreenElement('image-grid');
        // select some image.
        var selected = this.imagesData_[
            Math.floor(Math.random() * this.imagesData_.length)];
        this.context_.selectedImageUrl = selected.url;
        imageGrid.selectedItemUrl = selected.url;
        chrome.send('supervisedUserSelectImage',
                    [selected.url, 'default']);
        this.getScreenElement('image-grid').redraw();
        this.checkUserName_();
        this.updateNextButtonForUser_();
        this.getScreenElement('name').focus();
        this.getScreenElement('import-link').hidden =
            this.importList_.pods.length == 0;
      } else if (visiblePage == 'import-password') {
        var imageGrid = this.getScreenElement('image-grid');
        var selected;
        if ('selectedImageUrl' in this.context_) {
          selected = this.context_.selectedImageUrl;
        } else {
          // select some image.
          selected = this.imagesData_[
              Math.floor(Math.random() * this.imagesData_.length)].url;
          chrome.send('supervisedUserSelectImage',
                      [selected, 'default']);
        }
        imageGrid.selectedItemUrl = selected;
        this.getScreenElement('image-grid').redraw();

        this.updateNextButtonForUser_();

        this.getScreenElement('password').focus();
        this.getScreenElement('import-link').hidden = true;
      } else {
        this.getScreenElement('image-grid').stopCamera();
      }
      if (visiblePage == 'import') {
        this.getScreenElement('create-link').hidden = false;
        this.getScreenButton('import').disabled =
            !this.importList_.selectedPod_ ||
            this.importList_.selectedPod_.user.exists;
      }
      $('supervised-user-creation-close-button-item').hidden =
          (visiblePage == 'created');

      chrome.send('currentSupervisedUserPage', [this.currentPage_]);
    },

    setButtonDisabledStatus: function(buttonName, status) {
      var button = $('supervised-user-creation-' + buttonName + '-button');
      button.disabled = status;
    },

    gotItButtonPressed_: function() {
      chrome.send('finishLocalSupervisedUserCreation');
    },

    handleErrorButtonPressed_: function() {
      chrome.send('abortLocalSupervisedUserCreation');
    },

    startButtonPressed_: function() {
      this.setVisiblePage_('manager');
      this.setButtonDisabledStatus('next', true);
    },

    nextButtonPressed_: function() {
      if (this.currentPage_ == 'manager') {
        this.validateAndLogInAsManager_();
        return;
      }
      if (this.currentPage_ == 'username') {
        this.validateAndCreateSupervisedUser_();
      }
    },

    importButtonPressed_: function() {
      this.importSupervisedUser_();
    },

    importLinkPressed_: function() {
      this.setVisiblePage_('import');
    },

    handleSuggestImport_: function(user_id) {
      this.setVisiblePage_('import');
      this.importList_.selectUser(user_id);
    },

    createLinkPressed_: function() {
      this.setVisiblePage_('username');
      this.lastIncorrectUserName_ = null;
      this.lastVerifiedName_ = null;
      this.checkUserName_();
    },

    prevButtonPressed_: function() {
      this.setVisiblePage_('intro');
    },

    showProgress: function(text) {
      var status = this.getScreenElement('status');
      var statusText = status.querySelector('.id-text');
      statusText.textContent = text;
      statusText.classList.remove('error');
      status.querySelector('.id-spinner').hidden = false;
      status.hidden = false;
      this.getScreenElement('import-link').hidden = true;
      this.getScreenElement('create-link').hidden = true;
    },

    showStatusError: function(text) {
      var status = this.getScreenElement('status');
      var statusText = status.querySelector('.id-text');
      statusText.textContent = text;
      statusText.classList.add('error');
      status.querySelector('.id-spinner').hidden = true;
      status.hidden = false;
      this.getScreenElement('import-link').hidden = true;
      this.getScreenElement('create-link').hidden = true;
    },

    hideStatus_: function() {
      var status = this.getScreenElement('status');
      status.hidden = true;
    },

    /**
     * Updates state of login header so that necessary buttons are displayed.
     */
    onBeforeShow: function(data) {
      $('login-header-bar').signinUIState =
          SIGNIN_UI_STATE.SUPERVISED_USER_CREATION_FLOW;
      if (data['managers']) {
        this.loadManagers(data['managers']);
      }
      var imageGrid = this.getScreenElement('image-grid');
      imageGrid.updateAndFocus();
    },

    /**
     * Update state of login header so that necessary buttons are displayed.
     */
    onBeforeHide: function() {
      $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN;
      this.getScreenElement('image-grid').stopCamera();
    },

    /**
     * Returns a control which should receive an initial focus.
     */
    get defaultControl() {
      return $('supervised-user-creation-name');
    },

    /**
     * True if the the screen is disabled (handles no user interaction).
     * @type {boolean}
     */
    disabled_: false,

    get disabled() {
      return this.disabled_;
    },

    set disabled(value) {
      this.disabled_ = value;
      var controls = this.querySelectorAll('button,input');
      for (var i = 0, control; control = controls[i]; ++i) {
        control.disabled = value;
      }
      $('login-header-bar').disabled = value;
      $('cancel-add-user-button').disabled = false;
    },

    /**
     * Called by backend part to propagate list of possible managers.
     * @param {Array} userList - list of users that can be managers.
     */
    loadManagers: function(userList) {
      $('supervised-user-creation-managers-block').hidden = false;
      this.managerList_.clearPods();
      for (var i = 0; i < userList.length; ++i)
        this.managerList_.addPod(userList[i]);
      if (userList.length > 0)
        this.managerList_.selectPod(this.managerList_.pods[0]);
    },

    /**
     * Cancels user creation and drops to user screen (either sign).
     */
    cancel: function() {
      var notSignedInPages = ['intro', 'manager'];
      var postCreationPages = ['created'];
      if (notSignedInPages.indexOf(this.currentPage_) >= 0) {
        chrome.send('hideLocalSupervisedUserCreation');

        // Make sure no manager password is kept:
        this.managerList_.clearPods();

        Oobe.showUserPods();
        return;
      }
      if (postCreationPages.indexOf(this.currentPage_) >= 0) {
        chrome.send('finishLocalSupervisedUserCreation');
        return;
      }
      chrome.send('abortLocalSupervisedUserCreation');
    },

    updateText_: function() {
      var managerDisplayId = this.context_.managerDisplayId;
      this.updateElementText_('intro-alternate-text',
                              'createSupervisedUserIntroAlternateText');
      this.updateElementText_('created-text-1',
                              'createSupervisedUserCreatedText1',
                              this.context_.supervisedName);
      // TODO(antrim): Move wrapping with strong in grd file, and eliminate this
      //call.
      this.updateElementText_('created-text-2',
                              'createSupervisedUserCreatedText2',
                              this.wrapStrong(
                                  loadTimeData.getString('managementURL')),
                                  this.context_.supervisedName);
      this.updateElementText_('created-text-3',
                              'createSupervisedUserCreatedText3',
                              managerDisplayId);
      this.updateElementText_('name-explanation',
                              'createSupervisedUserNameExplanation',
                              managerDisplayId);
    },

    wrapStrong: function(original) {
      if (original == undefined)
        return original;
      return '<strong>' + original + '</strong>';
    },

    updateElementText_: function(localId, templateName) {
      var args = Array.prototype.slice.call(arguments);
      args.shift();
      this.getScreenElement(localId).innerHTML =
          loadTimeData.getStringF.apply(loadTimeData, args);
    },

    showIntroPage: function() {
      $('supervised-user-creation-password').value = '';
      $('supervised-user-creation-password-confirm').value = '';
      $('supervised-user-creation-name').value = '';

      this.lastVerifiedName_ = null;
      this.lastIncorrectUserName_ = null;
      this.passwordErrorVisible = false;
      $('supervised-user-creation-password').classList.remove('password-error');
      this.nameErrorVisible = false;

      this.setVisiblePage_('intro');
    },

    showManagerPage: function() {
      this.setVisiblePage_('manager');
    },

    showUsernamePage: function() {
      this.setVisiblePage_('username');
    },

    showTutorialPage: function() {
      this.setVisiblePage_('created');
    },

    showPage: function(page) {
      this.setVisiblePage_(page);
    },

    showErrorPage: function(errorTitle, errorText, errorButtonText) {
      this.disabled = false;
      $('supervised-user-creation-error-title').innerHTML = errorTitle;
      $('supervised-user-creation-error-text').innerHTML = errorText;
      $('supervised-user-creation-error-button').textContent = errorButtonText;
      this.setVisiblePage_('error');
    },

    showManagerPasswordError: function() {
      this.disabled = false;
      this.showSelectedManagerPasswordError_();
    },

    /*
    TODO(antrim) : this is an explicit code duplications with UserImageScreen.
    It should be removed by issue 251179.
    */
    /**
     * Currently selected user image index (take photo button is with zero
     * index).
     * @type {number}
     */
    selectedUserImage_: -1,
    imagesData: [],

    setDefaultImages: function(imagesData) {
      var imageGrid = this.getScreenElement('image-grid');
      imageGrid.setDefaultImages(imagesData);
      this.imagesData_ = imagesData;
    },


    handleActivate_: function() {
      var imageGrid = this.getScreenElement('image-grid');
      if (imageGrid.selectedItemUrl == ButtonImages.TAKE_PHOTO) {
        this.handleTakePhoto_();
        return;
      }
      this.nextButtonPressed_();
    },

    /**
     * Handles selection change.
     * @param {Event} e Selection change event.
     * @private
     */
    handleSelect_: function(e) {
      var imageGrid = this.getScreenElement('image-grid');
      this.updateNextButtonForUser_();

      $('supervised-user-creation-flip-photo').tabIndex =
          (imageGrid.selectionType == 'camera') ? 0 : -1;
      if (imageGrid.cameraLive || imageGrid.selectionType != 'camera')
        imageGrid.previewElement.classList.remove('phototaken');
      else
        imageGrid.previewElement.classList.add('phototaken');

      if (!imageGrid.cameraLive || imageGrid.selectionType != 'camera') {
        this.context_.selectedImageUrl = imageGrid.selectedItemUrl;
        chrome.send('supervisedUserSelectImage',
                    [imageGrid.selectedItemUrl, imageGrid.selectionType]);
      }
      // Start/stop camera on (de)selection.
      if (!imageGrid.inProgramSelection &&
          imageGrid.selectionType != e.oldSelectionType) {
        if (imageGrid.selectionType == 'camera') {
          // Programmatic selection of camera item is done in
          // startCamera callback where streaming is started by itself.
          imageGrid.startCamera(
              function() {
                // Start capture if camera is still the selected item.
                $('supervised-user-creation-image-preview-img').classList.
                    toggle('animated-transform', true);
                return imageGrid.selectedItem == imageGrid.cameraImage;
              });
        } else {
          $('supervised-user-creation-image-preview-img').classList.toggle(
              'animated-transform', false);
          imageGrid.stopCamera();
        }
      }
    },

    /**
     * Handle camera-photo flip.
     */
    handleFlipPhoto_: function() {
      var imageGrid = this.getScreenElement('image-grid');
      imageGrid.previewElement.classList.add('animation');
      imageGrid.flipPhoto = !imageGrid.flipPhoto;
      var flipMessageId = imageGrid.flipPhoto ?
         'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText';
      announceAccessibleMessage(loadTimeData.getString(flipMessageId));
    },

    /**
     * Handle photo capture from the live camera stream.
     */
    handleTakePhoto_: function(e) {
      this.getScreenElement('image-grid').takePhoto();
      chrome.send('supervisedUserTakePhoto');
    },

    handlePhotoTaken_: function(e) {
      chrome.send('supervisedUserPhotoTaken', [e.dataURL]);
      announceAccessibleMessage(
          loadTimeData.getString('photoCaptureAccessibleText'));
    },

    /**
     * Handle photo updated event.
     * @param {Event} e Event with 'dataURL' property containing a data URL.
     */
    handlePhotoUpdated_: function(e) {
      chrome.send('supervisedUserPhotoTaken', [e.dataURL]);
    },

    /**
     * Handle discarding the captured photo.
     */
    handleDiscardPhoto_: function(e) {
      var imageGrid = this.getScreenElement('image-grid');
      imageGrid.discardPhoto();
      chrome.send('supervisedUserDiscardPhoto');
      announceAccessibleMessage(
          loadTimeData.getString('photoDiscardAccessibleText'));
    },

    setCameraPresent: function(present) {
      this.getScreenElement('image-grid').cameraPresent = present;
    },

    setExistingSupervisedUsers: function(users) {
      var selectedUser = null;
      // Store selected user
      if (this.importList_.selectedPod)
        selectedUser = this.importList_.selectedPod.user.id;

      var userList = users;
      userList.sort(function(a, b) {
        // Put existing users last.
        if (a.exists != b.exists)
          return a.exists ? 1 : -1;
        // Sort rest by name.
        return a.name.localeCompare(b.name, [], {sensitivity: 'base'});
      });

      this.importList_.clearPods();
      var selectedIndex = -1;
      for (var i = 0; i < userList.length; ++i) {
        this.importList_.addPod(userList[i]);
        if (selectedUser == userList[i].id)
          selectedIndex = i;
      }

      if (userList.length == 1)
        this.importList_.selectPod(this.importList_.pods[0]);

      if (selectedIndex >= 0)
        this.importList_.selectPod(this.importList_.pods[selectedIndex]);

      if (this.currentPage_ == 'username')
        this.getScreenElement('import-link').hidden = (userList.length == 0);
    },
  };
});

