'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;
