‘use strict’;

function arrayToObject(parameters) {

const keyValue = {};
parameters.forEach((parameter) =>{
    const name = parameter.name;
    delete parameter.name;
    keyValue[name] = parameter;
});
return keyValue;

}

function decorate(to, category, object) {

to.category = category;
Object.keys(object).forEach((field) => {
    // skip the 'name' field as it is part of the function prototype
    if (field === 'name') {
        return;
    }
    // commands and events have parameters whereas types have properties
    if (category === 'type' && field === 'properties' ||
        field === 'parameters') {
        to[field] = arrayToObject(object[field]);
    } else {
        to[field] = object[field];
    }
});

}

function addCommand(chrome, domainName, command) {

const commandName = `${domainName}.${command.name}`;
const handler = (params, sessionId, callback) => {
    return chrome.send(commandName, params, sessionId, callback);
};
decorate(handler, 'command', command);
chrome[commandName] = chrome[domainName][command.name] = handler;

}

function addEvent(chrome, domainName, event) {

const eventName = `${domainName}.${event.name}`;
const handler = (sessionId, handler) => {
    if (typeof sessionId === 'function') {
        handler = sessionId;
        sessionId = undefined;
    }
    const rawEventName = sessionId ? `${eventName}.${sessionId}` : eventName;
    if (typeof handler === 'function') {
        chrome.on(rawEventName, handler);
        return () => chrome.removeListener(rawEventName, handler);
    } else {
        return new Promise((fulfill, reject) => {
            chrome.once(rawEventName, fulfill);
        });
    }
};
decorate(handler, 'event', event);
chrome[eventName] = chrome[domainName][event.name] = handler;

}

function addType(chrome, domainName, type) {

const typeName = `${domainName}.${type.id}`;
const help = {};
decorate(help, 'type', type);
chrome[typeName] = chrome[domainName][type.id] = help;

}

function prepare(object, protocol) {

// assign the protocol and generate the shorthands
object.protocol = protocol;
protocol.domains.forEach((domain) => {
    const domainName = domain.domain;
    object[domainName] = {};
    // add commands
    (domain.commands || []).forEach((command) => {
        addCommand(object, domainName, command);
    });
    // add events
    (domain.events || []).forEach((event) => {
        addEvent(object, domainName, event);
    });
    // add types
    (domain.types || []).forEach((type) => {
        addType(object, domainName, type);
    });
    // add utility listener for each domain
    object[domainName].on = (eventName, handler) => {
        return object[domainName][eventName](handler);
    };
});

}

module.exports.prepare = prepare;