(function(root, factory) {

if (typeof module === 'object' && module.exports) {
    // CommonJS-like environments that support module.exports, like Node.
    module.exports = factory(require('../ApiClient'), require('./InvocationContext'), require('../CommonUtil'), require('../ResponseWrapper'), require('./Base')
, require('../handlers/CreateCustomerHandler')
, require('../handlers/GetCustomerHandler')
, require('../handlers/UpdateCustomerHandler'), require('../OrbipayApiError'));
  }
}(this, function(ApiClient, InvocationContext, CommonUtil, ResponseWrapper, Base, CreateCustomerHandler, GetCustomerHandler, UpdateCustomerHandler, OrbipayApiError) {
  'use strict';

    /**
    * The Customer wrapper module.
    * @module wrappers/Customer
    */
  var exports = function(id_customer) {
  	var _this = this;
        Base.call(_this);
  		_this['ID_CUSTOMER'] = id_customer;
        _this.id = id_customer;
  };

      /**
      * Constructs a <code>Customer</code> from a plain JavaScript object, optionally creating a new instance.
      * Copies all relevant properties from <code>data</code> to <code>obj</code> if supplied or a new instance if not.
      * @param {Object} data The plain JavaScript object bearing properties of interest.
      * @param {module:wrappers/Customer} obj Optional instance to populate.
      * @return {module:wrappers/Customer} The populated <code>Customer</code> instance.
      */
  exports.constructFromObject = function (data, obj) {
        if (data) {
            obj = obj || new exports();
            if (data.hasOwnProperty('first_name')) {
                obj['first_name'] = data['first_name'];
            }
            if (data.hasOwnProperty('last_name')) {
                obj['last_name'] = data['last_name'];
            }
            if (data.hasOwnProperty('middle_name')) {
                obj['middle_name'] = data['middle_name'];
            }
            if (data.hasOwnProperty('gender')) {
                obj['gender'] = data['gender'];
            }
            if (data.hasOwnProperty('date_of_birth')) {
                obj['date_of_birth'] = data['date_of_birth'];
            }
            if (data.hasOwnProperty('ssn')) {
                obj['ssn'] = data['ssn'];
            }
            if (data.hasOwnProperty('locale')) {
                obj['locale'] = data['locale'];
            }
            if (data.hasOwnProperty('email')) {
                obj['email'] = data['email'];
            }
            if (data.hasOwnProperty('registered_email')) {
                obj['registered_email'] = data['registered_email'];
            }
            if (data.hasOwnProperty('home_phone')) {
                obj['home_phone'] = data['home_phone'];
            }
            if (data.hasOwnProperty('work_phone')) {
                obj['work_phone'] = data['work_phone'];
            }
            if (data.hasOwnProperty('mobile_phone')) {
                obj['mobile_phone'] = data['mobile_phone'];
            }
            if (data.hasOwnProperty('address')) {
                var Address = require('./Address');
                obj['address'] = Address.constructFromObject(data['address']);
            }
            if (data.hasOwnProperty('custom_fields')) {
                obj['custom_fields'] = data['custom_fields'];
            }
            if (data.hasOwnProperty('customer_reference')) {
                obj['customer_reference'] = data['customer_reference'];
            }
            if (data.hasOwnProperty('id')) {
                obj['id'] = data['id'];
            }
            if (data.hasOwnProperty('status')) {
                obj['status'] = data['status'];
            }
            if (data.hasOwnProperty('url')) {
                obj['url'] = data['url'];
            }
            if (data.hasOwnProperty('comments')) {
                obj['comments'] = data['comments'];
            }
            if (data.hasOwnProperty('customer_accounts')) {
                var CustomerAccounts = require('./CustomerAccounts');
                obj['customer_accounts'] = CustomerAccounts.constructFromObject(data['customer_accounts']);
            }
            if (data.hasOwnProperty('funding_accounts')) {
                var FundingAccounts = require('./FundingAccounts');
                obj['funding_accounts'] = FundingAccounts.constructFromObject(data['funding_accounts']);
            }
            if (data.hasOwnProperty('payments')) {
                var Payments = require('./Payments');
                obj['payments'] = Payments.constructFromObject(data['payments']);
            }
            if (data.hasOwnProperty('payment_setups')) {
                var PaymentSetups = require('./PaymentSetups');
                obj['payment_setups'] = PaymentSetups.constructFromObject(data['payment_setups']);
            }
            if (data.hasOwnProperty('audit_info')) {
                var AuditInfo = require('./AuditInfo');
                obj['audit_info'] = AuditInfo.constructFromObject(data['audit_info']);
            }
            if (data.hasOwnProperty('ID_CUSTOMER')) {
                obj['ID_CUSTOMER'] = data['ID_CUSTOMER'];
            }
        }
        return obj;
  };


  exports.prototype = Object.create(Base.prototype);
  exports.prototype.constructor = exports;

    /**
    * The first name of the customer. Either first_name or last_name is required to create a customer.
    * @member {String} first_name
    */
  exports.prototype['first_name'] = undefined;
    /**
    * The last name of the customer. Either first_name or last_name is required to create a customer.
    * @member {String} last_name
    */
  exports.prototype['last_name'] = undefined;
    /**
    * The middle name of the customer.
    * @member {String} middle_name
    */
  exports.prototype['middle_name'] = undefined;
    /**
    * The gender of the customer.
    * @member {String} gender
    */
  exports.prototype['gender'] = undefined;
    /**
    * The date of birth of the customer. It should be in the full-date format as per ISO8601, namely, YYYY-MM-DD.
    * @member {String} date_of_birth
    */
  exports.prototype['date_of_birth'] = undefined;
    /**
    * The SSN of the customer if the account holder is an individual or the tax ID, if the customer is a business.
    * @member {String} ssn
    */
  exports.prototype['ssn'] = undefined;
    /**
    * The language in which the customer wants the alerts and notifications from EBPP. This is to be specified in the format,<br><i>< <b>ISO-639-1 language code</b>  >_< <b>ISO ALPHA-2 Country Code</b> ></i>.<br> For e.g., <b>en_US</b> indicates the language preference as US English, which is also the default value.
    * @member {String} locale
    */
  exports.prototype['locale'] = undefined;
    /**
    * The email address of the customer to which notifications from EBPP will be sent. This will default to the registered_email while creating a customer.
    * @member {String} email
    */
  exports.prototype['email'] = undefined;
    /**
    * The email address of the customer registered with the client. This may be used to uniquely identify the customer if the client is set up accordingly in EBPP.
    * @member {String} registered_email
    */
  exports.prototype['registered_email'] = undefined;
    /**
    * The home phone number of the customer.
    * @member {String} home_phone
    */
  exports.prototype['home_phone'] = undefined;
    /**
    * The work phone number of the customer.
    * @member {String} work_phone
    */
  exports.prototype['work_phone'] = undefined;
    /**
    * The mobile phone number of the customer.
    * @member {String} mobile_phone
    */
  exports.prototype['mobile_phone'] = undefined;
    /**
    * @member {Address} address
    */
  exports.prototype['address'] = undefined;
    /**
    * The additional information or meta-information that EBPP can accept, maintain and transmit back to the client. The custom fields need to be configured with EBPP before they can be accepted. EBPP would reject custom fields that are not pre-configured. Please contact <a href = \"mailto: support@billerpayments.com\">support@billerpayments.com</a> for more information on configuring and using custom fields. Only the custom fields enabled for the client, in EBPP, would be accepted in the requests.
    * @member {{String: String}} custom_fields
    */
  exports.prototype['custom_fields'] = undefined;
    /**
    * The unique identifier in the client system for the customer.
    * @member {String} customer_reference
    */
  exports.prototype['customer_reference'] = undefined;
    /**
    * The unique identifier assigned by EBPP to the customer.
    * @member {String} id
    */
  exports.prototype['id'] = undefined;
    /**
    * The status of the customer in EBPP. 
    * @member {String} status
    */
  exports.prototype['status'] = undefined;
    /**
    * This URL fetches the Customer details.
    * @member {String} url
    */
  exports.prototype['url'] = undefined;
    /**
    * Comments that can be used to recollect the operation performed on the resource object. API clients need to ensure that no sensitive information is passed in the memo. Alacriti (EBPP) is not responsible for the security of any sensitive information that may be passed as part of the memo.
    * @member {String} comments
    */
  exports.prototype['comments'] = undefined;
    /**
    * @member {CustomerAccounts} customer_accounts
    */
  exports.prototype['customer_accounts'] = undefined;
    /**
    * @member {FundingAccounts} funding_accounts
    */
  exports.prototype['funding_accounts'] = undefined;
    /**
    * @member {Payments} payments
    */
  exports.prototype['payments'] = undefined;
    /**
    * @member {PaymentSetups} payment_setups
    */
  exports.prototype['payment_setups'] = undefined;
    /**
    * @member {AuditInfo} audit_info
    */
  exports.prototype['audit_info'] = undefined;
    /**
    * The unique identifier assigned by EBPP to the customer.
    * @member {String} ID_CUSTOMER
    */
  exports.prototype['ID_CUSTOMER'] = undefined;

  /**
  * @param  {String} client_key - The client_key of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.forClient = function (client_key) {
        var _this = this;
	    Base.prototype.forClient.call(_this,client_key);
        return _this;
  };
  /**
  * @param  {String} channel - The channel of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.videChannel = function (channel) {
        var _this = this;
	    Base.prototype.videChannel.call(_this,channel);
        return _this;
  };
  /**
  * @param  {String} first_name - The first_name of Customer. 
  * @param  {String} last_name - The last_name of Customer. 
  * @param  {String} middle_name - The middle_name of Customer. 
  * @param  {String} date_of_birth - The date_of_birth of Customer. 
  * @param  {String} ssn - The ssn of Customer. 
  * @param  {String} gender - The gender of Customer. 
  * @param  {String} registered_email - The registered_email of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withDetails = function (first_name, last_name, middle_name, date_of_birth, ssn, gender, registered_email) {
        var _this = this;

        _this['first_name'] = first_name;

        _this['last_name'] = last_name;

        _this['middle_name'] = middle_name;

        _this['date_of_birth'] = date_of_birth;

        _this['ssn'] = ssn;

        _this['gender'] = gender;

        _this['registered_email'] = registered_email;


        return _this;
  };
  /**
  * @param  {String} customer_reference - The customer_reference of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withReference = function (customer_reference) {
        var _this = this;

        _this['customer_reference'] = customer_reference;


        return _this;
  };
  /**
  * @param  {String} status - The status of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withStatus = function (status) {
        var _this = this;

        _this['status'] = status;


        return _this;
  };
  /**
  * @param  {String} email - The email of Customer. 
  * @param  {String} home_phone - The home_phone of Customer. 
  * @param  {String} work_phone - The work_phone of Customer. 
  * @param  {String} mobile_phone - The mobile_phone of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withContactInfo = function (email, home_phone, work_phone, mobile_phone) {
        var _this = this;

        _this['email'] = email;

        _this['home_phone'] = home_phone;

        _this['work_phone'] = work_phone;

        _this['mobile_phone'] = mobile_phone;


        return _this;
  };
  /**
  * @param  {String} locale - The locale of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withLocale = function (locale) {
        var _this = this;

        _this['locale'] = locale;


        return _this;
  };
  /**
  * @param  {CustomerAccounts} customer_accounts - The customer_accounts of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withAccounts = function (customer_accounts) {
        var _this = this;

        _this['customer_accounts'] = customer_accounts;


        return _this;
  };
  /**
  * @param  {Address} address - The address of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withAddress = function (address) {
        var _this = this;

        _this['address'] = address;


        return _this;
  };
  /**
  * @param  {{String: String}} custom_fields - The custom_fields of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withCustomFields = function (custom_fields) {
        var _this = this;

        _this['custom_fields'] = custom_fields;


        return _this;
  };
  /**
  * @param  {String} comments - The comments of Customer. 
  * @return {module:wrappers/Customer} The instance of <code>Customer</code>.
  */
  exports.prototype.withMemo = function (comments) {
        var _this = this;

        _this['comments'] = comments;


        return _this;
  };

  exports.prototype.createdBy = function (requestor, requestor_type) {
        var _this = this;
        _this.requestedBy(requestor, requestor_type);
        return _this;
  };
  exports.prototype.retrievedBy = function (requestor, requestor_type) {
        var _this = this;
        _this.requestedBy(requestor, requestor_type);
        return _this;
  };
  exports.prototype.updatedBy = function (requestor, requestor_type) {
        var _this = this;
        _this.requestedBy(requestor, requestor_type);
        return _this;
  };

  exports.prototype.create = function (invocation_context, callback, live_mode, api_end_point) {
        var _this = this;
        var internalCallback = function (errorMessage, parsedData, httpResponse, exception) {
            try {
                var response = ResponseWrapper.wrapResponse(exports, exception, errorMessage, parsedData, httpResponse);
                if (callback) {
                    callback(response['exception'], response['data'])
                }
            } catch (e) {
                exception = OrbipayApiError.getDefaultException(e);
                if (callback) {
                    callback(exception)
                }
            }
        };
        try {
			_this.withContext(invocation_context, live_mode, api_end_point);
			var handler = new CreateCustomerHandler();
			if (callback && CommonUtil.isFunction(callback)) {
			    return handler.process(_this, internalCallback);
			} else {
			    return handler.process(_this);
			}
		}
		catch (e){
		    var error = OrbipayApiError.getDefaultException(e);
		    if (callback) {
		        callback(error)
		    }
        }
  };
  exports.prototype.get = function (invocation_context, callback, live_mode, api_end_point) {
        var _this = this;
        var internalCallback = function (errorMessage, parsedData, httpResponse, exception) {
            try {
                var response = ResponseWrapper.wrapResponse(exports, exception, errorMessage, parsedData, httpResponse);
                if (callback) {
                    callback(response['exception'], response['data'])
                }
            } catch (e) {
                exception = OrbipayApiError.getDefaultException(e);
                if (callback) {
                    callback(exception)
                }
            }
        };
        try {
			_this.withContext(invocation_context, live_mode, api_end_point);
			var handler = new GetCustomerHandler();
			if (callback && CommonUtil.isFunction(callback)) {
			    return handler.process(_this, internalCallback);
			} else {
			    return handler.process(_this);
			}
		}
		catch (e){
		    var error = OrbipayApiError.getDefaultException(e);
		    if (callback) {
		        callback(error)
		    }
        }
  };
  exports.prototype.update = function (invocation_context, callback, live_mode, api_end_point) {
        var _this = this;
        var internalCallback = function (errorMessage, parsedData, httpResponse, exception) {
            try {
                var response = ResponseWrapper.wrapResponse(exports, exception, errorMessage, parsedData, httpResponse);
                if (callback) {
                    callback(response['exception'], response['data'])
                }
            } catch (e) {
                exception = OrbipayApiError.getDefaultException(e);
                if (callback) {
                    callback(exception)
                }
            }
        };
        try {
			_this.withContext(invocation_context, live_mode, api_end_point);
			var handler = new UpdateCustomerHandler();
			if (callback && CommonUtil.isFunction(callback)) {
			    return handler.process(_this, internalCallback);
			} else {
			    return handler.process(_this);
			}
		}
		catch (e){
		    var error = OrbipayApiError.getDefaultException(e);
		    if (callback) {
		        callback(error)
		    }
        }
  };

  return exports;

}));