'use strict';

/* jshint ignore:start */
/**
 * This code was generated by
 * \ / _    _  _|   _  _
 *  | (_)\/(_)(_|\/| |(/_  v1.0.0
 *       /       /
 */
/* jshint ignore:end */

var Q = require('q');  /* jshint ignore:line */
var _ = require('lodash');  /* jshint ignore:line */
var util = require('util');  /* jshint ignore:line */
var EventList = require('./call/event').EventList;
var FeedbackList = require('./call/feedback').FeedbackList;
var FeedbackSummaryList = require('./call/feedbackSummary').FeedbackSummaryList;
var NotificationList = require('./call/notification').NotificationList;
var Page = require('../../../../base/Page');  /* jshint ignore:line */
var PaymentList = require('./call/payment').PaymentList;
var RecordingList = require('./call/recording').RecordingList;
var SiprecList = require('./call/siprec').SiprecList;
var StreamList = require('./call/stream').StreamList;
var deserialize = require(
    '../../../../base/deserialize');  /* jshint ignore:line */
var serialize = require('../../../../base/serialize');  /* jshint ignore:line */
var values = require('../../../../base/values');  /* jshint ignore:line */

var CallList;
var CallPage;
var CallInstance;
var CallContext;

/* jshint ignore:start */
/**
 * Initialize the CallList
 *
 * @constructor Twilio.Api.V2010.AccountContext.CallList
 *
 * @param {Twilio.Api.V2010} version - Version of the resource
 * @param {string} accountSid - The SID of the Account that created this resource
 */
