/**
 * @archivo mixins/stateful.js
 * @módulo con estado
 * /
import {isEvented} from './evented';
importar * como Obj desde '../utils/obj';

/**
 * Contiene métodos que proporcionan estado a un objeto que se pasa
 * a {@link module:stateful}.
 *
 * @mixin StatefulMixin
 * /
const StatefulMixin = {

  /**
   * Un hash que contiene claves y valores arbitrarios que representan el estado de
   * el objeto.
   *
   * @type {Objeto}
   * /
  estado: {},

  /**
   * Establecer el estado de un objeto mutando su
   * Objeto {@link module:stateful~StatefulMixin.state|state} en su lugar.
   *
   * Módulo @fires: stateful~StatefulMixin#statechanged
   * @param {Objeto|Función} stateUpdates
   * Un nuevo conjunto de propiedades para fusionarse superficialmente en el estado del complemento.
   * Puede ser un objeto simple o una función que devuelve un objeto simple.
   *
   * @return {Objeto|indefinido}
   * Un objeto que contiene cambios que ocurrieron. Si no hay cambios
   * ocurrió, devuelve `indefinido`.
   * /
  setState(estadoActualizaciones) {

    // Admite proporcionar el estado `stateUpdates` como una función.
    if (typeof stateUpdates === 'función') {
      actualizaciones de estado = actualizaciones de estado ();
    }

    dejar cambios;

    Obj.each(stateUpdates, (valor, clave) => {

      // Registrar el cambio si el valor es diferente de lo que está en el
      // estado actual.
      if (este.estado[clave] !== valor) {
        cambios = cambios || {};
        cambios[clave] = {
          de: este.estado[clave],
          valorar
        };
      }

      este.estado[clave] = valor;
    });

    // Activar "cambio de estado" solo si hubo cambios Y tenemos un activador
    // función. Esto nos permite no requerir que el objeto de destino sea un
    // objeto con eventos.
    si (cambios && isEvented(esto)) {

      /**
       * Un evento desencadenado en un objeto que es a la vez
       * {@módulo de enlace:con estado|con estado} y {@módulo de enlace:con eventos|con eventos}
       * indicando que su estado ha cambiado.
       *
       * Módulo @event:con estado~ConestadoMixin#estadocambiado
       * @type {Objeto}
       * @propiedad {Objeto} cambia
       * Un hash que contiene las propiedades que se cambiaron y
       * los valores se cambiaron `desde` y `hasta`.
       * /
      este.disparador({
        cambios,
        tipo: 'estado cambiado'
      });
    }

    devolver cambios;
  }
};

/**
 * Aplica {@link module:stateful~StatefulMixin|StatefulMixin} a un objetivo
 * objeto.
 *
 * Si el objeto de destino es {@link module:evented|evented} y tiene un
 * método `handleStateChanged`, ese método se vinculará automáticamente al
 * Evento `statechanged` sobre sí mismo.
 *
 * @param {Objeto} objetivo
 * El objeto que se va a convertir en estado.
 *
 * @param {Objeto} [estado predeterminado]
 * Un conjunto predeterminado de propiedades para completar el objeto con estado nuevo
 * Propiedad `estado`.
 *
 * @return {Objeto}
 * Devuelve el `objetivo`.
 * /
función con estado (objetivo, estado predeterminado) {
  Obj.assign(objetivo, StatefulMixin);

  // Esto sucede después de la mezcla porque necesitamos reemplazar el `estado`
  // añadido en ese paso.
  target.state = Obj.assign({}, target.state, defaultState);

  // Vincula automáticamente el método `handleStateChanged` del objeto de destino si existe.
  if (typeof target.handleStateChanged === 'función' && isEvented(objetivo)) {
    target.on('estadocambiado', target.handleStateChanged);
  }

  objetivo de retorno;
}

exportar por defecto con estado;