/* jshint sub: true */

var
    /**
     * @type {number} next period to wait before next retry in case of failure, in seconds
    **/
    NEXT_RETRY = 0,

    /**
     * @type {Room|null}
    **/
    SELECTED_ROOM = null,

    /**
     * @type {SimpleChatSystem|null}
    **/
    SELECTED_CONTEXT = null,

    /** @type {Message|null} */
    REPLYING_TO = null,

    /** @type {Message|null} */
    EDITING = null
;

function initHljs() {
    var xhr = new XMLHttpRequest();
    xhr.timeout = 1000 * 60 * 1; // 3 min timeout
    xhr.onreadystatechange = function(e) {
        if (xhr.readyState === 4) {
            var script = document.createElement("script");

            script.innerHTML = xhr.response;
            script.language = "text/javascript";
            document.head.innerHTML += '<link href="hljs-androidstudio.css" rel="stylesheet"/>';
            document.body.appendChild(script);
        }
    };
    xhr.open('GET', 'highlight.pack.js', true);
    xhr.send(null);
}

/**
 * @param {Room} room
 * @param {function(boolean)} cb
**/
function fetchHistory(room, cb) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'api/hist?room=' +room.id, true);
    xhr.send(null);
}

function onConfigUpdated() {
    if (!CONFIG.services.length) {
        Settings.setClosable(false).display(Settings.pages.services);
    }
}

function poll(callback) {
    var xhr = new XMLHttpRequest();
    xhr.timeout = 1000 * 60 * 1; // 3 min timeout
    xhr.onreadystatechange = function(e) {
        if (xhr.readyState === 4) {
            if (xhr.status === 0) {
                if (NEXT_RETRY) {
                    NEXT_RETRY = 0;
                    onNetworkStateUpdated(true);
                }
                poll(callback); // retry on timeout
                return;
            }
            var resp = null,
                success = Math.floor(xhr.status / 100) === 2;

            if (success) {
                if (NEXT_RETRY) {
                    NEXT_RETRY = 0;
                    onNetworkStateUpdated(true);
                }
                resp = xhr.response;
                try {
                    resp = JSON.parse(/** @type {string} */ (resp));
                } catch (exp) {
                    resp = null;
                }
            } else {
                if (NEXT_RETRY) {
                    NEXT_RETRY += Math.floor((NEXT_RETRY || 5)/2);
                    NEXT_RETRY = Math.min(60, NEXT_RETRY);
                } else {
                    NEXT_RETRY = 5;
                    onNetworkStateUpdated(false);
                }
            }
            callback(success, resp);
        }
    };
    xhr.open('GET', 'api?v=' +DATA.lastServerVersion, true);
    xhr.send(null);
}

function outOfSync() {
    DATA.lastServerVersion = 0;
}

/**
 * @param {Room} room
**/
function sendTyping(room) {
    var xhr = new XMLHttpRequest(),
        url = 'api/typing?room=' +room.id;
    xhr.open('POST', url, true);
    xhr.send(null);
}

/**
 * @param {boolean} success
 * @param {*} response
**/
function onPollResponse(success, response) {
    if (success) {
        if (response) {
            DATA.update(response);
        }
        startPolling();
    } else {
        setTimeout(startPolling, NEXT_RETRY * 1000);
    }
}

function startPolling() {
    poll(onPollResponse);
}

/**
 * @param {Room} room
**/
function selectRoom(room) {
    if (SELECTED_ROOM)
        unselectRoom();
    document.getElementById("room_" +room.id).classList.add(R.klass.selected);
    document.body.classList.remove(R.klass.noRoomSelected);
    SELECTED_ROOM = room;
    SELECTED_CONTEXT = /** @type {SimpleChatSystem} */ (DATA.context.getChannelContext(room.id));
    onRoomSelected();
    createContextBackground(SELECTED_CONTEXT.getChatContext().team.id, SELECTED_CONTEXT.getChatContext().users, function(imgData) {
        document.getElementById(R.id.context).style.backgroundImage = 'url(' +imgData +')';
    });
    if (SELECTED_ROOM.lastMsg !== 0 && !DATA.history[SELECTED_ROOM.id])
        fetchHistory(SELECTED_ROOM, function(success) {});
}

function unselectRoom() {
    document.getElementById("room_" +SELECTED_ROOM.id).classList.remove(R.klass.selected);
}

/**
 * @param {Room} chan
 * @param {string} filename
 * @param {File} file
 * @param {function(string?)} callback
**/
function uploadFile(chan, filename, file, callback) {
    var fileReader = new FileReader(),
        formData = new FormData(),
        xhr = new XMLHttpRequest();

    formData.append("file", file);
    formData.append("filename", filename);
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status === 204) {
                callback(null);
            } else {
                callback(xhr.statusText);
            }
        }
    };
    xhr.open('POST', 'api/file?room=' +chan.id);
    xhr.send(formData);
}