/* jshint ignore:end */
CallList = function CallList(version, accountSid) {
  /* jshint ignore:start */
  /**
   * @function calls
   * @memberof Twilio.Api.V2010.AccountContext#
   *
   * @param {string} sid - sid of instance
   *
   * @returns {Twilio.Api.V2010.AccountContext.CallContext}
   */
  /* jshint ignore:end */
  function CallListInstance(sid) {
    return CallListInstance.get(sid);
  }

  CallListInstance._version = version;
  // Path Solution
  CallListInstance._solution = {accountSid: accountSid};
  CallListInstance._uri = `/Accounts/${accountSid}/Calls.json`;

  // Components
  CallListInstance._feedbackSummaries = undefined;

  /* jshint ignore:start */
  /**
   * create a CallInstance
   *
   * @function create
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @param {object} opts - Options for request
   * @param {string} opts.to -
   *          Phone number, SIP address, or client identifier to call
   * @param {string} opts.from - Twilio number from which to originate the call
   * @param {string} [opts.method] - HTTP method to use to fetch TwiML
   * @param {string} [opts.fallbackUrl] - Fallback URL in case of error
   * @param {string} [opts.fallbackMethod] - HTTP Method to use with fallback_url
   * @param {string} [opts.statusCallback] -
   *          The URL we should call to send status information to your application
   * @param {string|list} [opts.statusCallbackEvent] -
   *          The call progress events that we send to the `status_callback` URL.
   * @param {string} [opts.statusCallbackMethod] -
   *          HTTP Method to use with status_callback
   * @param {string} [opts.sendDigits] -
   *          The digits to dial after connecting to the number
   * @param {number} [opts.timeout] - Number of seconds to wait for an answer
   * @param {boolean} [opts.record] - Whether to record the call
   * @param {string} [opts.recordingChannels] -
   *          The number of channels in the final recording
   * @param {string} [opts.recordingStatusCallback] -
   *          The URL that we call when the recording is available to be accessed
   * @param {string} [opts.recordingStatusCallbackMethod] -
   *          The HTTP method we should use when calling the `recording_status_callback` URL
   * @param {string} [opts.sipAuthUsername] -
   *          The username used to authenticate the caller making a SIP call
   * @param {string} [opts.sipAuthPassword] -
   *          The password required to authenticate the user account specified in `sip_auth_username`.
   * @param {string} [opts.machineDetection] -
   *          Enable machine detection or end of greeting detection
   * @param {number} [opts.machineDetectionTimeout] -
   *          Number of seconds to wait for machine detection
   * @param {string|list} [opts.recordingStatusCallbackEvent] -
   *          The recording status events that will trigger calls to the URL specified in `recording_status_callback`
   * @param {string} [opts.trim] -
   *          Set this parameter to control trimming of silence on the recording.
   * @param {string} [opts.callerId] -
   *          The phone number, SIP address, or Client identifier that made this call. Phone numbers are in E.164 format (e.g., +16175551212). SIP addresses are formatted as `name@company.com`.
   * @param {number} [opts.machineDetectionSpeechThreshold] -
   *          Number of milliseconds for measuring stick for the length of the speech activity
   * @param {number} [opts.machineDetectionSpeechEndThreshold] -
   *          Number of milliseconds of silence after speech activity
   * @param {number} [opts.machineDetectionSilenceTimeout] -
   *          Number of milliseconds of initial silence
   * @param {string} [opts.asyncAmd] - Enable asynchronous AMD
   * @param {string} [opts.asyncAmdStatusCallback] -
   *          The URL we should call to send amd status information to your application
   * @param {string} [opts.asyncAmdStatusCallbackMethod] -
   *          HTTP Method to use with async_amd_status_callback
   * @param {string} [opts.byoc] - BYOC trunk SID (Beta)
   * @param {string} [opts.callReason] - Reason for the call (Branded Calls Beta)
   * @param {string} [opts.callToken] -
   *          A token string needed to invoke a forwarded call with a CallerId recieved on a previous incoming call
   * @param {string} [opts.recordingTrack] - Which track(s) to record
   * @param {number} [opts.timeLimit] - The maximum duration of the call in seconds.
   * @param {string} [opts.url] - The absolute URL that returns TwiML for this call
   * @param {string} [opts.twiml] - TwiML instructions for the call
   * @param {string} [opts.applicationSid] -
   *          The SID of the Application resource that will handle the call
   * @param {function} [callback] - Callback to handle processed record
   *
   * @returns {Promise} Resolves to processed CallInstance
   */
  /* jshint ignore:end */
  CallListInstance.create = function create(opts, callback) {
    if (_.isUndefined(opts)) {
      throw new Error('Required parameter "opts" missing.');
    }
    if (_.isUndefined(opts['to'])) {
      throw new Error('Required parameter "opts[\'to\']" missing.');
    }
    if (_.isUndefined(opts['from'])) {
      throw new Error('Required parameter "opts[\'from\']" missing.');
    }

    var deferred = Q.defer();
    var data = values.of({
      'To': _.get(opts, 'to'),
      'From': _.get(opts, 'from'),
      'Url': _.get(opts, 'url'),
      'Twiml': _.get(opts, 'twiml'),
      'ApplicationSid': _.get(opts, 'applicationSid'),
      'Method': _.get(opts, 'method'),
      'FallbackUrl': _.get(opts, 'fallbackUrl'),
      'FallbackMethod': _.get(opts, 'fallbackMethod'),
      'StatusCallback': _.get(opts, 'statusCallback'),
      'StatusCallbackEvent': serialize.map(_.get(opts, 'statusCallbackEvent'), function(e) { return e; }),
      'StatusCallbackMethod': _.get(opts, 'statusCallbackMethod'),
      'SendDigits': _.get(opts, 'sendDigits'),
      'Timeout': _.get(opts, 'timeout'),
      'Record': serialize.bool(_.get(opts, 'record')),
      'RecordingChannels': _.get(opts, 'recordingChannels'),
      'RecordingStatusCallback': _.get(opts, 'recordingStatusCallback'),
      'RecordingStatusCallbackMethod': _.get(opts, 'recordingStatusCallbackMethod'),
      'SipAuthUsername': _.get(opts, 'sipAuthUsername'),
      'SipAuthPassword': _.get(opts, 'sipAuthPassword'),
      'MachineDetection': _.get(opts, 'machineDetection'),
      'MachineDetectionTimeout': _.get(opts, 'machineDetectionTimeout'),
      'RecordingStatusCallbackEvent': serialize.map(_.get(opts, 'recordingStatusCallbackEvent'), function(e) { return e; }),
      'Trim': _.get(opts, 'trim'),
      'CallerId': _.get(opts, 'callerId'),
      'MachineDetectionSpeechThreshold': _.get(opts, 'machineDetectionSpeechThreshold'),
      'MachineDetectionSpeechEndThreshold': _.get(opts, 'machineDetectionSpeechEndThreshold'),
      'MachineDetectionSilenceTimeout': _.get(opts, 'machineDetectionSilenceTimeout'),
      'AsyncAmd': _.get(opts, 'asyncAmd'),
      'AsyncAmdStatusCallback': _.get(opts, 'asyncAmdStatusCallback'),
      'AsyncAmdStatusCallbackMethod': _.get(opts, 'asyncAmdStatusCallbackMethod'),
      'Byoc': _.get(opts, 'byoc'),
      'CallReason': _.get(opts, 'callReason'),
      'CallToken': _.get(opts, 'callToken'),
      'RecordingTrack': _.get(opts, 'recordingTrack'),
      'TimeLimit': _.get(opts, 'timeLimit')
    });

    var promise = this._version.create({uri: this._uri, method: 'POST', data: data});

    promise = promise.then(function(payload) {
      deferred.resolve(new CallInstance(
        this._version,
        payload,
        this._solution.accountSid,
        this._solution.sid
      ));
    }.bind(this));

    promise.catch(function(error) {
      deferred.reject(error);
    });

    if (_.isFunction(callback)) {
      deferred.promise.nodeify(callback);
    }

    return deferred.promise;
  };

  /* jshint ignore:start */
  /**
   * Streams CallInstance records from the API.
   *
   * This operation lazily loads records as efficiently as possible until the limit
   * is reached.
   *
   * The results are passed into the callback function, so this operation is memory
   * efficient.
   *
   * If a function is passed as the first argument, it will be used as the callback
   * function.
   *
   * @function each
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @param {object} [opts] - Options for request
   * @param {string} [opts.to] -
   *          Phone number or Client identifier of calls to include
   * @param {string} [opts.from] -
   *          Phone number or Client identifier to filter `from` on
   * @param {string} [opts.parentCallSid] - Parent call SID to filter on
   * @param {call.status} [opts.status] - The status of the resources to read
   * @param {Date} [opts.startTimeBefore] -
   *          Only include calls that started on this date
   * @param {Date} [opts.startTime] - Only include calls that started on this date
   * @param {Date} [opts.startTimeAfter] -
   *          Only include calls that started on this date
   * @param {Date} [opts.endTimeBefore] - Only include calls that ended on this date
   * @param {Date} [opts.endTime] - Only include calls that ended on this date
   * @param {Date} [opts.endTimeAfter] - Only include calls that ended on this date
   * @param {number} [opts.limit] -
   *         Upper limit for the number of records to return.
   *         each() guarantees never to return more than limit.
   *         Default is no limit
   * @param {number} [opts.pageSize] -
   *         Number of records to fetch per request,
   *         when not set will use the default value of 50 records.
   *         If no pageSize is defined but a limit is defined,
   *         each() will attempt to read the limit with the most efficient
   *         page size, i.e. min(limit, 1000)
   * @param {Function} [opts.callback] -
   *         Function to process each record. If this and a positional
   *         callback are passed, this one will be used
   * @param {Function} [opts.done] -
   *          Function to be called upon completion of streaming
   * @param {Function} [callback] - Function to process each record
   */
  /* jshint ignore:end */
  CallListInstance.each = function each(opts, callback) {
    if (_.isFunction(opts)) {
      callback = opts;
      opts = {};
    }
    opts = opts || {};
    if (opts.callback) {
      callback = opts.callback;
    }
    if (_.isUndefined(callback)) {
      throw new Error('Callback function must be provided');
    }

    var done = false;
    var currentPage = 1;
    var currentResource = 0;
    var limits = this._version.readLimits({
      limit: opts.limit,
      pageSize: opts.pageSize
    });

    function onComplete(error) {
      done = true;
      if (_.isFunction(opts.done)) {
        opts.done(error);
      }
    }

    function fetchNextPage(fn) {
      var promise = fn();
      if (_.isUndefined(promise)) {
        onComplete();
        return;
      }

      promise.then(function(page) {
        _.each(page.instances, function(instance) {
          if (done || (!_.isUndefined(opts.limit) && currentResource >= opts.limit)) {
            done = true;
            return false;
          }

          currentResource++;
          callback(instance, onComplete);
        });

        if (!done) {
          currentPage++;
          fetchNextPage(_.bind(page.nextPage, page));
        } else {
          onComplete();
        }
      });

      promise.catch(onComplete);
    }

    fetchNextPage(_.bind(this.page, this, _.merge(opts, limits)));
  };

  /* jshint ignore:start */
  /**
   * Lists CallInstance records from the API as a list.
   *
   * If a function is passed as the first argument, it will be used as the callback
   * function.
   *
   * @function list
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @param {object} [opts] - Options for request
   * @param {string} [opts.to] -
   *          Phone number or Client identifier of calls to include
   * @param {string} [opts.from] -
   *          Phone number or Client identifier to filter `from` on
   * @param {string} [opts.parentCallSid] - Parent call SID to filter on
   * @param {call.status} [opts.status] - The status of the resources to read
   * @param {Date} [opts.startTimeBefore] -
   *          Only include calls that started on this date
   * @param {Date} [opts.startTime] - Only include calls that started on this date
   * @param {Date} [opts.startTimeAfter] -
   *          Only include calls that started on this date
   * @param {Date} [opts.endTimeBefore] - Only include calls that ended on this date
   * @param {Date} [opts.endTime] - Only include calls that ended on this date
   * @param {Date} [opts.endTimeAfter] - Only include calls that ended on this date
   * @param {number} [opts.limit] -
   *         Upper limit for the number of records to return.
   *         list() guarantees never to return more than limit.
   *         Default is no limit
   * @param {number} [opts.pageSize] -
   *         Number of records to fetch per request,
   *         when not set will use the default value of 50 records.
   *         If no page_size is defined but a limit is defined,
   *         list() will attempt to read the limit with the most
   *         efficient page size, i.e. min(limit, 1000)
   * @param {function} [callback] - Callback to handle list of records
   *
   * @returns {Promise} Resolves to a list of records
   */
  /* jshint ignore:end */
  CallListInstance.list = function list(opts, callback) {
    if (_.isFunction(opts)) {
      callback = opts;
      opts = {};
    }
    opts = opts || {};
    var deferred = Q.defer();
    var allResources = [];
    opts.callback = function(resource, done) {
      allResources.push(resource);

      if (!_.isUndefined(opts.limit) && allResources.length === opts.limit) {
        done();
      }
    };

    opts.done = function(error) {
      if (_.isUndefined(error)) {
        deferred.resolve(allResources);
      } else {
        deferred.reject(error);
      }
    };

    if (_.isFunction(callback)) {
      deferred.promise.nodeify(callback);
    }

    this.each(opts);
    return deferred.promise;
  };

  /* jshint ignore:start */
  /**
   * Retrieve a single page of CallInstance records from the API.
   *
   * The request is executed immediately.
   *
   * If a function is passed as the first argument, it will be used as the callback
   * function.
   *
   * @function page
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @param {object} [opts] - Options for request
   * @param {string} [opts.to] -
   *          Phone number or Client identifier of calls to include
   * @param {string} [opts.from] -
   *          Phone number or Client identifier to filter `from` on
   * @param {string} [opts.parentCallSid] - Parent call SID to filter on
   * @param {call.status} [opts.status] - The status of the resources to read
   * @param {Date} [opts.startTimeBefore] -
   *          Only include calls that started on this date
   * @param {Date} [opts.startTime] - Only include calls that started on this date
   * @param {Date} [opts.startTimeAfter] -
   *          Only include calls that started on this date
   * @param {Date} [opts.endTimeBefore] - Only include calls that ended on this date
   * @param {Date} [opts.endTime] - Only include calls that ended on this date
   * @param {Date} [opts.endTimeAfter] - Only include calls that ended on this date
   * @param {string} [opts.pageToken] - PageToken provided by the API
   * @param {number} [opts.pageNumber] -
   *          Page Number, this value is simply for client state
   * @param {number} [opts.pageSize] - Number of records to return, defaults to 50
   * @param {function} [callback] - Callback to handle list of records
   *
   * @returns {Promise} Resolves to a list of records
   */
  /* jshint ignore:end */
  CallListInstance.page = function page(opts, callback) {
    if (_.isFunction(opts)) {
      callback = opts;
      opts = {};
    }
    opts = opts || {};

    var deferred = Q.defer();
    var data = values.of({
      'To': _.get(opts, 'to'),
      'From': _.get(opts, 'from'),
      'ParentCallSid': _.get(opts, 'parentCallSid'),
      'Status': _.get(opts, 'status'),
      'StartTime<': serialize.iso8601DateTime(_.get(opts, 'startTimeBefore')),
      'StartTime': serialize.iso8601DateTime(_.get(opts, 'startTime')),
      'StartTime>': serialize.iso8601DateTime(_.get(opts, 'startTimeAfter')),
      'EndTime<': serialize.iso8601DateTime(_.get(opts, 'endTimeBefore')),
      'EndTime': serialize.iso8601DateTime(_.get(opts, 'endTime')),
      'EndTime>': serialize.iso8601DateTime(_.get(opts, 'endTimeAfter')),
      'PageToken': opts.pageToken,
      'Page': opts.pageNumber,
      'PageSize': opts.pageSize
    });

    var promise = this._version.page({uri: this._uri, method: 'GET', params: data});

    promise = promise.then(function(payload) {
      deferred.resolve(new CallPage(this._version, payload, this._solution));
    }.bind(this));

    promise.catch(function(error) {
      deferred.reject(error);
    });

    if (_.isFunction(callback)) {
      deferred.promise.nodeify(callback);
    }

    return deferred.promise;
  };

  /* jshint ignore:start */
  /**
   * Retrieve a single target page of CallInstance records from the API.
   *
   * The request is executed immediately.
   *
   * If a function is passed as the first argument, it will be used as the callback
   * function.
   *
   * @function getPage
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @param {string} [targetUrl] - API-generated URL for the requested results page
   * @param {function} [callback] - Callback to handle list of records
   *
   * @returns {Promise} Resolves to a list of records
   */
  /* jshint ignore:end */
  CallListInstance.getPage = function getPage(targetUrl, callback) {
    var deferred = Q.defer();

    var promise = this._version._domain.twilio.request({method: 'GET', uri: targetUrl});

    promise = promise.then(function(payload) {
      deferred.resolve(new CallPage(this._version, payload, this._solution));
    }.bind(this));

    promise.catch(function(error) {
      deferred.reject(error);
    });

    if (_.isFunction(callback)) {
      deferred.promise.nodeify(callback);
    }

    return deferred.promise;
  };

  /* jshint ignore:start */
  /**
   * Constructs a call
   *
   * @function get
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @param {string} sid - The SID of the Call resource to fetch
   *
   * @returns {Twilio.Api.V2010.AccountContext.CallContext}
   */
  /* jshint ignore:end */
  CallListInstance.get = function get(sid) {
    return new CallContext(this._version, this._solution.accountSid, sid);
  };

  Object.defineProperty(CallListInstance,
    'feedbackSummaries', {
      get: function feedbackSummaries() {
        if (!this._feedbackSummaries) {
          this._feedbackSummaries = new FeedbackSummaryList(this._version, this._solution.accountSid);
        }

        return this._feedbackSummaries;
      }
  });

  /* jshint ignore:start */
  /**
   * Provide a user-friendly representation
   *
   * @function toJSON
   * @memberof Twilio.Api.V2010.AccountContext.CallList#
   *
   * @returns Object
   */
  /* jshint ignore:end */
  CallListInstance.toJSON = function toJSON() {
    return this._solution;
  };

  CallListInstance[util.inspect.custom] = function inspect(depth, options) {
    return util.inspect(this.toJSON(), options);
  };

  return CallListInstance;
};


