/*
Xinef
 */

#include <time.h>

#include "LootItemStorage.h"
#include "PreparedStatement.h"
#include "ObjectMgr.h"

LootItemStorage::LootItemStorage()
{
}

LootItemStorage::~LootItemStorage()
{
}

void LootItemStorage::LoadStorageFromDB()
{
    uint32 oldMSTime = getMSTime();
    lootItemStore.clear();

    PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
    PreparedQueryResult result = CharacterDatabase.Query(stmt);
    if (!result)
    {
        sLog->outString(">>  Loaded 0 stored items!");
        sLog->outString();
        return;
    }

    uint32 count = 0;
    do
    {
        Field* fields = result->Fetch();
        
        StoredLootItemList& itemList = lootItemStore[fields[0].GetUInt32()];
        itemList.push_back(StoredLootItem(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[3].GetInt32(), fields[4].GetUInt32()));

        ++count;
    } while (result->NextRow());

    sLog->outString(">> Loaded %d stored items in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
    sLog->outString();
}

void LootItemStorage::RemoveEntryFromDB(uint32 containerId, uint32 itemid, uint32 count)
{
    SQLTransaction trans = CharacterDatabase.BeginTransaction();
    PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_SINGLE_ITEM);
    stmt->setUInt32(0, containerId);
    stmt->setUInt32(1, itemid);
    stmt->setUInt32(2, count);
    trans->Append(stmt);

    CharacterDatabase.CommitTransaction(trans);
}

void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* player)
{
    if (lootItemStore.find(loot->containerId) != lootItemStore.end())
    {
        sLog->outMisc("LootItemStorage::AddNewStoredLoot (A1) - %u!", loot->containerId);
        return;
    }

    SQLTransaction trans = CharacterDatabase.BeginTransaction();
    PreparedStatement* stmt = NULL;

    StoredLootItemList& itemList = lootItemStore[loot->containerId];

    // Gold at first
    if (loot->gold)
    {
        itemList.push_back(StoredLootItem(0, loot->gold, 0, 0));

        stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
        stmt->setUInt32(0, loot->containerId);
        stmt->setUInt32(1, 0);
        stmt->setUInt32(2, loot->gold);
        stmt->setInt32(3, 0);
        stmt->setUInt32(4, 0);
        trans->Append(stmt);
    }

    // And normal items
    if (!loot->isLooted())
        for (LootItemList::const_iterator li = loot->items.begin(); li != loot->items.end(); li++)
        {
            if (!li->AllowedForPlayer(player))
                continue;

            const ItemTemplate* itemTemplate = sObjectMgr->GetItemTemplate(li->itemid);
            if (!itemTemplate || itemTemplate->IsCurrencyToken())
                continue;

            itemList.push_back(StoredLootItem(li->itemid, li->count, li->randomPropertyId, li->randomSuffix));

            stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
            stmt->setUInt32(0, loot->containerId);
            stmt->setUInt32(1, li->itemid);
            stmt->setUInt32(2, li->count);
            stmt->setInt32 (3, li->randomPropertyId);
            stmt->setUInt32(4, li->randomSuffix);
            trans->Append(stmt);
        }

    CharacterDatabase.CommitTransaction(trans);
}

bool LootItemStorage::LoadStoredLoot(Item* item)
{
    Loot* loot = &item->loot;
    LootItemContainer::iterator itr = lootItemStore.find(loot->containerId);
    if (itr == lootItemStore.end())
        return false;

    StoredLootItemList& itemList = itr->second;
    for (StoredLootItemList::iterator it2 = itemList.begin(); it2 != itemList.end(); ++it2)
    {
        if (it2->itemid == 0)
        {
            loot->gold = it2->count;
            continue;
        }

        LootItem li;
        li.itemid = it2->itemid;
        li.count = it2->count;
        li.follow_loot_rules = false;
        li.freeforall = false;
        li.is_blocked = false;
        li.is_counted = false;
        li.is_underthreshold = false;
        li.is_looted = false;
        li.needs_quest = false;
        li.randomPropertyId = it2->randomPropertyId;
        li.randomSuffix = it2->randomSuffix;
        li.rollWinnerGUID = 0;

        loot->items.push_back(li);
        loot->unlootedCount++;
    }

   // Mark the item if it has loot so it won't be generated again on open
   item->m_lootGenerated = true;
   return true;
}

void LootItemStorage::RemoveStoredLootItem(uint32 containerId, uint32 itemid, uint32 count)
{
    LootItemContainer::iterator itr = lootItemStore.find(containerId);
    if (itr == lootItemStore.end())
        return;

    StoredLootItemList& itemList = itr->second;
    for (StoredLootItemList::iterator it2 = itemList.begin(); it2 != itemList.end(); ++it2)
        if (it2->itemid == itemid && it2->count == count)
        {
            RemoveEntryFromDB(containerId, itemid, count);
            itemList.erase(it2);
            break;
        }

    if (itemList.empty())
        lootItemStore.erase(itr);
}

void LootItemStorage::RemoveStoredLootMoney(uint32 containerId)
{
    LootItemContainer::iterator itr = lootItemStore.find(containerId);
    if (itr == lootItemStore.end())
        return;

    StoredLootItemList& itemList = itr->second;
    for (StoredLootItemList::iterator it2 = itemList.begin(); it2 != itemList.end(); ++it2)
        if (it2->itemid == 0)
        {
            RemoveEntryFromDB(containerId, 0, it2->count);
            itemList.erase(it2);
            break;
        }

    if (itemList.empty())
        lootItemStore.erase(itr);
}

void LootItemStorage::RemoveStoredLoot(uint32 containerId)
{
    lootItemStore.erase(containerId);

    SQLTransaction trans = CharacterDatabase.BeginTransaction();
    PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_CONTAINER);
    stmt->setUInt32(0, containerId);
    trans->Append(stmt);

    CharacterDatabase.CommitTransaction(trans);
}
