text: /*
      This file is part of vnt.js.
  
      vnt.js is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      vnt.js is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.
  
      You should have received a copy of the GNU Lesser General Public License
      along with vnt.js.  If not, see <http://www.gnu.org/licenses/>.
  */
  /**
   * @file event.js
   * @author Marek Kotewicz <marek@ethdev.com>
   * @date 2014
   */
  
  var utils = require('../utils/utils');
  var coder = require('../types/coder');
  var formatters = require('./formatters');
  var sha3 = require('../utils/sha3');
  var Filter = require('./filter');
  var watches = require('./methods/watches');
  
  /**
   * This prototype should be used to create event filters
   */
  var Event = function (requestManager, json, address) {
      this._requestManager = requestManager;
      this._params = json.inputs;
      this._name = utils.transformToFullName(json);
      this._address = address;
      this._anonymous = json.anonymous;
  };
  
  /**
   * Should be used to get filtered param types
   *
   * @method types
   * @param {Bool} decide if returned typed should be indexed
   * @return {Array} array of types
   */
  Event.prototype.types = function (indexed) {
      return this._params.filter(function (i) {
          return i.indexed === indexed;
      }).map(function (i) {
          return i.type;
      });
  };
  
  /**
   * Should be used to get event display name
   *
   * @method displayName
   * @return {String} event display name
   */
  Event.prototype.displayName = function () {
      return utils.extractDisplayName(this._name);
  };
  
  /**
   * Should be used to get event type name
   *
   * @method typeName
   * @return {String} event type name
   */
  Event.prototype.typeName = function () {
      return utils.extractTypeName(this._name);
  };
  
  /**
   * Should be used to get event signature
   *
   * @method signature
   * @return {String} event signature
   */
  Event.prototype.signature = function () {
      return sha3(this._name);
  };
  
  /**
   * Should be used to encode indexed params and options to one final object
   *
   * @method encode
   * @param {Object} indexed
   * @param {Object} options
   * @return {Object} everything combined together and encoded
   */
  Event.prototype.encode = function (indexed, options) {
      indexed = indexed || {};
      options = options || {};
      var result = {};
  
      ['fromBlock', 'toBlock'].filter(function (f) {
          return options[f] !== undefined;
      }).forEach(function (f) {
          result[f] = formatters.inputBlockNumberFormatter(options[f]);
      });
  
      result.topics = [];
  
      result.address = this._address;
      if (!this._anonymous) {
          result.topics.push('0x' + this.signature());
      }
  
      var indexedTopics = this._params.filter(function (i) {
          return i.indexed === true;
      }).map(function (i) {
          var value = indexed[i.name];
          if (value === undefined || value === null) {
              return null;
          }
  
          if (utils.isArray(value)) {
              return value.map(function (v) {
                  return '0x' + coder.encodeParam(i.type, v, true);
              });
          }
          return '0x' + coder.encodeParam(i.type, value, true);
      });
  
      result.topics = result.topics.concat(indexedTopics);
  
      return result;
  };
  
  /**
   * Should be used to decode indexed params and options
   *
   * @method decode
   * @param {Object} data
   * @return {Object} result object with decoded indexed && not indexed params
   */
  Event.prototype.decode = function (data) {
  
      data.data = data.data || '';
      data.topics = data.topics || [];
  
  
      var argTopics = this._anonymous ? data.topics : data.topics.slice(1);
      var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join("");
      var indexedParams = coder.decodeParams(this.types(true), indexedData, true);
  
      var notIndexedData = data.data.slice(2);
      var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData);
  
      var result = formatters.outputLogFormatter(data);
      result.event = this.displayName();
      result.address = data.address;
  
      result.args = this._params.reduce(function (acc, current) {
          acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift();
          return acc;
      }, {});
  
      delete result.data;
      delete result.topics;
  
      return result;
  };
  
  /**
   * Should be used to create new filter object from event
   *
   * @method execute
   * @param {Object} indexed
   * @param {Object} options
   * @return {Object} filter object
   */
  Event.prototype.execute = function (indexed, options, callback) {
  
      if (utils.isFunction(arguments[arguments.length - 1])) {
          callback = arguments[arguments.length - 1];
          if(arguments.length === 2){
              options = arguments[0];
              indxed = {}
          } else if(arguments.length === 1) {
              options = null;
              indexed = {};
          }
      } else {
          if(arguments.length === 2){
              options = arguments[1];
              indxed = arguments[0];
          } else if(arguments.length === 1) {
              options = arguments[0];
              indexed = {};
          } else {
              options = null;
              indexed = {};
          }
      }
  
      var o = this.encode(indexed, options);
      var formatter = this.decode.bind(this);
      return new Filter(o, 'vnt', this._requestManager, watches.vnt(), formatter, callback);
  };
  
  /**
   * Should be used to attach event to contract object
   *
   * @method attachToContract
   * @param {Contract}
   */
  Event.prototype.attachToContract = function (contract) {
      var execute = this.execute.bind(this);
      var displayName = this.displayName();
      if (!contract[displayName]) {
          contract[displayName] = execute;
      }
      contract[displayName][this.typeName()] = this.execute.bind(this, contract);
  };
  
  module.exports = Event;
  