/* jshint ignore:start */
/**
 * Initialize the CallPage
 *
 * @constructor Twilio.Api.V2010.AccountContext.CallPage
 *
 * @param {V2010} version - Version of the resource
 * @param {Response<string>} response - Response from the API
 * @param {CallSolution} solution - Path solution
 *
 * @returns CallPage
 */
/* jshint ignore:end */
CallPage = function CallPage(version, response, solution) {
  // Path Solution
  this._solution = solution;

  Page.prototype.constructor.call(this, version, response, this._solution);
};

_.extend(CallPage.prototype, Page.prototype);
CallPage.prototype.constructor = CallPage;

/* jshint ignore:start */
/**
 * Build an instance of CallInstance
 *
 * @function getInstance
 * @memberof Twilio.Api.V2010.AccountContext.CallPage#
 *
 * @param {CallPayload} payload - Payload response from the API
 *
 * @returns CallInstance
 */
/* jshint ignore:end */
CallPage.prototype.getInstance = function getInstance(payload) {
  return new CallInstance(this._version, payload, this._solution.accountSid);
};

/* jshint ignore:start */
/**
 * Provide a user-friendly representation
 *
 * @function toJSON
 * @memberof Twilio.Api.V2010.AccountContext.CallPage#
 *
 * @returns Object
 */
