/*
WARNING: THIS IS STILL EXPERIMENTAL STUFF
I want to have the ability to assign specific behaviors to each room without messing with the main engine
So I'm creating a module for server-side modifications (mods). There is one also for the client.
Their naming convention is roomIdFunction.
The functions are called by the engine at crucial points, only if they exist.
*/

//called at the beginning
module.exports.initMod = function (io, gameState, DATA) {
    console.log("MOD: Initialized");

    //EVERYTHING GLOBALLLLL
    global.rita = require('rita');
    global.gameState = gameState;
    global.io = io;
    global.DATA = DATA;

    //family room roles
    global.familyRoles = {
        wife: "",
        husband: "", //id of player
        child1: "",
        child2: "",
        child3: "",
        uncle: "",
        milkman: "",
        boyfriend: ""
    };

    global.lastRhymes = [];
    global.rhymingPlayers = {};
    global.beatPlaying = false;


    global.paranoidTalk = [
        "Hey you",
        "There are bots in here",
        "Are you a bot?",
        "Russia is controlling the bots",
        "Are you real?",
        "Yes",
        "I don't trust you",
        "This is weird",
        "Prove you are human",
        "No",
        "Have you seen that?",
        "That person is a bot",
        "Listen",
        "Bots everywhere",
        "Hello",
        "Another bot"
    ];

    //load extended dictionary, this is 3Mb but only sits on the server and it's used by only one room
    const fs = require('fs');
    global.dictionary = fs.readFileSync('dictionary.json');

    //cycle through contraints in the consonant room
    global.consonant = 0;
    setInterval(function () {
        global.consonant++;
        //aeiou-
        if (global.consonant > 5) {
            global.consonant = 0;
        }
        var msg = "";

        if (global.consonant == 0) //a
            msg = "All art appalls a fan";
        if (global.consonant == 1) //e
            msg = "Greet her when she enters";
        if (global.consonant == 2) //i
            msg = "I sit ildly till twilight";
        if (global.consonant == 3) //o
            msg = "No stools, no books: work protocol";
        if (global.consonant == 4) //u
            msg = "But truth: dull suburbs turn fun";
        if (global.consonant == 5) //none
            msg = "Tsk, tsk... try my rhythms";


        //sends a message to the room
        io.to("cnsnntrm").emit('nonPlayerTalked', { id: "", labelColor: "#3e7eb0", room: "cnsnntrm", message: msg, x: 36, y: 56 });

    }, 60 * 1000); //every minute changes

    //global function ffs
    global.random = function (min, max) {
        return Math.random() * (max - min) + min;
    }


    //Example of NPC creation and behavior

    var npc = new NPC(
        {
            id: "paranoid",
            nickName: "Anonymous",
            room: "secondFloor",
            x: 23,
            y: 78,
            avatar: 1,
            colors: [2, 2, 1, 5],
            labelColor: "#1e839d"
        });

    npc.behavior = setTimeout(function ramble() {
        var dice = random(0, 100);

        if (dice < 40) {
            npc.talk(global.paranoidTalk[Math.floor(random(0, global.paranoidTalk.length - 1))]);

            npc.behavior = setTimeout(ramble, random(7000, 9000));
        }
        else if (dice < 60) {
            npc.move(random(17, 113) * 2, random(76, 98) * 2);
            npc.behavior = setTimeout(ramble, random(4000, 8000));
        }
        else {
            //just wait
            npc.behavior = setTimeout(ramble, random(1000, 3000));

            //to kill the bot
            //clearTimeout(npc.behavior);
            //npc.delete();
        }


    }, random(1000, 2000));


    global.VIPList = [];

}


//custom function called on the server side when a player successfully enters or exits the room
//executed before it's broadcast to the other players
module.exports.experimentsJoin = function (player, roomId) {
    //console.log("MOD: " + player.nickName + " entered room " + roomId);
}

module.exports.experimentsLeave = function (player, roomId) {
    //console.log("MOD: " + player.nickName + " exited room " + roomId);
}

//wouldn't it be funny if cetain rooms modified your messages?
module.exports.experimentsTalkFilter = function (player, message) {

    //console.log("MOD: " + player.nickName + " said " + message);
    //message = message.replace(/[aeiou]/ig, '');
    //make sure it returns a message
    return message;
}


