/* global APP */
/**
 * Implements API class that communicates with external api class
 * and provides interface to access Jitsi Meet features by external
 * applications that embed Jitsi Meet
 */

/**
 * List of the available commands.
 * @type {{
 *              displayName: inputDisplayNameHandler,
 *              toggleAudio: toggleAudio,
 *              toggleVideo: toggleVideo,
 *              toggleFilmStrip: toggleFilmStrip,
 *              toggleChat: toggleChat,
 *              toggleContactList: toggleContactList
 *          }}
 */
var commands = {};

function initCommands() {
    commands = {
        displayName: APP.UI.inputDisplayNameHandler,
        toggleAudio: APP.conference.toggleAudioMuted,
        toggleVideo: APP.conference.toggleVideoMuted,
        toggleFilmStrip: APP.UI.toggleFilmStrip,
        toggleChat: APP.UI.toggleChat,
        toggleContactList: APP.UI.toggleContactList
    };
}


/**
 * Maps the supported events and their status
 * (true it the event is enabled and false if it is disabled)
 * @type {{
 *              incomingMessage: boolean,
 *              outgoingMessage: boolean,
 *              displayNameChange: boolean,
 *              participantJoined: boolean,
 *              participantLeft: boolean
 *      }}
 */
const events = {
    incomingMessage: false,
    outgoingMessage:false,
    displayNameChange: false,
    participantJoined: false,
    participantLeft: false
};

/**
 * Processes commands from external application.
 * @param message the object with the command
 */
function processCommand(message) {
    if (message.action != "execute") {
        console.error("Unknown action of the message");
        return;
    }
    for (var key in message) {
        if(commands[key])
            commands[key].apply(null, message[key]);
    }
}

/**
 * Processes events objects from external applications
 * @param event the event
 */
function processEvent(event) {
    if (!event.action) {
        console.error("Event with no action is received.");
        return;
    }

    var i = 0;
    switch(event.action) {
        case "add":
            for (; i < event.events.length; i++) {
                events[event.events[i]] = true;
            }
            break;
        case "remove":
            for (; i < event.events.length; i++) {
                events[event.events[i]] = false;
            }
            break;
        default:
            console.error("Unknown action for event.");
    }
}

/**
 * Sends message to the external application.
 * @param object
 */
function sendMessage(object) {
    window.parent.postMessage(JSON.stringify(object), "*");
}

/**
 * Processes a message event from the external application
 * @param event the message event
 */
function processMessage(event) {
    var message;
    try {
        message = JSON.parse(event.data);
    } catch (e) {}

    if(!message.type)
        return;
    switch (message.type) {
        case "command":
            processCommand(message);
            break;
        case "event":
            processEvent(message);
            break;
        default:
            console.error("Unknown type of the message");
            return;
    }
}

/**
 * Check whether the API should be enabled or not.
 * @returns {boolean}
 */
function isEnabled () {
    let hash = location.hash;
    return hash && hash.indexOf("external=true") > -1 && window.postMessage;
}

/**
 * Checks whether the event is enabled ot not.
 * @param name the name of the event.
 * @returns {*}
 */
function isEventEnabled (name) {
    return events[name];
}

/**
 * Sends event object to the external application that has been subscribed
 * for that event.
 * @param name the name event
 * @param object data associated with the event
 */
function triggerEvent (name, object) {
    if (isEnabled() && isEventEnabled(name)) {
        sendMessage({
            type: "event",
            action: "result",
            event: name,
            result: object
        });
    }
}

export default {
    /**
     * Initializes the APIConnector. Setups message event listeners that will
     * receive information from external applications that embed Jitsi Meet.
     * It also sends a message to the external application that APIConnector
     * is initialized.
     */
    init: function () {
        if (!isEnabled()) {
            return;
        }
        initCommands();
        if (window.addEventListener) {
            window.addEventListener('message', processMessage, false);
        } else {
            window.attachEvent('onmessage', processMessage);
        }
        sendMessage({type: "system", loaded: true});
    },

    /**
     * Notify external application (if API is enabled) that message was sent.
     * @param {string} body message body
     */
    notifySendingChatMessage (body) {
        triggerEvent("outgoingMessage", {"message": body});
    },

    /**
     * Notify external application (if API is enabled) that
     * message was received.
     * @param {string} id user id
     * @param {string} nick user nickname
     * @param {string} body message body
     * @param {number} ts message creation timestamp
     */
    notifyReceivedChatMessage (id, nick, body, ts) {
        if (APP.conference.isLocalId(id)) {
            return;
        }

        triggerEvent(
            "incomingMessage",
            {"from": id, "nick": nick, "message": body, "stamp": ts}
        );
    },

    /**
     * Notify external application (if API is enabled) that
     * user joined the conference.
     * @param {string} id user id
     */
    notifyUserJoined (id) {
        triggerEvent("participantJoined", {id});
    },

    /**
     * Notify external application (if API is enabled) that
     * user left the conference.
     * @param {string} id user id
     */
    notifyUserLeft (id) {
        triggerEvent("participantLeft", {id});
    },

    /**
     * Notify external application (if API is enabled) that
     * user changed their nickname.
     * @param {string} id user id
     * @param {string} displayName user nickname
     */
    notifyDisplayNameChanged (id, displayName) {
        triggerEvent("displayNameChange", {id, displayname: displayName});
    },

    /**
     * Removes the listeners.
     */
    dispose: function () {
        if (!isEnabled()) {
            return;
        }

        if (window.removeEventListener) {
            window.removeEventListener("message", processMessage, false);
        } else {
            window.detachEvent('onmessage', processMessage);
        }
    }
};