<?php

/*
  __PocketMine Plugin__
  name=ServerMail
  description=Send mail to players
  version=1.2
  author=tschrock
  class=ServerMail
  apiversion=12
 */

class ServerMail implements Plugin {

    private $api, $config;

    const CONFIG_NPMESSAGE = "newPlayerMessage";
    const CONFIG_MAXMESSAGE = "maxMessagesToPlayer";
    const CONFIG_SIMILARLIM = "similarLimit";

    public function __construct(ServerAPI $api, $server = false) {
        $this->api = $api;

        if ($this->api->loadAPI("mail", "inst_ServerMailAPI") !== false) {
            $this->api->mail->setPlugin($this);
        }

        ServerMailAPI::setPlugin($this);
    }

    public function init() {

        $this->config = new Config($this->api->plugin->configPath($this) . "config.yml", CONFIG_YAML, array(
            ServerMail::CONFIG_NPMESSAGE => "Welcome to the Server!",
            ServerMail::CONFIG_MAXMESSAGE => 10,
            ServerMail::CONFIG_SIMILARLIM => 0.90,
        ));

        @mkdir($this->api->plugin->configPath($this) . "players/");


        $this->api->addHandler("player.connect", array($this, "eventHandler"));

        if (class_exists("SimpleAuth")) {
            $this->api->addHandler("simpleauth.login", array($this, "eventHandler"));
        } else {
            $this->api->addHandler("player.spawn", array($this, "eventHandler"));
        }

        $this->api->console->register("mail", "<read|clear> or /mail send <player> <message>", array($this, "commandHandler"));
    }

    public function commandHandler($cmd, $params, $issuer, $alias) {
        if ($cmd == "mail") {
            switch (strtolower(array_shift($params))) {
                case "read":  // fallthrough
                case "view":
                    $messages = $this->getMessages($this->getUserName($issuer));
                    $this->sendChat($issuer, "[ServerMail] You have " . count($messages) . " messages:");
                    foreach ($messages as $message) {
                        $this->sendChat($issuer, "    " . $message["sender"] . ": " . $message["message"]);
                    }
                    break;
                case "clear":
                    $this->clearMessages($this->getUserName($issuer));
                    $this->sendChat($issuer, "[ServerMail] All messages cleared");
                    break;
                case "send":
                    $sender = $this->getUserName($issuer);
                    $recipiant = strtolower(array_shift($params));
                    $message = implode(" ", $params);

                    if ($recipiant != NULL && $message != NULL) {
                        if ($this->checkUser($recipiant)) {

                            if ($this->isMessageSimilar($sender, $recipiant, $message)) {
                                $this->sendChat($issuer, "[ServerMail] You already sent a message like that!");
                            } else {
                                $msgCount = $this->countMessagesFromPlayer($sender, $recipiant);
                                $msgCountMax = $this->config->get(ServerMail::CONFIG_MAXMESSAGE);
                                if ($msgCount > $msgCountMax) {
                                    $this->sendChat($issuer, "[ServerMail] You have reached your message limit to $recipiant! (" . ($msgCount-1) . "/$msgCountMax)");
                                } else {
                                    $this->addMessage($recipiant, $sender, $message);
                                    $this->sendChat($issuer, "[ServerMail] Message sent! ($msgCount/$msgCountMax)");
                                }
                            }
                        } else {
                            $this->sendChat($issuer, "[ServerMail] $recipiant has no mailbox!");
                        }
                    } else {
                        $this->sendChat($issuer, "Usage: /mail send <player> <message>");
                    }

                    break;
                case "broadcast":

                //break;
                default:
                    $this->sendChat($issuer, "Usage: /mail <view|read|clear|send>");
            }
        }
    }

    public function eventHandler($data, $event) {
        switch ($event) {
            case "player.connect":

                break;
            case "simpleauth.login":
            case "player.spawn":

                $messagecount = $this->getMessageCount($data->iusername);

                if ($messagecount == 0) {
                    $data->sendChat("[ServerMail] You have no messages.");
                } else {
                    $data->sendChat("[ServerMail] You have " . $messagecount . " messages.");
                    $data->sendChat("Use '/mail read' to see them. ");
                }
                break;
        }
    }

    public function getMessageCount($player) {
        $d = $this->getData($player);
        if ($d === false){
            return false;
        }
        $c = count($d->get("messages"));
        if ($d->get("firstrun")) {
            $c = $c + 1;
        }
        return $c;
    }

    public function getMessages($player) {
        $d = $this->getData($player);
        if ($d === false){
            return false;
        }
        $m = $d->get("messages");
        if ($d->get("firstrun")) {
            $m[] = array(
                "sender" => "Server",
                "message" => $this->config->get(ServerMail::CONFIG_NPMESSAGE),
            );
        }
        return $m;
    }