//wouldn't it be funny if cetain rooms modified your messages?
module.exports.VIPRoomTalkFilter = function (player, message) {

    //console.log("MOD: " + player.nickName + " said " + message);
    message = global.rita.getPhonemes(message);
    message = message.replace(/-/g, "");
    //make sure it returns a message
    return message;
}

//wouldn't it be funny if cetain rooms modified your messages?
module.exports.cnsnntrmTalkFilter = function (player, message) {

    //console.log("MOD: " + player.nickName + " said " + message);

    if (global.consonant == 0) //a
        message = message.replace(/[eiou]/ig, 'a');
    if (global.consonant == 1) //e
        message = message.replace(/[aiou]/ig, 'e');
    if (global.consonant == 2) //i
        message = message.replace(/[aeou]/ig, 'i');
    if (global.consonant == 3) //o
        message = message.replace(/[aeiu]/ig, 'o');
    if (global.consonant == 4) //u
        message = message.replace(/[aeio]/ig, 'u');
    if (global.consonant == 5) //none
        message = message.replace(/[aeiou]/ig, '');


    //make sure it returns a message
    return message;
}

//words can only be used once 
module.exports.censorshipRoomTalkFilter = function (player, message) {

    //create a list of censored words
    if (global.forbiddenWords == null) {
        global.forbiddenWords = [];
    }

    //strip special characters
    message = message.replace(/[`~!@#$%^&*()_|+\-=?;:",.<>\{\}\[\]\\\/]/gi, '');

    //break down the message into words
    var words = message.split(" ");
    var censoredMessage = "";

    //check each single word
    for (var j = 0; j < words.length; j++) {

        /*
        //remove repeated character if they occur more than twice like hellooooo > hello
        var word = words[j];
        var pChar = "";
        var ppChar = "";
        var newWord = "";

        for (var k = 0; k < word.length; k++) {
            var newChar = word[k];

            if (pChar == "" || ppChar == "" || !(newChar == ppChar && newChar == pChar)) {
                newWord += newChar;
            }
            ppChar = pChar;
            pChar = newChar;
        }
        */

        var newWord = words[j];

        //found, censor
        if (forbiddenWords.indexOf(newWord.toLowerCase()) > -1) {
            var l = newWord.length;
            var bleep = "";
            for (var i = 0; i < l; i++) {
                bleep += "*";
            }

            censoredMessage += bleep;

        }
        else {
            censoredMessage += newWord;
            //not found add
            forbiddenWords.push(newWord.toLowerCase());
        }

        if (j < words.length - 1)
            censoredMessage += " ";
    }


    return censoredMessage;

}


module.exports.rhymeRoomTalkFilter = function (player, message) {
    //
    if (global.beat == null)
        global.beat = 1;

    var arr = message.split(" ");
    var lastWord = "";

    if (arr.length > 0)
        lastWord = arr[arr.length - 1].toLowerCase();

    //extended dictionary
    var exists = global.dictionary.indexOf(lastWord) != -1;

    var first = false;
    var lastRhyme = "";
    var used = false;


    if (global.lastRhymes.length == 0)
        first = true;
    else {
        used = global.lastRhymes.indexOf(lastWord) != -1;

        lastRhyme = global.lastRhymes[global.lastRhymes.length - 1].toLowerCase();

    }

    if (exists && !used) {

        var rhymes = false;

        //not first check the rhym
        if (!first)
            rhymes = global.rita.isRhyme(lastWord, lastRhyme);

        //start the battle
        if (first || rhymes) {

            if (global.beatPlaying == false) {

                io.to("rhymeRoom").emit('musicOn', global.beat);
                global.beatPlaying = true;
            }

            global.lastRhymes.push(lastWord);

            //create the rhyming player score
            if (global.rhymingPlayers[player.nickName] == null)
                global.rhymingPlayers[player.nickName] = 0;

            //calculate the score by counting the real words
            //skip the first
            if (global.lastRhymes.length > 1) {
                for (var i = 0; i < arr.length; i++) {
                    if (global.rita.containsWord(arr[i]))
                        global.rhymingPlayers[player.nickName]++;
                }
            }

            //console.log("YEAH " + player.nickName + " " + lastWord + "! Words uttered " + global.rhymingPlayers[player.nickName]);

            clearTimeout(global.rhymeTime);

            global.rhymeTime = setTimeout(function () {
                //console.log("Rhyme timeout");

                //send to everybody in the room
                io.to("rhymeRoom").emit('musicOff');
                global.beatPlaying = false;
                //change record
                global.beat++;
                if (global.beat > 3)
                    global.beat = 1;

                var highscore = 0;
                var winner = "";
                //find high score
                for (var nn in global.rhymingPlayers) {
                    if (global.rhymingPlayers[nn] >= 4 && global.rhymingPlayers[nn] > highscore) {
                        winner = nn;
                        highscore = global.rhymingPlayers[nn];
                    }
                }
                global.lastRhymes = [];
                global.rhymingPlayers = {};
                if (winner != "") {
                    io.to("rhymeRoom").emit('godMessage', winner + " wins!" + highscore + " words uttered");

                }
            }, 8000);

            return message;
        }//doesn't ryme
        else {
            return "...";
        }
    }//doesn't exist
    else {
        return "...";
    }
}

//if enters when music is playing sent 
module.exports.rhymeRoomJoin = function (playerObject, roomId) {

    if (io.sockets.sockets[playerObject.id] != null && global.beatPlaying) {
        io.sockets.sockets[playerObject.id].emit('musicEnter', global.beat);

    }

}

//if enters when music is playing sent 
module.exports.rhymeRoomLeave = function (playerObject, roomId) {

    if (io.sockets.sockets[playerObject.id] != null) {
        io.sockets.sockets[playerObject.id].emit('musicExit');

    }
}

module.exports.darkRoomTalkFilter = function (player, message) {
    //I should declare them at the init but whatev
    var nouns = ["ass", "climax", "coitus", "boner", "booty", "threesome", "tush", "lust", "orgy", "libido", "dildo", "kink",
        "porno", "buttplug", "cunnilingus", "cybersex", "sex", "cum", "orgasm", "quickie", "intercourse", "cock", "penis", "dick", "pussy", "fanny", "vagina", "clit", "butt"];
    var verbs = ["love", "shag", "mate", "seduce", "hook up", "hump", "arouse", "fornicate", "erect", "get some", "bone", "bang", "fuck", "lick", "suck", "cum", "penetrate", "screw", "sodomize", "arouse", "kiss", "pet", "masturbate", "come"];

    var arr = rita.tokenize(message);
    var replaced = false;

    for (var i = 0; i < arr.length && !replaced; i++) {
        var word = arr[i];
        //skip verbs 50% since they are more likely to come before nouns
        if (rita.isVerb(word) && Math.random() < 0.5) {
            arr[i] = rita.randomItem(verbs);
            replaced = true;
        }
        if (rita.isNoun(word)) {
            arr[i] = rita.randomItem(nouns);
            replaced = true;
        }

    }

    return arr.join(" ");
}

//player enters family room roles are assigned by the server
module.exports.familyRoomJoin = function (playerObject, roomId) {

    var foundRole = false;
    for (var roleId in global.familyRoles) {
        //role not assigned
        if (global.familyRoles[roleId] == "" && !foundRole) {
            foundRole = true;
            global.familyRoles[roleId] = playerObject.id;
            console.log(playerObject.id + " becomes " + roleId);
        }
    }

    if (!foundRole)
        console.log(playerObject.id + " becomes a fly");

    //assign a new role and send all the roles to the room

    io.to("familyRoom").emit('updateRoles', playerObject.id, global.familyRoles);

    //io.to("familyRoom").emit('assignRole', { id: playerObject.id, roleId: "wife", roleLabel: "Wife", rolePrompt: "You are feeling frustrated" });
    //send the existing roles
}

//exit > free up the role
//player enters family room roles are assigned by the server
module.exports.familyRoomLeave = function (playerObject, roomId) {

    for (var roleId in global.familyRoles) {
        //role not assigned
        if (global.familyRoles[roleId] == playerObject.id) {

            global.familyRoles[roleId] = "";
            console.log(roleId + " is now free");
        }
    }
    //I don't need to send updated roles
    //io.to("familyRoom").emit('updateRoles', playerObject.id, global.familyRoles);

}

//mute spectators on the server-side
module.exports.familyRoomTalkFilter = function (player, message) {
    var spectator = true;

    for (var roleId in global.familyRoles) {
        //role assigned
        if (global.familyRoles[roleId] == player.id) {
            spectator = false;
        }
    }

    if (spectator)
        return "zzzz";
    else
        return message;

}

module.exports.VIPRoomJoin = function (playerObject, roomId) {
    //console.log(playerObject.nickName + " enters the VIP room");
    //...
    global.VIPList.push(playerObject.id);
    if (global.VIPList.length > 3) {
        var expelled = global.VIPList.shift();

        //force leave
        if (io.sockets.sockets[expelled] != null) {

            this.transferPlayer(expelled, "VIPRoom", "likelikeOutside", 121 * 2, 89 * 2);
            io.to(expelled).emit('godMessage', "Sorry, we had to expel you to make room for " + playerObject.nickName);
        }

    }

}

module.exports.VIPRoomIntro = function (newComerId, introObj) {
    //the problem with the auto expulsion in VIPRoom is that the intro is sent before it's the other person is expelled
    //so the intros arrive too late creating ghosts.
    //since the server has the real list I can override the intro after the fact and expel the ghost. Ugly but necessary.

    //console.log("Obsolete intro? " + gameState.players[introObj.id].room);

    if (gameState.players[introObj.id].room != "VIPRoom")
        io.to("VIPRoom").emit("playerLeft", { id: introObj.id, room: "VIPRoom", disconnect: false });

}

//force change room
module.exports.transferPlayer = function (playerId, from, to, x, y) {
    //console.log(playerId + " is transfered to " + to);

    var s = io.sockets.sockets[playerId];
    var p = gameState.players[playerId];

    if (s != null)
        if (p.room != null) {

            //var from = p.room;
            s.leave(from);
            s.join(to);

            //broadcast the change to everybody in the current room
            //from the client perspective leaving the room is the same as disconnecting
            io.to(from).emit("playerLeft", { id: playerId, room: from, disconnect: false });

            //same for joining, sending everybody in the room the player state

            p.room = to;
            p.x = p.destinationX = x;
            p.y = p.destinationY = y;
            p.new = false;


            //check if there is a custom function in the MOD to call at this point
            if (this[from + "Leave"] != null) {
                //call it!
                this[from + "Leave"](p, from);
            }

            io.to(to).emit("playerJoined", p);


            //check if there is a custom function in the MOD to call at this point
            if (this[to + "Join"] != null) {
                //call it!
                this[to + "Join"](p, to);
            }

            //check if there are NPCs in this room and make them send info to the player
            for (var NPCId in gameState.NPCs) {
                var npc = gameState.NPCs[NPCId];

                if (npc.room == to) {
                    npc.sendIntroTo(playerId);
                }
            }

        }
}

//if a player leaves the room on their own accord make sure they are removed from the list as well
module.exports.VIPRoomLeave = function (playerObject, roomId) {
    //console.log(playerObject.nickName + " exits the VIP room");

    var index = global.VIPList.indexOf(playerObject.id);
    if (index !== -1) {
        global.VIPList.splice(index, 1);
    }

}


//a client can send generic action request to the server
//the action logic is defined in functions named "on"+ActionId like this one
//I don't want a hacked client to be able to call whatever function exists on the server mod hence the naming
//and I want send only an id without arguments to force all my logic here on the server side
module.exports.onTVInteract = function (pId) {
    //console.log("Action onTVInteract called by " + pId);

    //a persistent change to the game state: change the DATA sent to the new players
    //*persistent until server restarts

    var TVState = !DATA.ROOMS.familyRoom.things.TV.visible;
    //change the visibility
    DATA.ROOMS.familyRoom.things.TV.visible = TVState;
    //send a thing update too ALL clients, changing the client data and telling them to delete and recreate the sprite if they are in the room 
    io.sockets.emit("thingChanged", { thingId: "TV", room: "familyRoom", property: "visible", value: TVState });
}