/* jshint ignore:end */
CallPage.prototype.toJSON = function toJSON() {
  let clone = {};
  _.forOwn(this, function(value, key) {
    if (!_.startsWith(key, '_') && ! _.isFunction(value)) {
      clone[key] = value;
    }
  });
  return clone;
};

CallPage.prototype[util.inspect.custom] = function inspect(depth, options) {
  return util.inspect(this.toJSON(), options);
};


/* jshint ignore:start */
/**
 * Initialize the CallContext
 *
 * @constructor Twilio.Api.V2010.AccountContext.CallInstance
 *
 * @property {string} sid - The unique string that identifies this resource
 * @property {Date} dateCreated -
 *          The RFC 2822 date and time in GMT that this resource was created
 * @property {Date} dateUpdated -
 *          The RFC 2822 date and time in GMT that this resource was last updated
 * @property {string} parentCallSid -
 *          The SID that identifies the call that created this leg.
 * @property {string} accountSid -
 *          The SID of the Account that created this resource
 * @property {string} to -
 *          The phone number, SIP address or Client identifier that received this call. Phone numbers are in E.164 format (e.g., +16175551212). SIP addresses are formatted as `name@company.com`. Client identifiers are formatted `client:name`.
 * @property {string} toFormatted -
 *          The phone number, SIP address or Client identifier that received this call. Formatted for display.
 * @property {string} from -
 *          The phone number, SIP address or Client identifier that made this call. Phone numbers are in E.164 format (e.g., +16175551212). SIP addresses are formatted as `name@company.com`. Client identifiers are formatted `client:name`.
 * @property {string} fromFormatted -
 *          The calling phone number, SIP address, or Client identifier formatted for display.
 * @property {string} phoneNumberSid -
 *          If the call was inbound, this is the SID of the IncomingPhoneNumber resource that received the call. If the call was outbound, it is the SID of the OutgoingCallerId resource from which the call was placed.
 * @property {call.status} status - The status of this call.
 * @property {Date} startTime -
 *          The start time of the call. Null if the call has not yet been dialed.
 * @property {Date} endTime -
 *          The end time of the call. Null if the call did not complete successfully.
 * @property {string} duration - The length of the call in seconds.
 * @property {string} price -
 *          The charge for this call, in the currency associated with the account. Populated after the call is completed. May not be immediately available.
 * @property {string} priceUnit - The currency in which `Price` is measured.
 * @property {string} direction -
 *          A string describing the direction of the call. `inbound` for inbound calls, `outbound-api` for calls initiated via the REST API or `outbound-dial` for calls initiated by a `Dial` verb.
 * @property {string} answeredBy -
 *          Either `human` or `machine` if this call was initiated with answering machine detection. Empty otherwise.
 * @property {string} apiVersion - The API Version used to create the call
 * @property {string} forwardedFrom -
 *          The forwarding phone number if this call was an incoming call forwarded from another number (depends on carrier supporting forwarding). Otherwise, empty.
 * @property {string} groupSid -
 *          The Group SID associated with this call. If no Group is associated with the call, the field is empty.
 * @property {string} callerName -
 *          The caller's name if this call was an incoming call to a phone number with caller ID Lookup enabled. Otherwise, empty.
 * @property {string} queueTime -
 *          The wait time in milliseconds before the call is placed.
 * @property {string} trunkSid -
 *          The (optional) unique identifier of the trunk resource that was used for this call.
 * @property {string} uri -
 *          The URI of this resource, relative to `https://api.twilio.com`
 * @property {string} subresourceUris -
 *          A list of related subresources identified by their relative URIs
 *
 * @param {V2010} version - Version of the resource
 * @param {CallPayload} payload - The instance payload
 * @param {sid} accountSid - The SID of the Account that created this resource
 * @param {sid} sid - The SID of the Call resource to fetch
 */
