"use strict";
var fs = require('fs');
var logger = require('../logger');
var whitelist = require('../resources/aws_whitelist.json');
var paramTypes = {
    REQ_DESC: 'request_descriptors',
    REQ_PARAMS: 'request_parameters',
    RES_DESC: 'response_descriptors',
    RES_PARAMS: 'response_parameters'
};
/**
 * Represents a set of AWS services, operations and keys or params to capture.
 * @constructor
 * @param {string|Object} [source] - The location or source JSON object of the custom AWS whitelist file. If none is provided, the default file will be used.
 */
function CallCapturer(source) {
    this.init(source);
}
CallCapturer.prototype.init = function init(source) {
    if (source) {
        if (typeof source === 'string') {
            logger.getLogger().info('Using custom AWS whitelist file: ' + source);
            this.services = loadWhitelist(JSON.parse(fs.readFileSync(source, 'utf8')));
        }
        else {
            logger.getLogger().info('Using custom AWS whitelist source.');
            this.services = loadWhitelist(source);
        }
    }
    else {
        this.services = whitelist.services;
    }
};
CallCapturer.prototype.append = function append(source) {
    var newServices = {};
    if (typeof source === 'string') {
        logger.getLogger().info('Appending AWS whitelist with custom file: ' + source);
        newServices = loadWhitelist(JSON.parse(fs.readFileSync(source, 'utf8')));
    }
    else {
        logger.getLogger().info('Appending AWS whitelist with a custom source.');
        newServices = loadWhitelist(source);
    }
    for (var attribute in newServices) {
        this.services[attribute] = newServices[attribute];
    }
};
CallCapturer.prototype.capture = function capture(serviceName, response) {
    var operation = response.request.operation;
    var call = this.services[serviceName] !== undefined ? this.services[serviceName].operations[operation] : null;
    if (call === null) {
        logger.getLogger().debug('Call "' + serviceName + '.' + operation + '" is not whitelisted for additional data capturing. Ignoring.');
        return;
    }
    var dataCaptured = {};
    for (var paramType in call) {
        var params = call[paramType];
        if (paramType === paramTypes.REQ_PARAMS) {
            captureCallParams(params, response.request.params, dataCaptured);
        }
        else if (paramType === paramTypes.REQ_DESC) {
            captureDescriptors(params, response.request.params, dataCaptured);
        }
        else if (paramType === paramTypes.RES_PARAMS) {
            if (response.data) {
                captureCallParams(params, response.data, dataCaptured);
            }
        }
        else if (paramType === paramTypes.RES_DESC) {
            if (response.data) {
                captureDescriptors(params, response.data, dataCaptured);
            }
        }
        else {
            logger.getLogger().error('Unknown parameter type "' + paramType + '". Must be "request_descriptors", "response_descriptors", ' +
                '"request_parameters" or "response_parameters".');
        }
    }
    return dataCaptured;
};
function captureCallParams(params, call, data) {
    params.forEach(function (param) {
        if (typeof call[param] !== 'undefined') {
            var formatted = toSnakeCase(param);
            this[formatted] = call[param];
        }
    }, data);
}
function captureDescriptors(descriptors, params, data) {
    for (var paramName in descriptors) {
        var attributes = descriptors[paramName];
        if (typeof params[paramName] !== 'undefined') {
            var paramData;
            if (attributes.list && attributes.get_count) {
                paramData = params[paramName] ? params[paramName].length : 0;
            }
            else {
                paramData = attributes.get_keys === true ? Object.keys(params[paramName]) : params[paramName];
            }
            if (typeof attributes.rename_to === 'string') {
                data[attributes.rename_to] = paramData;
            }
            else {
                var formatted = toSnakeCase(paramName);
                data[formatted] = paramData;
            }
        }
    }
}
function toSnakeCase(param) {
    if (param === 'IPAddress') {
        return 'ip_address';
    }
    else {
        return param.split(/(?=[A-Z])/).join('_').toLowerCase();
    }
}
function loadWhitelist(source) {
    var doc = source;
    if (doc.services === undefined) {
        throw new Error('Document formatting is incorrect. Expecting "services" param.');
    }
    return doc.services;
}
module.exports = CallCapturer;
