Show:
/**
 * @module proact-properties
 */

/**
 * <p>
 *  Constructs a `ProAct.AutoProperty`.
 *  The properties are simple {{#crossLink "ProAct.Actor"}}{{/crossLink}}s with state.
 *  The auto-computed or functional property has a state of a function return value.
 * </p>
 * <p>
 *  Auto-computed properties are functions which are turned
 *  to {{#crossLink "ProAct.Property"}}{{/crossLink}}s by a {{#crossLink "ProAct.ObjectCore"}}{{/crossLink}}.
 * </p>
 * <p>
 *  If these functions are reading another fields of ProAct.js objects,
 *  they authomatically become dependent on them.
 * </p>
 * <p>
 *  For example:
 *  <pre>
 *    var obj = {
 *      a: 1,
 *      b: 2,
 *      c: function () {
 *        return this.a - this.b;
 *      }
 *    };
 *  </pre>
 *  If this object - <i>obj</i> is turned to a reactive ProAct.js object,
 *  it becomes a simple object with three fields:
 *  <pre>
 *    {
 *      a: 1,
 *      b: 2,
 *      c: -1
 *    }
 *  </pre>
 *  But now <i>c</i> is dependent on <i>a</i> and <i>b</i>,
 *  so if <i>a</i> is set to <b>4</b>, <i>obj</i> becomes:
 *  <pre>
 *    {
 *      a: 1,
 *      b: 2,
 *      c: 2
 *    }
 *  </pre>
 * </p>
 * <p>
 *  The logic is the following:
 *  <ul>
 *    <li>The property is initialized to be lazy, so its state is {{#crossLink "ProAct.States/init:property"}}{{/crossLink}}</li>
 *    <li>
 *      On its first read, the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} is set to the listener of the property,
 *      so all the properties read in the function body become observed by it.
 *      The value of the property is computed using the original function of the field.
 *    </li>
 *    <li>On this first read the state of the property is updated to {{#crossLink "ProAct.States/ready:property"}}{{/crossLink}}.</li>
 *    <li>On its following reads it is a simple value, computed from the first read. No re-computations on get.</li>
 *    <li>If a property, this auto-computed property depends changes, the value of <i>this</i> ProAct.AutoProperty is recomputed.</li>
 *    <li>Setting the property can be implemented easy, because on set, the original function of the property is called with the new value.</li>
 *  </ul>
 * </p>
 * <p>
 *  `ProAct.AutoProperty` can be dependant on another `ProAct.AutoProperty`.
 * </p>
 * <p>
 *  `ProAct.AutoProperty` is part of the proact-properties module of ProAct.js.
 * </p>
 *
 * @class ProAct.AutoProperty
 * @extends ProAct.Property
 * @constructor
 * @param {String} queueName
 *      The name of the queue all the updates should be pushed to.
 *      <p>
 *        If this parameter is null/undefined the default queue of
 *        {{#crossLink "ProAct/flow:property"}}{{/crossLink}} is used.
 *      </p>
 *      <p>
 *        If this parameter is not a string it is used as the
 *        <i>proObject</i>.
 *      </p>
 * @param {Object} proObject
 *      A plain JavaScript object, holding a field, this property will represent.
 * @param {String} property
 *      The name of the field of the object, this property should represent.
 */
function AutoProperty (queueName, proObject, property) {
  if (queueName && !P.U.isString(queueName)) {
    property = proObject;
    proObject = queueName;
    queueName = null;
  }

  this.func = proObject[property];

  var self = this,
      getter = function () {
        self.addCaller();
        var oldCaller = P.currentCaller,
            get = P.P.defaultGetter(self),
            set = P.P.defaultSetter(self, function (newVal) {
              return self.func.call(self.proObject, newVal);
            }),
            args = arguments,
            autoFunction;

        P.currentCaller = self.makeListener();

        autoFunction = function () {
          self.val = self.func.apply(self.proObject, args);
        };
        P.flow.run(function () {
          P.flow.pushOnce(autoFunction);
        });

        P.currentCaller = oldCaller;

        P.P.defineProp(self.proObject, self.property, get, set);

        self.state = P.States.ready;

        self.val = P.Actor.transform(self, self.val);
        return self.val;
      };

  P.P.call(this, queueName, proObject, property, getter, function () {});
}
ProAct.AutoProperty = P.FP = AutoProperty;

ProAct.AutoProperty.prototype = P.U.ex(Object.create(P.P.prototype), {

  /**
   * Reference to the constructor of this object.
   *
   * @property constructor
   * @type ProAct.AutoProperty
   * @final
   * @for ProAct.AutoProperty
   */
  constructor: ProAct.AutoProperty,

  /**
   * Retrieves the {{#crossLink "ProAct.Property.Types"}}{{/crossLink}} value of <i>this</i> property.
   * <p>
   *  For instances of the `ProAct.AutoProperty` class, it is
   *  {{#crossLink "ProAct.Property.Types/auto:property"}}{{/crossLink}}.
   * </p>
   *
   * @for ProAct.AutoProperty
   * @instance
   * @method type
   * @return {Number}
   *      The right type of the property.
   */
  type: function () {
    return P.P.Types.auto;
  },

  /**
   * Creates the <i>listener</i> of this `ProAct.AutoProperty`.
   * <p>
   *  This listener turns the observable in a observer.
   * </p>
   * <p>
   *  The listener for `ProAct.AutoProperty` is an object defining the <i>call</i> method.
   * </p>
   * <p>
   *  It has a <i>property</i> field set to <i>this</i>.
   * </p>
   * <p>
   *  On value changes the <i><this</i> value is set to the value computed by the original function,
   *  using the {{#crossLink "ProAct.Actor/transform:method"}}{{/crossLink}} to transform it.
   * </p>
   *
   * @for ProAct.AutoProperty
   * @protected
   * @instance
   * @method makeListener
   * @return {Object}
   *      The <i>listener of this ProAct.AutoProperty</i>.
   */
  makeListener: function () {
    if (!this.listener) {
      var self = this;

      this.listener = {
        property: self,
        queueName: self.queueName,
        call: function () {
          self.oldVal = self.val;
          self.val = P.Actor.transform(self, self.func.call(self.proObject));
        }
      };
    }

    return this.listener;
  },

  /**
   * Called automatically after initialization of this property.
   * <p>
   *  For `ProAct.AutoProperty` it does nothing -
   *  the real initialization is lazy and is performed on the first read of <i>this</i>.
   * </p>
   *
   * @for ProAct.AutoProperty
   * @protected
   * @instance
   * @method afterInit
   */
  afterInit: function () {}
});