/**
 * @file clickable-component.js
 */
import Component from './component' ;
import * as Dom from './utils/dom.js' ;
import log from './utils/log.js' ;
import {assign} from './utils/obj' ;
import keycode from 'keycode' ;

/**
 * Composant cliquable ou actionnable au clavier, mais qui n'est pas un
 * bouton HTML natif.
 *
 * @extends Component
 */
class ClickableComponent extends Component {

  /**
   * Crée une instance de cette classe.
   *
   * @param {Player} player
   *         Le `Player` auquel cette classe doit être attachée.
   *
   * @param {Objet} [options]
   *         Le magasin clé/valeur des options des composants.
   *
   * @param {function} [options.clickHandler]
   *         La fonction à appeler lorsque le bouton est cliqué / activé
   *
   * @param {string} [options.controlText]
   *         Texte à placer sur le bouton
   *
   * @param {string} [options.className]
   *         Une classe ou une liste de classes séparées par des espaces pour ajouter le composant
   *
   */
  constructor(player, options) {

    super(player, options) ;

    if (this.options_.controlText) {
      this.controlText(this.options_.controlText) ;
    }

    this.handleMouseOver_ = (e) => this.handleMouseOver(e) ;
    this.handleMouseOut_ = (e) => this.handleMouseOut(e) ;
    this.handleClick_ = (e) => this.handleClick(e) ;
    this.handleKeyDown_ = (e) => this.handleKeyDown(e) ;

    this.emitTapEvents() ;

    this.enable() ;
  }

  /**
   * Créer l'élément DOM `ClickableComponent`s.
   *
   * @param {string} [tag=div]
   *        Le type de nœud de l'élément.
   *
   * @param {Objet} [props={}]
   *        Un objet de propriétés à définir sur l'élément.
   *
   * @param {Objet} [attributes={}]
   *        Un objet d'attributs à définir sur l'élément.
   *
   * @return {Element}
   *         L'élément qui est créé.
   */
  createEl(tag = 'div', props = {}, attributes = {}) {
    props = assign({
      className : this.buildCSSClass(),
      tabIndex : 0
    }, props) ;

    if (tag === 'button') {
      log.error(`La création d'un ClickableComponent avec un élément HTML de ${tag} n'est pas prise en charge ; utilisez plutôt un Button.`) ;
    }

    // Ajouter des attributs ARIA pour les éléments cliquables qui ne sont pas des boutons HTML natifs
    attributs = assign({
      rôle : "button" (bouton)
    }, attributs) ;

    this.tabIndex_ = props.tabIndex ;

    const el = Dom.createEl(tag, props, attributes) ;

    el.appendChild(Dom.createEl('span', {
      className : 'vjs-icon-placeholder'
    }, {
      aria-hidden" : vrai
    })) ;

    this.createControlTextEl(el) ;

    return el ;
  }

  dispose() {
    // supprimer controlTextEl_ lors de l'élimination
    this.controlTextEl_ = null ;

    super.dispose() ;
  }

  /**
   * Créer un élément de contrôle textuel sur ce `ClickableComponent`
   *
   * @param {Element} [el]
   *        Élément parent du texte de contrôle.
   *
   * @return {Element}
   *         L'élément de texte du contrôle qui est créé.
   */
  createControlTextEl(el) {
    this.controlTextEl_ = Dom.createEl('span', {
      className : 'vjs-control-text'
    }, {
      // indique à l'utilisateur du lecteur d'écran que le texte de l'élément peut être modifié
      aria-live" : "poli
    }) ;

    if (el) {
      el.appendChild(this.controlTextEl_) ;
    }

    this.controlText(this.controlText_, el) ;

    return this.controlTextEl_ ;
  }

  /**
   * Obtient ou définit le texte de localisation à utiliser pour les contrôles du `ClickableComponent`.
   *
   * @param {string} [texte]
   *        Texte de contrôle pour l'élément.
   *
   * @param {Element} [el=this.el()]
   *        Élément sur lequel le titre doit être placé.
   *
   * @return {string}
   *         - Le texte du contrôle lors de l'obtention de
   */
  controlText(text, el = this.el()) {
    if (text === undefined) {
      return this.controlText_ || 'Texte nécessaire' ;
    }

    const localizedText = this.localize(text) ;

    this.controlText_ = texte ;
    Dom.textContent(this.controlTextEl_, localizedText) ;
    if (!this.nonIconControl && !this.player_.options_.noUITitleAttributes) {
      // Définir l'attribut title si seule une icône est affichée
      el.setAttribute('title', localizedText) ;
    }
  }

  /**
   * Construit le DOM par défaut `className`.
   *
   * @return {string}
   *         Le `nom de classe` du DOM pour cet objet.
   */
  buildCSSClass() {
    return `vjs-control vjs-button ${super.buildCSSClass()}` ;
  }

  /**
   * Activer ce `ClickableComponent` (composant cliquable)
   */
  enable() {
    if (!this.enabled_) {
      this.enabled_ = true ;
      this.removeClass('vjs-disabled') ;
      this.el_.setAttribute('aria-disabled', 'false') ;
      if (typeof this.tabIndex_ !== 'undefined') {
        this.el_.setAttribute('tabIndex', this.tabIndex_) ;
      }
      this.on(['tap', 'click'], this.handleClick_) ;
      this.on('keydown', this.handleKeyDown_) ;
    }
  }

  /**
   * Désactiver ce `ClickableComponent` (composant cliquable)
   */
  disable() {
    this.enabled_ = false ;
    this.addClass('vjs-disabled') ;
    this.el_.setAttribute('aria-disabled', 'true') ;
    if (typeof this.tabIndex_ !== 'undefined') {
      this.el_.removeAttribute('tabIndex') ;
    }
    this.off('mouseover', this.handleMouseOver_) ;
    this.off('mouseout', this.handleMouseOut_) ;
    this.off(['tap', 'click'], this.handleClick_) ;
    this.off('keydown', this.handleKeyDown_) ;
  }

  /**
   * Gère le changement de langue dans ClickableComponent pour le lecteur dans les composants
   *
   *
   */
  handleLanguagechange() {
    this.controlText(this.controlText_) ;
  }

  /**
   * Gestionnaire d'événement appelé lorsqu'un `ClickableComponent` reçoit une commande
   * événement `click` ou `tap`.
   *
   * @param {EventTarget~Event} event
   *        L'événement `tap` ou `click` qui a provoqué l'appel de cette fonction.
   *
   * @listens tap
   * @listens click
   * @abstract
   */
  handleClick(event) {
    if (this.options_.clickHandler) {
      this.options_.clickHandler.call(this, arguments) ;
    }
  }

  /**
   * Gestionnaire d'événement appelé lorsqu'un `ClickableComponent` reçoit une commande
   * événement `keydown`.
   *
   * Par défaut, si la touche est Espace ou Entrée, elle déclenche un événement `click`.
   *
   * @param {EventTarget~Event} event
   *        L'événement `keydown` qui a provoqué l'appel de cette fonction.
   *
   * @listens keydown
   */
  handleKeyDown(event) {

    // Prendre en charge l'opération de la touche Espace ou Entrée pour déclencher un événement de clic. En outre,
    // empêche l'événement de se propager dans le DOM et de déclencher
    // Raccourcis clavier du joueur.
    if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
      event.preventDefault() ;
      event.stopPropagation() ;
      this.trigger('click') ;
    } else {

      // Transmettre la gestion des pressions de touches pour les touches non prises en charge
      super.handleKeyDown(event) ;
    }
  }
}

Component.registerComponent('ClickableComponent', ClickableComponent) ;
export default ClickableComponent ;