
const ChatContext = require('./context.js').ChatContext
    ,ChatInfo = require('./context.js').ChatInfo
    ,Command = require('./context.js').Command
    ,Room = require('./room.js').Room
    ,Chatter = require('./chatter.js').Chatter
    ,PrivateMessageRoom = require('./room.js').PrivateMessageRoom;

/**
 * @constructor
 * @extends {ChatInfo}
**/
function SlackTeam(teamId) {
    ChatInfo.call(this, teamId);
    /** @type {string} */
    this.domain;
    /** @type {string} */
    this.callApp;
    /** @type {string} */
    this.callAppName;
    /** @type {boolean} */
    this.fileUploadPermission;
    /** @type {boolean} */
    this.fileEditPermission;
    /** @type {boolean} */
    this.fileDeletePermission;
    /** @type {string} */
    this.icons = {
        small: ""
        ,large: ""
    };
};
SlackTeam.prototype = Object.create(ChatInfo.prototype);
SlackTeam.prototype.constructor = SlackTeam;

SlackTeam.prototype.toStatic = function(t) {
    var res = ChatInfo.prototype.toStatic.call(this, t);
    if (res) {
        res["domain"] = this.domain
        res["prefs"] = {
            "calling_app_id": this.callApp
            ,"calling_app_name": this.callAppName
            ,"disable_file_uploads": this.fileUploadPermission
            ,"disable_file_editing": this.fileEditPermission
            ,"disable_file_deleting": this.fileDeletePermission
        }
        res["icon"] = {
            "small": this.icons.small
            ,"large": this.icons.large
        };
    }
    return res;
};

SlackTeam.prototype.update = function(teamData, t) {
    ChatInfo.prototype.update.call(this, teamData, t);
    if (teamData["domain"] !== undefined) this.domain = teamData["domain"];
    if (teamData["prefs"]) {
        this.callApp = teamData["prefs"]["calling_app_id"];
        this.callAppName = teamData["prefs"]["calling_app_name"];
        this.fileUploadPermission = teamData["prefs"]["disable_file_uploads"];
        this.fileEditPermission = teamData["prefs"]["disable_file_editing"];
        this.fileDeletePermission = teamData["prefs"]["disable_file_deleting"];
    }
    if (teamData["icon"]) {
        this.icons.small = teamData["icon"]["image_34"];
        this.icons.large = teamData["icon"]["image_230"];
    }
};

/**
 * @constructor
**/
function SlackChan(chanId, isGroup) {
    Room.call(this, chanId);
    this.isPrivate = isGroup;
};

SlackChan.prototype = Object.create(Room.prototype);
SlackChan.prototype.constructor = SlackChan;

SlackChan.prototype.setNameFromMembers = function() {
    var userNames = [];
    for (var i in this.users)
        if (!this.users[i].deleted)
            userNames.push(this.users[i].name);
    userNames.sort();
    this.name = userNames.join(", ");
};

/**
 * @constructor
 * @extends {PrivateMessageRoom}
 * @param {string} id
 * @param {SlackChatter} user
**/
function SlackIms(id, user) {
    PrivateMessageRoom.call(this, id, user);
};
SlackIms.prototype = Object.create(PrivateMessageRoom.prototype);
SlackIms.prototype.constructor = SlackIms;

/**
 * @constructor
 * @extends {Chatter}
**/
function SlackChatter(id) {
    Chatter.call(this, id);
};
SlackChatter.prototype = Object.create(Chatter.prototype);
SlackChatter.prototype.constructor = SlackChatter;

SlackChatter.prototype.setPresence = function(presenceStr, t) {
    this.presence = presenceStr !== 'away';
    this.version = Math.max(t, this.version);
};

/**
 * @constructor
 * @extends {SlackChatter}
**/
function SlackUser(id) {
    SlackChatter.call(this, id);
};
SlackUser.prototype = Object.create(SlackChatter.prototype);
SlackUser.prototype.constructor = SlackUser;

SlackUser.prototype.update = function(data, t) {
    SlackChatter.prototype.update.call(this, data, t);
    if (data["profile"]) {
        this.icons.small = data["profile"]["image_48"];
        this.icons.large = data["profile"]["image_512"];
        this.email = data["profile"]["email"];
        this.firstName = data["profile"]["first_name"];
        this.lastName = data["profile"]["last_name"];
    }
};