/* jshint ignore:end */
CallInstance = function CallInstance(version, payload, accountSid, sid) {
  this._version = version;

  // Marshaled Properties
  this.sid = payload.sid; // jshint ignore:line
  this.dateCreated = deserialize.rfc2822DateTime(payload.date_created); // jshint ignore:line
  this.dateUpdated = deserialize.rfc2822DateTime(payload.date_updated); // jshint ignore:line
  this.parentCallSid = payload.parent_call_sid; // jshint ignore:line
  this.accountSid = payload.account_sid; // jshint ignore:line
  this.to = payload.to; // jshint ignore:line
  this.toFormatted = payload.to_formatted; // jshint ignore:line
  this.from = payload.from; // jshint ignore:line
  this.fromFormatted = payload.from_formatted; // jshint ignore:line
  this.phoneNumberSid = payload.phone_number_sid; // jshint ignore:line
  this.status = payload.status; // jshint ignore:line
  this.startTime = deserialize.rfc2822DateTime(payload.start_time); // jshint ignore:line
  this.endTime = deserialize.rfc2822DateTime(payload.end_time); // jshint ignore:line
  this.duration = payload.duration; // jshint ignore:line
  this.price = payload.price; // jshint ignore:line
  this.priceUnit = payload.price_unit; // jshint ignore:line
  this.direction = payload.direction; // jshint ignore:line
  this.answeredBy = payload.answered_by; // jshint ignore:line
  this.apiVersion = payload.api_version; // jshint ignore:line
  this.forwardedFrom = payload.forwarded_from; // jshint ignore:line
  this.groupSid = payload.group_sid; // jshint ignore:line
  this.callerName = payload.caller_name; // jshint ignore:line
  this.queueTime = payload.queue_time; // jshint ignore:line
  this.trunkSid = payload.trunk_sid; // jshint ignore:line
  this.uri = payload.uri; // jshint ignore:line
  this.subresourceUris = payload.subresource_uris; // jshint ignore:line

  // Context
  this._context = undefined;
  this._solution = {accountSid: accountSid, sid: sid || this.sid, };
};

