/**
 * {{&description}}
 * @class {{&className}}
 * @param {(string|object)} [domainOrOptions] - The project domain or options object. If object, see the object's optional properties.
 * @param {string} [domainOrOptions.domain] - The project domain
 * @param {object} [domainOrOptions.token] - auth token - object with value property and optional headerOrQueryName and isQuery properties
 */
const {{&className}} = (function(){
    'use strict';

    {{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} request = require('request');
    {{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} Q = require('q');

    function {{&className}}(options){
        {{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} domain = (typeof options === 'object') ? options.domain : options;
        this.domain = domain ? domain : '{{&domain}}';
        if(this.domain.length === 0) {
            throw new Error('Domain parameter must be specified as a string.');
        }
        {{#isSecure}}
            {{#isSecureToken}}
                this.token = (typeof options === 'object') ? (options.token ? options.token : {}) : {};
            {{/isSecureToken}}
            {{#isSecureApiKey}}
                this.apiKey = (typeof options === 'object') ? (options.apiKey ? options.apiKey : {}) : {};
            {{/isSecureApiKey}}
            {{#isSecureBasic}}
                this.basic = (typeof options === 'object') ? (options.basic ? options.basic : {}) : {};
            {{/isSecureBasic}}
        {{/isSecure}}
    }

    function mergeQueryParams(parameters, queryParameters) {
        if (parameters.$queryParameters) {
            Object.keys(parameters.$queryParameters)
                  .forEach(function(parameterName) {
                      {{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} parameter = parameters.$queryParameters[parameterName];
                      queryParameters[parameterName] = parameter;
            });
        }
        return queryParameters;
    }

    /**
     * HTTP Request
     * @method
     * @name {{&className}}#request
     * @param {string} method - http method
     * @param {string} url - url to do request
     * @param {object} parameters
     * @param {object} body - body parameters / object
     * @param {object} headers - header parameters
     * @param {object} queryParameters - querystring parameters
     * @param {object} form - form data object
     * @param {object} deferred - promise object
     */
    {{&className}}.prototype.request = function(method, url, parameters, body, headers, queryParameters, form, deferred){
        {{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} req = {
            method: method,
            uri: url,
            qs: queryParameters,
            headers: headers,
            body: body
        };
        if(Object.keys(form).length > 0) {
            req.form = form;
        }
        if(typeof(body) === 'object' && !(body instanceof Buffer)) {
            req.json = true;
        }
        request(req, function(error, response, body){
            if(error) {
                deferred.reject(error);
            } else {
                if(/^application\/(.*\\+)?json/.test(response.headers['content-type'])) {
                    try {
                        body = JSON.parse(body);
                    } catch(e) {}
                }
                if(response.statusCode === 204) {
                    deferred.resolve({ response: response });
                } else if(response.statusCode >= 200 && response.statusCode <= 299) {
                    deferred.resolve({ response: response, body: body });
                } else {
                    deferred.reject({ response: response, body: body });
                }
            }
        });
    };

    {{#isSecure}}
        {{#isSecureToken}}
            /**
            * Set Token
            * @method
            * @name {{&className}}#setToken
            * @param {string} value - token's value
            * @param {string} headerOrQueryName - the header or query name to send the token at
            * @param {boolean} isQuery - true if send the token as query param, otherwise, send as header param
            */
            {{&className}}.prototype.setToken = function (value, headerOrQueryName, isQuery) {
                this.token.value = value;
                this.token.headerOrQueryName = headerOrQueryName;
                this.token.isQuery = isQuery;
            };
        {{/isSecureToken}}
        {{#isSecureApiKey}}
            /**
            * Set Api Key
            * @method
            * @name {{&className}}#setApiKey
            * @param {string} value - apiKey's value
            * @param {string} headerOrQueryName - the header or query name to send the apiKey at
            * @param {boolean} isQuery - true if send the apiKey as query param, otherwise, send as header param
            */
            {{&className}}.prototype.setApiKey = function (value, headerOrQueryName, isQuery) {
                this.apiKey.value = value;
                this.apiKey.headerOrQueryName = headerOrQueryName;
                this.apiKey.isQuery = isQuery;
            };
        {{/isSecureApiKey}}
        {{#isSecureBasic}}
            /**
            * Set Basic Auth
            * @method
            * @name {{&className}}#setBasicAuth
            * @param {string} username
            * @param {string} password
            */
            {{&className}}.prototype.setBasicAuth = function (username, password) {
                this.basic.username = value;
                this.basic.password = password;
            };
        {{/isSecureBasic}}
        /**
        * Set Auth headers
        * @method
        * @name {{&className}}#setAuthHeaders
        * @param {object} headerParams - headers object
        */
        {{&className}}.prototype.setAuthHeaders = function (headerParams) {
            {{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} headers = headerParams ? headerParams : {};
        {{#isSecureToken}}
            if (!this.token.isQuery) {
                if (this.token.headerOrQueryName) {
                    headers[this.token.headerOrQueryName] = this.token.value;
                } else if (this.token.value) {
                    headers['Authorization'] = 'Bearer ' + this.token.value;
                }
            }
        {{/isSecureToken}}
        {{#isSecureApiKey}}
            if (!this.apiKey.isQuery && this.apiKey.headerOrQueryName) {
                headers[this.apiKey.headerOrQueryName] = this.apiKey.value;
            }
        {{/isSecureApiKey}}
        {{#isSecureBasic}}
            if (this.basic.username && this.basic.password) {
                headers['Authorization'] = 'Basic ' + new Buffer(this.basic.username + ':' + this.basic.password, 'base64').toString();
            }
        {{/isSecureBasic}}
            return headers;
        };
    {{/isSecure}}

    {{#methods}}
        {{> method}}
    {{/methods}}

    return {{&className}};
})();

exports.{{&className}} = {{&className}};
