import MySQLdb as db
import sys
import random
import copy

# TODO: Implement lootmodes

# npc_entry, quest1, quest2, ... = argv
npc_entry = 36597  # lich king

with_quest_items = False


### random helpers ###


def RandCount(minCount, maxCount):
    """Random value between minCount and maxCount (inclusive)"""
    if (maxCount <= 0 or maxCount < minCount):
        print "counts (%i,%i) are invalid." % (minCount, maxCount)

    return random.randrange(minCount, maxCount + 1)


def RandChance(chance):
    """There's a chance% of this returning True"""

    if with_quest_items:
        return random.uniform(0, 100) < abs(chance)
    else:
        return random.uniform(0, 100) < chance


### get names ###


def GetCreatureName(entry, cursor):
    """ Returns the name of a creature"""
    cursor.execute("SELECT `name` FROM `creature_template` WHERE `entry`=%d LIMIT 1" % entry)
    return cursor.fetchone()[0]


def GetItemName(entry, cursor):
    """Returns the name of an item"""
    cursor.execute("SELECT `name` FROM `item_template` WHERE `entry`=%d LIMIT 1" % entry)
    return cursor.fetchone()[0]


### loot processing ###

def SplitIntoGroups(rows):
    """Splits rows of a certain entry into a dictionary, key is groupid"""

    groups = {}

    for row in rows:
        if row[3] in groups:
            groups[row[3]].append(row)
        else:
            groups[row[3]] = [row]

    return groups


def CalculateChanceGroups(groups):
    """Calculates chances if a group has all items with chance = 0"""
    for group in groups:
        sameChance = True
        for row in groups[group]:
            # assumes that a group will have all chances with 0 or no 0s at all
            if row[1] != 0:
                sameChance = False
                break

        if sameChance:

            chance = 100.0 / len(groups[group])
            for row in groups[group]:
                row[1] = chance

        groups[group] = [groups[group], sameChance]

    return groups


def ProcessReference(rowsOri):
    rows = copy.deepcopy(rowsOri)
    groups = SplitIntoGroups(rows)
    groups = CalculateChanceGroups(groups)

    loot = []

    for group in groups:
        gotItem = False
        forceDrop = groups[group][1]
        groupZero = group == 0

        while True:

            if gotItem and not groupZero:
                break

            if forceDrop and gotItem:
                break

            for row in groups[group][0]:
                    if (not gotItem or groupZero) and RandChance(row[1]):
                        for i in range(0, RandCount(row[4], row[5])):
                            loot.append(row[0])
                            gotItem = True
                            break

            if groupZero:
                break

    return loot


def ProcessLoot(rows, references, reflinks):
    """Simulates ONE kill; returns a list of items dropped."""
    loot = []

    for ref in references:
        if RandChance(references[ref][0]):  # ChanceOrQuestChance for references,
                                            # there's a certain chance of not processing references at all
            for i in range(0, references[ref][3]):  # maxcount for references, process reference X times
                if ref in rows:
                    newLoot = ProcessReference(rows[ref])
                    if newLoot:
                        for l in newLoot:
                            loot.append(l)

    return loot


def GetLootTableAux(entry, cursor, rows, references, referencesLinks):
    """Auxiliar method of GetLootTable"""
    table = ""
    refEntry = 0
    if not rows:
        table = "creature_loot_template"
    else:
        table = "reference_loot_template"
        refEntry = entry

    query = "SELECT `item`,`ChanceOrQuestChance`,`lootmode`,`groupid`,`mincountOrRef`,`maxcount` FROM `%s` WHERE `entry`=%d;" % (table, entry)
    cursor.execute(query)
    rawData = cursor.fetchall()

    referencesEntries = []

    for row in rawData:
        row = list(row)
        if row[4] < 0:
            referencesEntries.append(abs(row[4]))
            references[abs(row[4])] = [row[1], row[2], row[3], row[5]]

            if refEntry in referencesLinks:
                referencesLinks[refEntry].append(abs(row[4]))
            else:
                referencesLinks[refEntry] = [abs(row[4])]

        else:
            if refEntry in rows:
                rows[refEntry].append(row)
            else:
                rows[refEntry] = [row]

    if not referencesEntries:
        return
    else:
        for ref in referencesEntries:
            GetLootTableAux(ref, cursor, rows, references, referencesLinks)


def GetLootTable(entry, cursor):
    """Gets the full loot table from DB, including references"""
    rows = dict()
    references = dict()
    refLinks = dict()
    GetLootTableAux(entry, cursor, rows, references, refLinks)

    references[0] = [100.0, 1, 1, 1]

    return rows, references, refLinks


### main ###


try:
    con = db.connect('localhost', 'root', 'root', 'world')
    cur = con.cursor()

    rows, references, refLinks = GetLootTable(npc_entry, cur)

    iterNumber = 10

    print "-- Loot table for %s" % GetCreatureName(npc_entry, cur)
    for key in rows:
        print key
        for row in rows[key]:
            print "\t %s - %s" % (str(row), GetItemName(row[0], cur))

    for i in range(0, iterNumber):
        print "\n%i -- Loot generated for %s" % (i, GetCreatureName(npc_entry, cur))
        for item in ProcessLoot(rows, references, refLinks):
            print "\t%i - %s" % (item, GetItemName(item, cur))

    con.close()

except db.Error, e:
    print "Error %d: %s" % (e.args[0], e.args[1])
    sys.exit(1)

@@ -137,26 +137,13 @@
 y = 
-36597  # lich king
+18728
 %0A%0Awi
@@ -1776,17 +1776,16 @@
 Chance:%0A
-%0A
         
@@ -3270,17 +3270,16 @@
     
-newLoot =
+for l in
  Pro
@@ -3306,87 +3306,10 @@
 ef%5D)
+:
 %0A
-                    if newLoot:%0A                        for l in newLoot:%0A    
     
@@ -3518,24 +3518,67 @@
  if not rows
+ and not references and not referencesLinks
 :%0A        ta
@@ -4225,32 +4225,32 @@
           else:%0A
+
                 
@@ -4291,17 +4291,16 @@
 ow%5B4%5D)%5D%0A
-%0A
         

Fix a few bugs in reference linking