Object.defineProperty(CallInstance.prototype,
  '_proxy', {
    get: function() {
      if (!this._context) {
        this._context = new CallContext(this._version, this._solution.accountSid, this._solution.sid);
      }

      return this._context;
    }
});

/* jshint ignore:start */
/**
 * remove a CallInstance
 *
 * @function remove
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @param {function} [callback] - Callback to handle processed record
 *
 * @returns {Promise} Resolves to processed CallInstance
 */
/* jshint ignore:end */
CallInstance.prototype.remove = function remove(callback) {
  return this._proxy.remove(callback);
};

/* jshint ignore:start */
/**
 * fetch a CallInstance
 *
 * @function fetch
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @param {function} [callback] - Callback to handle processed record
 *
 * @returns {Promise} Resolves to processed CallInstance
 */
/* jshint ignore:end */
CallInstance.prototype.fetch = function fetch(callback) {
  return this._proxy.fetch(callback);
};

/* jshint ignore:start */
/**
 * update a CallInstance
 *
 * @function update
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @param {object} [opts] - Options for request
 * @param {string} [opts.url] - The absolute URL that returns TwiML for this call
 * @param {string} [opts.method] - HTTP method to use to fetch TwiML
 * @param {call.update_status} [opts.status] -
 *          The new status to update the call with.
 * @param {string} [opts.fallbackUrl] - Fallback URL in case of error
 * @param {string} [opts.fallbackMethod] - HTTP Method to use with fallback_url
 * @param {string} [opts.statusCallback] -
 *          The URL we should call to send status information to your application
 * @param {string} [opts.statusCallbackMethod] -
 *          HTTP Method to use to call status_callback
 * @param {string} [opts.twiml] - TwiML instructions for the call
 * @param {number} [opts.timeLimit] - The maximum duration of the call in seconds.
 * @param {function} [callback] - Callback to handle processed record
 *
 * @returns {Promise} Resolves to processed CallInstance
 */
/* jshint ignore:end */
CallInstance.prototype.update = function update(opts, callback) {
  return this._proxy.update(opts, callback);
};

/* jshint ignore:start */
/**
 * Access the recordings
 *
 * @function recordings
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.RecordingList}
 */
/* jshint ignore:end */
CallInstance.prototype.recordings = function recordings() {
  return this._proxy.recordings;
};

/* jshint ignore:start */
/**
 * Access the notifications
 *
 * @function notifications
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.NotificationList}
 */