/**
 * @constructor
 * @extends {SlackChatter}
**/
function SlackBot(id) {
    SlackChatter.call(this, id);
    /** @type {string} */
    this.appId;
    this.isBot = true;
};
SlackBot.prototype = Object.create(SlackChatter.prototype);
SlackBot.prototype.constructor = SlackBot;

/** @param {*} botData */
SlackBot.prototype.update = function(botData, t) {
    SlackChatter.prototype.update.call(this, botData, t);
    if (botData["app_id"] !== undefined) this.appId = botData["app_id"];
    this.isBot = true;
};

/**
 * @constructor
**/
function SlackData(slack) {
    ChatContext.call(this);

    /**
     * Node serv handler
     * @type {*}
    **/
    this.slack = slack;
};
SlackData.prototype = Object.create(ChatContext.prototype);
SlackData.prototype.constructor = SlackData;

/**
 * @param {*} data
**/
SlackData.prototype.updateStatic = function(data, t) {
    if (data["bots"]) for (var i =0, nbBots = data["bots"].length; i < nbBots; i++) {
        var botObj = this.users[data["bots"][i]["id"]];
        if (!botObj)
            botObj = this.users[data["bots"][i]["id"]] = new SlackBot(data["bots"][i]["id"]);
        botObj.update(data["bots"][i], t);
    }
    ChatContext.prototype.updateStatic.call(this, data, t);
    if (data["ims"]) for (var i =0, nbIms = data["ims"].length; i < nbIms; i++) {
        var user = this.users[data["ims"][i]["user"]];
        if (user) {
            if (!this.channels[data["ims"][i]["id"]])
                this.channels[data["ims"][i]["id"]] = new SlackIms(data["ims"][i]["id"], user);
            this.channels[data["ims"][i]["id"]].update(data["ims"][i], t);
        }
    }
    for (var i =0, nbGroups = data["groups"].length; i < nbGroups; i++) {
        var groupData = data["groups"][i]
            ,groupObj = this.channels[groupData["id"]];

        if (!groupObj)
            groupObj = this.channels[groupData["id"]] = new SlackChan(groupData["id"], true);
        groupObj.update(groupData, this, t);
        groupObj.archived |= groupData["is_open"] === false;
        groupObj.isMember = true;
        if (groupData["is_mpim"])
            groupObj.setNameFromMembers();
    }
};

SlackData.prototype.userFactory = function(userData) {
    return new SlackUser(userData["id"]);
};

SlackData.prototype.roomFactory = function(roomData) {
    return new SlackChan(roomData["id"], false);
};

SlackData.prototype.teamFactory = function(id) {
    return new SlackTeam(id);
};

SlackData.prototype.commandFactory = function(data) {
    var getServiceName = (function() {
        if (data["service_name"])
            return data["service_name"];
        else if (data["app"]) {
            for (var i in this.users)
                if (this.users[i].appId === data["app"] && this.users[i].name)
                    return this.users[i].name;
            console.error("Unknown app " +data["app"]);
            return "";
        }
        return "Slack";
    }).bind(this);
    data["category"] = data["category"] || getServiceName();
    return new Command(data);
};

/**
 * @param {*} msg
 * @param {number} t
**/
SlackData.prototype.onMessage = function(msg, t) {
    if (msg["type"] === "presence_change") {
        var member = this.users[msg["user"]];
        if (member)
            member.setPresence(msg["presence"], t);
        this.staticV = Math.max(this.staticV, t);
    } else if (msg["type"] === "user_typing") {
        this.typing[msg["channel"]] = this.typing[msg["channel"]] || {};
        this.typing[msg["channel"]][msg["user"]] = t;
        this.staticV = Math.max(this.staticV, t);
    } else if (msg["type"] === "im_marked" || msg["type"] === "channel_marked" || msg["type"] === "group_marked") {
        var channel = this.channels[msg["channel"]];
        if (channel) {
            channel.lastRead = parseFloat(msg["ts"]);
            this.staticV = channel.version = t;
        }
    }
};

/**
 * @param {number} knownVersion
 * @param {number} now time at update check
 * @return {Object|undefined}
**/
SlackData.prototype.getUpdates = function(knownVersion, now) {
    if (this.staticV > knownVersion)
        return this.toStatic(knownVersion, now);
    return undefined;
};

/** @suppress {undefinedVars,checkTypes} */
(function() {
    if (typeof module !== "undefined") {
        module.exports.SlackData = SlackData;
    }
})();