/**
 * @param {string} payload
 * @param {string} serviceId
 * @param {(function((string|null)))=} callback
**/
function sendCommand(payload, serviceId, callback) {
    var xhr = new XMLHttpRequest();

    if (callback) {
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status === 204) {
                    callback(null);
                } else {
                    callback(xhr.statusText);
                }
            }
        };
    }
    xhr.open('POST', "api/attachmentAction?serviceId=" +serviceId);
    xhr.send(JSON.stringify(payload));
}

function getActionPayload(channelId, msg, attachment, action) {
    var payload = {
        "actions": [ action ],
        "attachment_id": attachment["id"],
        "callback_id": attachment["callback_id"],
        "channel_id": channelId,
        "is_ephemeral": msg instanceof NoticeMessage,
        "message_ts": msg["id"]
    };
    return payload;
}

/**
 * @param {Room} chan
 * @param {Command!} cmd
 * @param {string} args
**/
function doCommand(chan, cmd, args) {
    var xhr = new XMLHttpRequest(),
        url = 'api/cmd?room=' +chan.id +"&cmd=" +encodeURIComponent(cmd.name.substr(1)) +"&args=" +encodeURIComponent(args);
    xhr.open('POST', url, true);
    xhr.send(null);
}

/**
 * @param {Room} chan
 * @param {string} msg
 * @param {Message|null=} replyTo
**/
function sendMsg(chan, msg, replyTo) {
    var xhr = new XMLHttpRequest();
    var url = 'api/msg?room=' +chan.id +"&text=" +encodeURIComponent(msg);
    if (replyTo) {
        var sender = DATA.context.getUser(replyTo.userId),
            footer = chan.isPrivate ? locale.message : chan.name;

        var attachment = {
            "fallback": replyTo.text,
            "author_name": sender.name,
            "text": replyTo.text,
            "footer": footer,
            "ts": replyTo.ts
        };
        url += "&attachments=" +encodeURIComponent(JSON.stringify([attachment]));
    }
    xhr.open('POST', url, true);
    xhr.send(null);
}

/**
 * @param {string} input
 * @param {boolean=} skipCommand
 * @return {boolean} true on recognized input
**/
function onTextEntered(input, skipCommand) {
    var success = true;
    if (EDITING) {
        editMsg(SELECTED_ROOM, input, EDITING);
        return true;
    }
    if (input[0] === '/' && skipCommand !== true) {
        var endCmd = input.indexOf(' '),
            cmd = input.substr(0, endCmd === -1 ? undefined : endCmd),
            args = endCmd === -1 ? "" : input.substr(endCmd),
            ctx = SELECTED_CONTEXT,
            cliCmdObject = CLIENT_COMMANDS.getCommand(cmd);

        if (cliCmdObject) {
            cliCmdObject.exec(ctx, SELECTED_ROOM, args.trim());
            return true;
        } else if (ctx) {
            var cmdObject = ctx.getChatContext().commands.data[cmd];

            if (cmdObject) {
                doCommand(SELECTED_ROOM, cmdObject, args.trim());
                return true;
            }
        }
        return false;
    }
    sendMsg(SELECTED_ROOM, input, REPLYING_TO);
    return true;
}

/**
 * @param {Room} chan
 * @param {string} text
 * @param {Message|null=} msg
**/
function editMsg(chan, text, msg) {
    var xhr = new XMLHttpRequest();
    var url = 'api/msg?room=' +chan.id +"&ts=" +msg.id +"&text=" +encodeURIComponent(text);
    xhr.open('PUT', url, true);
    xhr.send(null);
}

/**
 * @param {Room} chan
 * @param {Message|null=} msg
**/
function removeMsg(chan, msg) {
    var xhr = new XMLHttpRequest();
    var url = 'api/msg?room=' +chan.id +"&ts=" +msg.id;
    xhr.open('DELETE', url, true);
    xhr.send(null);
}

/**
 * @param {Room} chan
 * @param {string} id
 * @param {number} ts
**/
function sendReadMarker(chan, id, ts) {
    var xhr = new XMLHttpRequest();
    var url = 'api/markread?room=' +chan.id +"&id=" +id +"&ts=" +ts;
    xhr.open('POST', url, true);
    xhr.send(null);
}

/**
 * @param {string} channelId
 * @param {string} msgId
 * @param {string} reaction
**/
function addReaction(channelId, msgId, reaction) {
    var xhr = new XMLHttpRequest();
    var url = 'api/reaction?room=' +channelId +"&msg=" +msgId +"&reaction=" +encodeURIComponent(reaction);
    xhr.open('POST', url, true);
    xhr.send(null);
}

/**
 * @param {string} channelId
 * @param {string} msgId
 * @param {string} reaction
**/
function removeReaction(channelId, msgId, reaction) {
    var xhr = new XMLHttpRequest();
    var url = 'api/reaction?room=' +channelId +"&msg=" +msgId +"&reaction=" +encodeURIComponent(reaction);
    xhr.open('DELETE', url, true);
    xhr.send(null);
}