/* jshint ignore:end */
CallInstance.prototype.notifications = function notifications() {
  return this._proxy.notifications;
};

/* jshint ignore:start */
/**
 * Access the feedback
 *
 * @function feedback
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.FeedbackList}
 */
/* jshint ignore:end */
CallInstance.prototype.feedback = function feedback() {
  return this._proxy.feedback;
};

/* jshint ignore:start */
/**
 * Access the events
 *
 * @function events
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.EventList}
 */
/* jshint ignore:end */
CallInstance.prototype.events = function events() {
  return this._proxy.events;
};

/* jshint ignore:start */
/**
 * Access the payments
 *
 * @function payments
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.PaymentList}
 */
/* jshint ignore:end */
CallInstance.prototype.payments = function payments() {
  return this._proxy.payments;
};

/* jshint ignore:start */
/**
 * Access the siprec
 *
 * @function siprec
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.SiprecList}
 */
/* jshint ignore:end */
CallInstance.prototype.siprec = function siprec() {
  return this._proxy.siprec;
};

/* jshint ignore:start */
/**
 * Access the streams
 *
 * @function streams
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns {Twilio.Api.V2010.AccountContext.CallContext.StreamList}
 */
/* jshint ignore:end */
CallInstance.prototype.streams = function streams() {
  return this._proxy.streams;
};

/* jshint ignore:start */
/**
 * Provide a user-friendly representation
 *
 * @function toJSON
 * @memberof Twilio.Api.V2010.AccountContext.CallInstance#
 *
 * @returns Object
 */
/* jshint ignore:end */
CallInstance.prototype.toJSON = function toJSON() {
  let clone = {};
  _.forOwn(this, function(value, key) {
    if (!_.startsWith(key, '_') && ! _.isFunction(value)) {
      clone[key] = value;
    }
  });
  return clone;
};

CallInstance.prototype[util.inspect.custom] = function inspect(depth, options) {
  return util.inspect(this.toJSON(), options);
};


/* jshint ignore:start */
/**
 * Initialize the CallContext
 *
 * @constructor Twilio.Api.V2010.AccountContext.CallContext
 *
 * @property {Twilio.Api.V2010.AccountContext.CallContext.RecordingList} recordings -
 *          recordings resource
 * @property {Twilio.Api.V2010.AccountContext.CallContext.NotificationList} notifications -
 *          notifications resource
 * @property {Twilio.Api.V2010.AccountContext.CallContext.FeedbackList} feedback -
 *          feedback resource
 * @property {Twilio.Api.V2010.AccountContext.CallContext.EventList} events -
 *          events resource
 * @property {Twilio.Api.V2010.AccountContext.CallContext.PaymentList} payments -
 *          payments resource
 * @property {Twilio.Api.V2010.AccountContext.CallContext.SiprecList} siprec -
 *          siprec resource
 * @property {Twilio.Api.V2010.AccountContext.CallContext.StreamList} streams -
 *          streams resource
 *
 * @param {V2010} version - Version of the resource
 * @param {sid} accountSid -
 *          The SID of the Account that created the resource(s) to fetch
 * @param {sid} sid - The SID of the Call resource to fetch
 */
/* jshint ignore:end */
CallContext = function CallContext(version, accountSid, sid) {
  this._version = version;

  // Path Solution
  this._solution = {accountSid: accountSid, sid: sid, };
  this._uri = `/Accounts/${accountSid}/Calls/${sid}.json`;

  // Dependents
  this._recordings = undefined;
  this._notifications = undefined;
  this._feedback = undefined;
  this._events = undefined;
  this._payments = undefined;
  this._siprec = undefined;
  this._streams = undefined;
};

/* jshint ignore:start */
/**
 * remove a CallInstance
 *
 * @function remove
 * @memberof Twilio.Api.V2010.AccountContext.CallContext#
 *
 * @param {function} [callback] - Callback to handle processed record
 *
 * @returns {Promise} Resolves to processed CallInstance
 */
/* jshint ignore:end */
CallContext.prototype.remove = function remove(callback) {
  var deferred = Q.defer();
  var promise = this._version.remove({uri: this._uri, method: 'DELETE'});

  promise = promise.then(function(payload) {
    deferred.resolve(payload);
  }.bind(this));

  promise.catch(function(error) {
    deferred.reject(error);
  });

  if (_.isFunction(callback)) {
    deferred.promise.nodeify(callback);
  }

  return deferred.promise;
};

/* jshint ignore:start */
/**
 * fetch a CallInstance
 *
 * @function fetch
 * @memberof Twilio.Api.V2010.AccountContext.CallContext#
 *
 * @param {function} [callback] - Callback to handle processed record
 *
 * @returns {Promise} Resolves to processed CallInstance
 */