    public function addMessage($player, $sender, $message) {
        $d = $this->getData($player);
        if ($d === false){
            return false;
        }
        $e = $d->get("messages");
        $e[] = array(
            "sender" => "$sender",
            "message" => "$message",
        );
        $d->set("messages", $e);
        $d->save();
    }

    public function clearMessages($player) {
        $d = $this->getData($player);
        if ($d === false){
            return false;
        }
        $d->remove("messages");
        $d->set("firstrun", false);
        $d->save();
    }

    public function getData($player) {
        if ($player instanceof Player) {
            $iusername = $player->iusername;
        } elseif (is_string($player)) {
            $iusername = $player;
        }
        else {
            return false;
        }

        $iusername = strtolower($iusername);
        if (!file_exists($this->api->plugin->configPath($this) . "players/" . $iusername{0} . "/$iusername.yml")) {
            @mkdir($this->api->plugin->configPath($this) . "players/" . $iusername{0} . "/");
            $d = new Config($this->api->plugin->configPath($this) . "players/" . $iusername{0} . "/" . $iusername . ".yml", CONFIG_YAML, array(
                "firstrun" => true,
                "messages" => array(),
            ));

            $d->save();
            return $d;
        }
        return new Config($this->api->plugin->configPath($this) . "players/" . $iusername{0} . "/" . $iusername . ".yml", CONFIG_YAML, array(
            "firstrun" => true,
            "messages" => array(),
        ));
    }

    public function checkUser($name) {
        $name = strtolower($name);
        return file_exists(dirname(dirname($this->api->plugin->configPath($this))) . "/players/$name.yml");
    }

    public function isMessageSimilar($fromPlayer, $toPlayer, $newmessage) {

        $limit = $this->config->get(ServerMail::CONFIG_SIMILARLIM);

        #console("limit:$limit");
        #console("1 - limit:" . 1 - $limit);

        if ($limit == 0) {
            return false;
        }

        $messages = $this->getMessages($toPlayer);
        foreach ($messages as $message) {
            if ($message["sender"] == $fromPlayer) {

                if ($this->compareStrings($message["message"], $newmessage) <= (1 - $limit)) {
                    return true;
                }
            }
        }

        return false;
    }

    public function compareStrings($str1, $str2) {
        $str1m = metaphone($str1);
        $str2m = metaphone($str2);

        #console("str1m:$str1m");
        #console("str2m:$str2m");

        $dist = levenshtein($str1m, $str2m);

        #console("dist:$dist");
        #console("return:" . $dist / max(strlen($str1m), strlen($str2m)));

        return $dist / max(strlen($str1m), strlen($str2m));
    }

    public function sendChat($to, $message) {
        if ($to instanceof Player) {
            $to->sendChat($message);
        } else {
            console($message);
        }
    }

    public function getUserName($issuer) {
        if ($issuer instanceof Player) {
            return $issuer->iusername;
        } else {
            return "Console";
        }
    }

    public function countMessagesFromPlayer($fromPlayer, $toPlayer) {
        $mcount = 0;
        $messages = $this->getMessages($toPlayer);
        foreach ($messages as $message) {
            if ($message["sender"] == $fromPlayer) {
                $mcount++;
            }
        }
        return $mcount;
    }

    public function __destruct() {
        
    }

}

class inst_ServerMailAPI {

    private $serverMailPlugin;

    function setPlugin(ServerMail $serverMailPlugin) {
        $this->serverMailPlugin = $serverMailPlugin;
    }

    public function getMessageCount($player) {
        return $this->serverMailPlugin->getMessageCount($player);
    }

    public function getMessages($player) {
        return $this->serverMailPlugin->getMessages($player);
    }

    public function addMessage($player, $sender, $message) {
        $this->serverMailPlugin->addMessage($player, $sender, $message);
    }

    public function clearMessages($player) {
        return $this->serverMailPlugin->clearMessages($player);
    }

}

class ServerMailAPI {

    static private $serverMailPlugin;

    static function setPlugin(ServerMail $serverMailPlugin) {
        ServerMailAPI::$serverMailPlugin = $serverMailPlugin;
    }

    static public function getMessageCount($player) {
        return ServerMailAPI::$serverMailPlugin->getMessageCount($player);
    }

    static public function getMessages($player) {
        return ServerMailAPI::$serverMailPlugin->getMessages($player);
    }

    static public function addMessage($player, $sender, $message) {
        ServerMailAPI::$serverMailPlugin->addMessage($player, $sender, $message);
    }

    static public function clearMessages($player) {
        return ServerMailAPI::$serverMailPlugin->clearMessages($player);
    }

}
