#################################################
# hw6.py
#
# Your name:
# Your andrew id:
#################################################

import math
#################################################
# Classes (for you to write)
#################################################

#### marbleClass ####

class Marble(object):
    pass

## You should probably write other classes here



#################################################
# Test Functions
#################################################

def getLocalMethods(clss):
    import types
    # This is a helper function for the test function below.
    # It returns a sorted list of the names of the methods
    # defined in a class. It's okay if you don't fully understand it!
    result = []
    for var in clss.__dict__:
        val = clss.__dict__[var]
        if (isinstance(val, types.FunctionType)):
            result.append(var)
    return sorted(result)


def testMarbleClasses():
    print("Testing Marble classes...", end="")
    # A Marble takes a string (not a list) of comma-separated color names
    m1 = Marble('Pink,Cyan')
    assert(m1.colorCount() == 2) # pink and cyan
    assert(Marble.getMarbleCount() == 1) # we have created 1 marble so far

    # When converted to a string, the Marble includes the color names,
    # each separated by a comma and a space, and all lower-case, and listed
    # in alphabetical order:
    assert(str(m1) == '<Marble with colors: cyan, pink>')

    m2 = Marble('Red,Orange,yellow,GREEN')
    assert(str(m2) == '<Marble with colors: green, orange, red, yellow>')
    assert(m2.colorCount() == 4)
    assert(Marble.getMarbleCount() == 2) # we have created 2 marbles so far

    # This also works in a list:
    assert(str([m1]) == '[<Marble with colors: cyan, pink>]')

    # Equality works as expected:
    m3 = Marble('red,blue')
    m4 = Marble('BLUE,RED')
    m5 = Marble('red,green,blue')
    assert((m3 == m4) and (m3 != m5) and (m3 != "Don't crash here!"))
    assert(Marble.getMarbleCount() == 5) # we have created 5 marbles so far

    # You can add colors, which only change the marble if they are not present:
    assert(m3.addColor('Red') == False) # False means the color was not added,
                                        # because it was already there
    # and no changes here:
    assert(m3.colorCount() == 2)
    assert(str(m3) == '<Marble with colors: blue, red>')
    assert((m3 == m4) and (m3 != m5))

    # Once more, but with a new color:
    assert(m3.addColor('green') == True) # True means the color was added!
    # and so these all change:
    assert(m3.colorCount() == 3)
    assert(str(m3) == '<Marble with colors: blue, green, red>')
    assert((m3 != m4) and (m3 == m5))

    # A ConstantMarble is a marble that never changes its color:
    m6 = ConstantMarble('red,blue')
    assert(isinstance(m6, Marble))
    assert(str(m6) == '<Marble with colors: blue, red>')
    assert(m6.addColor('green') == False) # constant marbles never change!
    assert(str(m6) == '<Marble with colors: blue, red>')
    assert(Marble.getMarbleCount() == 6) # we have created 6 marbles so far
    assert(getLocalMethods(ConstantMarble) == ['addColor'])

    # A DarkeningMarble is a marble that prefixes 'dark' to any colors
    # that are added after it is first created.
    # Note: for full credit, you must use super() properly here!
    m7 = DarkeningMarble('red,blue')
    assert(isinstance(m7, Marble))
    assert(str(m7) == '<Marble with colors: blue, red>') # not darkened
    assert(m7.addColor('green') == True) # but green will become darkgreen
    assert(str(m7) == '<Marble with colors: blue, darkgreen, red>')
    assert(Marble.getMarbleCount() == 7) # we have created 7 marbles so far
    assert(getLocalMethods(DarkeningMarble) == ['addColor'])
    print("Passed!")




#################################################
# testAll and main
#################################################

def testAll():
    # comment out the tests you do not wish to run!
    testMarbleClasses()

def main():
    testAll()

if __name__ == '__main__':
    main()