/* jshint ignore:end */
CallContext.prototype.fetch = function fetch(callback) {
  var deferred = Q.defer();
  var promise = this._version.fetch({uri: this._uri, method: 'GET'});

  promise = promise.then(function(payload) {
    deferred.resolve(new CallInstance(
      this._version,
      payload,
      this._solution.accountSid,
      this._solution.sid
    ));
  }.bind(this));

  promise.catch(function(error) {
    deferred.reject(error);
  });

  if (_.isFunction(callback)) {
    deferred.promise.nodeify(callback);
  }

  return deferred.promise;
};

/* jshint ignore:start */
/**
 * update a CallInstance
 *
 * @function update
 * @memberof Twilio.Api.V2010.AccountContext.CallContext#
 *
 * @param {object} [opts] - Options for request
 * @param {string} [opts.url] - The absolute URL that returns TwiML for this call
 * @param {string} [opts.method] - HTTP method to use to fetch TwiML
 * @param {call.update_status} [opts.status] -
 *          The new status to update the call with.
 * @param {string} [opts.fallbackUrl] - Fallback URL in case of error
 * @param {string} [opts.fallbackMethod] - HTTP Method to use with fallback_url
 * @param {string} [opts.statusCallback] -
 *          The URL we should call to send status information to your application
 * @param {string} [opts.statusCallbackMethod] -
 *          HTTP Method to use to call status_callback
 * @param {string} [opts.twiml] - TwiML instructions for the call
 * @param {number} [opts.timeLimit] - The maximum duration of the call in seconds.
 * @param {function} [callback] - Callback to handle processed record
 *
 * @returns {Promise} Resolves to processed CallInstance
 */
/* jshint ignore:end */
CallContext.prototype.update = function update(opts, callback) {
  if (_.isFunction(opts)) {
    callback = opts;
    opts = {};
  }
  opts = opts || {};

  var deferred = Q.defer();
  var data = values.of({
    'Url': _.get(opts, 'url'),
    'Method': _.get(opts, 'method'),
    'Status': _.get(opts, 'status'),
    'FallbackUrl': _.get(opts, 'fallbackUrl'),
    'FallbackMethod': _.get(opts, 'fallbackMethod'),
    'StatusCallback': _.get(opts, 'statusCallback'),
    'StatusCallbackMethod': _.get(opts, 'statusCallbackMethod'),
    'Twiml': _.get(opts, 'twiml'),
    'TimeLimit': _.get(opts, 'timeLimit')
  });

  var promise = this._version.update({uri: this._uri, method: 'POST', data: data});

  promise = promise.then(function(payload) {
    deferred.resolve(new CallInstance(
      this._version,
      payload,
      this._solution.accountSid,
      this._solution.sid
    ));
  }.bind(this));

  promise.catch(function(error) {
    deferred.reject(error);
  });

  if (_.isFunction(callback)) {
    deferred.promise.nodeify(callback);
  }

  return deferred.promise;
};

Object.defineProperty(CallContext.prototype,
  'recordings', {
    get: function() {
      if (!this._recordings) {
        this._recordings = new RecordingList(this._version, this._solution.accountSid, this._solution.sid);
      }
      return this._recordings;
    }
});

Object.defineProperty(CallContext.prototype,
  'notifications', {
    get: function() {
      if (!this._notifications) {
        this._notifications = new NotificationList(
          this._version,
          this._solution.accountSid,
          this._solution.sid
        );
      }
      return this._notifications;
    }
});

Object.defineProperty(CallContext.prototype,
  'feedback', {
    get: function() {
      if (!this._feedback) {
        this._feedback = new FeedbackList(this._version, this._solution.accountSid, this._solution.sid);
      }
      return this._feedback;
    }
});

Object.defineProperty(CallContext.prototype,
  'events', {
    get: function() {
      if (!this._events) {
        this._events = new EventList(this._version, this._solution.accountSid, this._solution.sid);
      }
      return this._events;
    }
});

Object.defineProperty(CallContext.prototype,
  'payments', {
    get: function() {
      if (!this._payments) {
        this._payments = new PaymentList(this._version, this._solution.accountSid, this._solution.sid);
      }
      return this._payments;
    }
});

Object.defineProperty(CallContext.prototype,
  'siprec', {
    get: function() {
      if (!this._siprec) {
        this._siprec = new SiprecList(this._version, this._solution.accountSid, this._solution.sid);
      }
      return this._siprec;
    }
});

Object.defineProperty(CallContext.prototype,
  'streams', {
    get: function() {
      if (!this._streams) {
        this._streams = new StreamList(this._version, this._solution.accountSid, this._solution.sid);
      }
      return this._streams;
    }
});

/* jshint ignore:start */
/**
 * Provide a user-friendly representation
 *
 * @function toJSON
 * @memberof Twilio.Api.V2010.AccountContext.CallContext#
 *
 * @returns Object
 */
/* jshint ignore:end */
CallContext.prototype.toJSON = function toJSON() {
  return this._solution;
};

CallContext.prototype[util.inspect.custom] = function inspect(depth, options) {
  return util.inspect(this.toJSON(), options);
};

module.exports = {
  CallList: CallList,
  CallPage: CallPage,
  CallInstance: CallInstance,
  CallContext: CallContext
};
