class Character:
    
    StatsArray = namedtuple("StatsArray", ["Hp", "Str", "Mag", "Skl", "Spd", "Lck", "Res", "Def"])
    WepArray = namedtuple("WepArray", ["Swd", "Axe", "Lnc", "Bow", "Knf", "Fir", "Thu", "Wnd", "Lgt", "Drk", "Stf"])
    
    
    def __init__(self, info):
        '''
        [name, currentHp, level, experience, statList, growthList, wepExpList, Inventory]
        '''
        #TODO Add skills, mov and any other important statistics. .

        #Mov might be better in the stats array, depending how I do class changes or if I want
        #anyone to be able to gain mov on level-up.

        
        self.name = info[0]
        self.cHp = info[1]
        self.lvl, self.exp = info[2], info[3]
        
        self.stats = Character.StatsArray._make(info[4])
        self.growths = Character.StatsArray._make(info[5])
        self.WExps = Character.WepArray._make(info[6])
        
        self.inv = Inventory(self, info[7])
        
        
    def cmbtWindow(self, defend):
        '''
        Prints out an info sheet on the selected combat, with self as the aggressor. Also
        initiates the fight.
        '''
        
        #Print "    Name1    Name2"
        print("\t" + self.name + "\t" + defend.name)
        
        #Print "    dmg1    dmg2"
        dmgA = self.stats.Str - defend.stats.Def + self.inv.wep.mt
        dmgB = defend.stats.Str - self.stats.Def + defend.inv.wep.mt
        if dmgA < 0:
            dmgA = 0
        if dmgB < 0:
            dmgB = 0
        print("Dmg\t" + str(dmgA) + "\t" + str(dmgB))
        
        #Print "    atks1    atks2"
        if self.stats.Spd - 7 >= defend.stats.Spd:
            atksA = 3
            atksB = 1
        elif self.stats.Spd - 4 >= defend.stats.Spd:
            atksA = 2
            atksB = 1
        elif defend.stats.Spd - 7 >= self.stats.Spd:
            atksA = 1
            atksB = 3
        elif defend.stats.Spd - 4 >= self.stats.Spd:
            atksA = 1
            atksB = 2
        else:
            atksA = 1
            atksB = 1
        print("Attacks\t" + str(atksA) + "\t" + str(atksB))
        
        #Print "    hit1    hit2"
        hitA = 2 * self.stats.Skl - 2 * defend.stats.Spd + self.stats.Lck - defend.stats.Lck + self.inv.wep.hit
        hitB = 2 * defend.stats.Skl - 2 * self.stats.Spd + defend.stats.Lck - self.stats.Lck + defend.inv.wep.hit
        if hitA < 0:
            hitA = 0
        if hitB < 0:
            hitB = 0
        print("Hit\t" + str(hitA) + "\t" + str(hitB))
        
        #Print "    crit1    crit2"
        critA = self.stats.Skl/2 - defend.stats.Lck + self.inv.wep.crit
        critB = defend.stats.Skl/2 - self.stats.Lck + defend.inv.wep.crit
        if critA < 0:
            critA = 0
        if critB < 0:
            critB = 0
        print("Crit\t" + str(critA) + "\t" + str(critB))
        
        #TODO Ask for input from user to fight or not.

        print("Would you like " + self.name + " to attack " + defend.name + "? (Y or N)")
        i = "x"
        
        #Loop until a y or n answer is obtained.
        while (True):
            i = raw_input()
            if (i == "n" or i == "N"):
                return
            if(i == "Y" or i == "y"):
                self.cmbt(defend)
                return
            print("Invalid input. Try Again.")

        
    def cmbt(self, defend):
        
        self.fight(defend)
        self.reequip()
        defend.reequip()
        
    def reequip(self):
        if ((self.inv.wep is None) and self.inv.equipped == True):
            self.inv.equipFirst()
        
    def fight(self, defend):
        '''
        TODO Add the option for Mag vs Def and Str vs Res or others? Skills instead?
        '''
        
        dmgTotalA = 0
        dmgTotalB = 0
        
        baseExpA = (21 + defend.lvl - self.lvl)/2
        baseExpB = (21 + self.lvl - defend.lvl)/2
        
        #Always
        x = self.attack(defend)
        dmgTotalA += x
        if x == -1:
            self.getExp(baseExpA + defend.lvl - self.lvl + 20)
            return
        
        #Always
        x= defend.attack(self)
        dmgTotalB+=x
        if x == -1:
            defend.getExp(baseExpB + self.lvl - defend.lvl + 20)
            return
        
        #When attacker has 2x or 3x
        if self.stats.Spd - 4 >= defend.stats.Spd:
            x= self.attack(defend)
            dmgTotalA+=x
            if x == -1:
                self.getExp(baseExpA + defend.lvl - self.lvl + 20)
                return
        
        #When attacker has 3x
        if self.stats.Spd - 7 >= defend.stats.Spd:
            x= self.attack(defend)
            dmgTotalA+=x
            if x == -1:
                self.getExp(baseExpA + defend.lvl - self.lvl + 20)
                return
            
        #When defender has 2x or 3x
        if defend.stats.Spd - 4 >= self.stats.Spd:
            x= defend.attack(self)
            dmgTotalB+=x
            if x == -1:
                defend.getExp(baseExpB + self.lvl - defend.lvl + 20)
                return
            
        #When defender has 3x
        if defend.stats.Spd - 7 >= self.stats.Spd:
            x= defend.attack(self)
            dmgTotalB+=x
            if x == -1:
                defend.getExp(baseExpB + self.lvl - defend.lvl + 20)
                return
            
        if dmgTotalA >= 1:
            self.getExp(baseExpA)
        else:
            self.getExp(1)
            
        if dmgTotalB >= 1:
            defend.getExp(baseExpB)
        else:
            defend.getExp(1)
            
    def attack(self, defend):
        '''
        self performs a Str vs Def or Mag vs Res attack on defend. Checks for crits and skill
        activations. 
        '''
        
        if (self.inv.wep is None):
            return 0
        
        
        hit = 2 * self.stats.Skl - 2 * defend.stats.Spd + self.stats.Lck - defend.stats.Lck + self.inv.wep.hit # Plus other bonuses
        hit = hit * 2
        r = randint(0, 99) + randint(0, 99)
        
        if hit > r:
            spec = self.specCheck(defend)
            if spec > 1:
                return self.specExe(defend, spec)
            
            if ((self.inv.wep.type >= 0 and self.inv.wep.type <= 4) or self.inv.wep.type == 10):
                dmg = self.stats.Str - defend.stats.Def + self.inv.wep.mt #TODO Add other Bonuses
            if (self.inv.wep.type > 5 and self.inv.wep.type <= 9):
                dmg = self.stats.Mag - defend.stats.Res + self.inv.wep.mt
            if (self.inv.wep is None):
                dmg = 0
            if (dmg < 0):
                dmg = 0
                
                
            if spec == 1:
                print("Critical!")
                dmg *= 3
            print(defend.name + " takes " + str(dmg) + " damage.")
            defend.cHp -= dmg
            if defend.cHp <= 0:
                self.inv.useWep()
                print(defend.name + " has died.")   #TODO fetch death quotes from somewhere.
                return -1
            if dmg > 0:
                self.inv.useWep()
            return dmg
        print("Miss")
        return 0
    
    def specCheck(self, defend):
        '''
        Uses RNG to check for skill activations, crits, etc.
        '''
        
        #TODO Add checks for skills that would proc before checking for crit
        
        #RAW crit is Skl/2 vs Lck
        crit = self.stats.Lck + self.stats.Skl/2 - 2 * defend.stats.Lck
        r = randint(0, 99)
        if crit > r:
            return 1
        
        #TODO Add checks for skills that would proc if a crit did not
        
        return 0
    
    def getExp(self, x):
        '''
        Adds experience gain, then checks to see if enough experience to level up.
        '''
        if x > 0:
            self.exp += x
            while (self.exp >= 100):
                self.levelUp()
    
    def levelUp(self):
        '''
        Called by getExp. Gives self the benefits of a level-up and increments their level
        '''
        
        
        self.exp -= 100
        self.lvl += 1
        s = list(self.stats)
        
        x = 0
        for i in range(8):
            r = randint(0, 99)
            if r < self.growths[i]:
                s[i] += 1
                x += 1
        self.stats = Character.StatsArray._make(s)
        
        #TODO Add class change and class skill learning

        return x
    
    def specExe(self, defend, spec):
        '''
        Replaces a normal hit (or crit). Executes skill #(spec) skill and returns damage done.
        Hit has already succeeded. 
        '''
        #TODO Add skills. Also, should probably throw an exception if skill not found.
        
        print("Skill not found.")
        return