/*
 *  The Mana World
 *  Copyright (C) 2009  The Mana World Development Team
 *  Copyright (C) 2009-2010  Andrei Karas
 *
 *  This file is part of The Mana World.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "spellmanager.h"
#include "being.h"
#include "log.h"
#include "localplayer.h"
#include "configuration.h"

#include "gui/chat.h"

#include "utils/dtor.h"
#include "utils/stringutils.h"

SpellManager::SpellManager()
{
    //fillSpells();
    load();
}

SpellManager::~SpellManager()
{
    delete_all(mSpells);
    mSpells.clear();
    mSpellsVector.clear();
//    save();
}

TextCommand* SpellManager::getSpell(int spellId)
{
    if (spellId < 0 || (unsigned int)spellId >= mSpells.size())
        return NULL;

    return mSpells[spellId];
}

TextCommand* SpellManager::getSpellByItem(int itemId)
{
    return getSpell(itemId - SPELL_MIN_ID);
}

void SpellManager::fillSpells()
{
//id, std::string name, std::string symbol, ST type, int basicLvl, MagicSchool school, int schoolLvl, int mana)

    addSpell(new TextCommand(0, "lum", "#lum", ALLOWTARGET,
             1, SKILL_MAGIC_LIFE, 0, 6));
    addSpell(new TextCommand(1, "inm", "#inma", NEEDTARGET,
             2, SKILL_MAGIC_LIFE, 2, 10));
    addSpell(new TextCommand(2, "fla", "#flar", NOTARGET,
             1, SKILL_MAGIC_WAR, 0, 10));
    addSpell(new TextCommand(3, "chi", "#chiza", NOTARGET,
             1, SKILL_MAGIC_WAR, 0, 9));
    addSpell(new TextCommand(4, "ing", "#ingrav", NOTARGET,
             2, SKILL_MAGIC_WAR, 2, 20));
    addSpell(new TextCommand(5, "fri", "#frillyar", NOTARGET,
             2, SKILL_MAGIC_WAR, 2, 25));
    addSpell(new TextCommand(6, "upm", "#upmarmu", NOTARGET,
             2, SKILL_MAGIC_WAR, 2, 20));
    addSpell(new TextCommand(7, "ite", "#itenplz", NOTARGET,
             1, SKILL_MAGIC_NATURE, 0, 3));
    addSpell(new TextCommand(8, "bet", "#betsanc", ALLOWTARGET,
             2, SKILL_MAGIC_NATURE, 2, 14));
    addSpell(new TextCommand(9, "abi", "#abizit", NOTARGET,
             1, SKILL_MAGIC, 0, 1));
    addSpell(new TextCommand(10, "inw", "#inwilt", NOTARGET,
             2, SKILL_MAGIC, 2, 7));
    addSpell(new TextCommand(11, "hi", "hi", NOTARGET));
    addSpell(new TextCommand(12, "hea", "heal", NOTARGET));
    addSpell(new TextCommand(13, "@sp", "@spawn maggot 10", NOTARGET));
    for (int f = 12; f < SPELL_SHORTCUT_ITEMS; f++)
    {
        addSpell(new TextCommand(f));
    }
}

bool SpellManager::addSpell(TextCommand *spell)
{
    std::map<unsigned int, TextCommand*>::iterator
        i = mSpells.find(spell->getId());
    if (i == mSpells.end())
    {
        mSpells[spell->getId()] = spell;
        mSpellsVector.push_back(spell);
        return true;
    }
    return false;
}

std::vector<TextCommand*> SpellManager::getAll()
{
    //logger->log(("mSpellsVector = " + toString(mSpellsVector.size())).c_str());
    return mSpellsVector;
}

void SpellManager::useItem(int itemId)
{
    invoke(itemId - SPELL_MIN_ID);
}

void SpellManager::invoke(int spellId)
{
    TextCommand* spell = getSpell(spellId);
    if (!spell)
        return;

    if (spell->getCommand() == "")
        return;

    if (spell->getCommandType() == TEXT_COMMAND_TEXT
        || (player_node->getAttributeEffective(player_node->MATK) > 0
        && player_node->getSkillLv(SKILL_MAGIC) >= spell->getBaseLvl()
        && player_node->getSkillLv(spell->getSchool()) >= spell->getSchoolLvl()
        && player_node->getMP() >= spell->getMana()))
    {
        Being* target = player_node->getTarget();
        if (spell->getTargetType() == NOTARGET)
        {
            invokeSpell(spell);
        }
        if ((target && (target->getType() != Being::MONSTER
            || spell->getCommandType() == TEXT_COMMAND_TEXT))
            && (spell->getTargetType() == ALLOWTARGET
            || spell->getTargetType() == NEEDTARGET))
        {
            invokeSpell(spell, target);
        }
        else if (spell->getTargetType() == ALLOWTARGET)
        {
            invokeSpell(spell);
        }
    }
}

void SpellManager::invokeSpell(TextCommand* spell)
{
    chatWindow->localChatInput(spell->getCommand());
}

void SpellManager::invokeSpell(TextCommand* spell, Being* target)
{
    chatWindow->localChatInput(spell->getCommand() + " " + target->getName());
}

TextCommand *SpellManager::createNewSpell()
{
    return new TextCommand(static_cast<unsigned>(mSpellsVector.size()));
}

void SpellManager::load(bool oldConfig)
{
    Configuration *cfg;
    if (oldConfig)
        cfg = &config;
    else
        cfg = &serverConfig;

    delete_all(mSpells);
    mSpells.clear();
    mSpellsVector.clear();

    if (cfg->getValue("commandShortcutFlags0", "") == "")
    {
        fillSpells();
        save();
        return;
    }

    unsigned int targetType;
    unsigned int basicLvl;
    unsigned int school;
    unsigned int schoolLvl;
    unsigned int mana;
    unsigned int commandType;

    for (int i = 0; i < SPELL_SHORTCUT_ITEMS; i++)
    {
        std::string flags =
            cfg->getValue("commandShortcutFlags" + toString(i), "");
        std::stringstream ss(flags);
        ss >> commandType;
        ss >> targetType;
        ss >> basicLvl;
        ss >> school;
        ss >> schoolLvl;
        ss >> mana;

        std::string cmd = cfg->getValue("commandShortcutCmd"
                                        + toString(i), "");
        std::string symbol = cfg->getValue("commandShortcutSymbol"
                                           + toString(i), "");

        if ((TextCommandType)commandType == TEXT_COMMAND_MAGIC)
        {
            addSpell(new TextCommand(i, symbol, cmd, (SpellTarget)targetType,
                     basicLvl, (MagicSchool)school, schoolLvl, mana));
        }
        else
        {
            addSpell(new TextCommand(i, symbol, cmd, (SpellTarget)targetType));
        }
    }
}

void SpellManager::save()
{
    for (int i = 0; i < SPELL_SHORTCUT_ITEMS; i++)
    {
        TextCommand *spell = mSpellsVector[i];
        if (spell)
        {
            serverConfig.setValue("commandShortcutCmd" + toString(i),
                                  spell->getCommand());
            serverConfig.setValue("commandShortcutSymbol" + toString(i),
                                  spell->getSymbol());
            serverConfig.setValue("commandShortcutFlags" + toString(i),
                strprintf("%u %u %u %u %u %u", spell->getCommandType(),
                spell->getTargetType(), spell->getBaseLvl(),
                spell->getSchool(), spell->getSchoolLvl(), spell->getMana()));
        }
    }
}

std::string SpellManager::autoComplete(std::string partName)
{
    std::vector<TextCommand*>::iterator i = mSpellsVector.begin();
    std::string newName = "";
    TextCommand *newCommand = NULL;

    while (i != mSpellsVector.end())
    {
        TextCommand *cmd = *i;
        std::string line = cmd->getCommand();

        if (line != "")
        {
            std::string::size_type pos = line.find(partName, 0);
            if (pos == 0)
            {
                if (newName != "")
                {
                    newName = findSameSubstring(line, newName);
                    newCommand = NULL;
                }
                else
                {
                    newName = line;
                    newCommand = cmd;
                }
            }
        }
        ++i;
    }
    if (newName != "" && newCommand
        && newCommand->getTargetType() == NEEDTARGET)
    {
        return newName + " ";
    }
    return newName;
}
