from tkinter import *
from ..pypeg2 import *
from .actionbuttons import *
import sys
from .matrix import *
import math
from ..gooey import *

import os

SMALL_WIN_SIZE = 200
MED_WIN_SIZE = 400
LARGE_WIN_SIZE = 600

SMALL_TEXTBOX_WIDTH = 20
SMALL_TEXTBOX_HEIGHT = 1
MED_TEXTBOX_WIDTH = 35
MED_TEXTBOX_HEIGHT = 8
LARGE_TEXTBOX_WIDTH = 50
LARGE_TEXTBOX_HEIGHT = 10

class ErrorPopup:
    '''
    A pop-up window that gracefully handles Gooey errors.
    Displays the error message to the user and closes when "OK" button is clicked.
    '''
    def __init__(self, message):
        self.message = "Error: " + str(message)
        # Create error popup window
        self.window = Toplevel()
        self.window.title("Error")
        self.window.geometry("%dx%d%+d%+d" % (200, 200, 200, 200))
        # Add message to popup
        messageText = Message(self.window, text=self.message, justify=CENTER)
        messageText.pack()
        # Add "OK" button to popup, that will close popup when clicked
        button = Button(self.window, text="Ok", command=self.window.destroy)
        button.pack()


class GooeyError(Exception):
    def __init__(self, message):
        self.message = message
        ErrorPopup(self.message)
    def __repr__(self):
        return self.message
class Binding:
    '''
    Binding object has four instance variables
    bType - the type of object with regards to "Gooey" ex) Window, Button
    varname - how we identify the object (a string)
    bObject - the actual tkinter object
    params - an optional argument use to take in the parameters of a user defined function
    '''
    bType = None
    varname = None
    bObject = None
    params = None
    frames = None

    def __init__(self,bType,varname,bObject,params,frames):
        '''Sets instance variables: type, name, Tkinter object, and optional parameters'''
        self.bType = bType
        self.varname = varname
        self.bObject = bObject
        self.params = params
        self.frames = frames

    def __repr__(self):
        '''Prints a pretty version of the bindings'''
        prettyStr = "Binding " + str(self.varname) + " of type " + str(self.bType) + "."
        return prettyStr

class Interpreter():
    '''Interpreter class: creates GUI based on the expression given by the user.'''
    gRows = 0
    gColumns = 0

    def __init__(self, target,winBinding,bindings):
        '''Initializes the GUI window'''
        self.window = target
        self.winBinding = winBinding
        self.bindings = bindings

    def setWinBinding(self, b):
        self.winBinding = b

    def interpret(self, ast):
        '''Interprets the Gooey code and creates a GUI in the window.
        It takes in an abstract syntax tree as generated by pypeg, and the current bindings.
        Returns a new list of bindings. '''

        for expr in ast:


            '''
-------------------- MAKE --------------------
            '''
            if(expr.__class__.__name__ == "Make"):
                if hasattr(expr, "type"):

                    # Check to see if variable name is already used,
                    # make the object, and add to bindings.
                    if (expr.type == "Window"):
                        self.checkVarname(expr)
                        (w,frames) = self.makeWindow(self.window,expr)
                        binding = self.makeBinding("Window", expr.varname, w,[],frames)
                        self.setWinBinding(binding)
                        self.bindings = self.addBinding(binding)

                    elif(expr.type == "Button"):
                        self.checkVarname(expr)
                        b = self.makeButton(self.winBinding,expr)
                        binding = self.makeBinding("Button", expr.varname, b)
                        self.bindings = self.addBinding(binding)
                    #NEEDS TO BE MODIFIED TO NOT TAKE IN SELF.WINDOW
                    elif(expr.type == "Menu"):
                        self.checkVarname(expr)
                        m = self.makeMenu(self.winBinding,expr)
                        options = self.getOptions(expr)
                        # print("OPTIONS IN MAKEMENU",options)
                        binding = self.makeBinding("Menu", expr.varname, m, options)
                        self.bindings = self.addBinding(binding)
                        # print("made the menu")

                    elif(expr.type == "MenuItem"):
                        # print("making the menuitem")
                        #self.checkVarname(expr) #Can't do this right now cuz of how we're making the menuitems in menu
                        # print("Checked the varname")
                        mi = self.makeMenuItem(self.winBinding,expr)
                        # print("made the menuitem")
                        # options = self.getOptions(expr)
                        # print("options",options)
                        # binding = self.makeBinding("MenuItem", expr.varname, mi, options)
                        # self.bindings = self.addBinding(binding)

                    elif(expr.type == "TextBox"):
                        self.checkVarname(expr)
                        t = self.makeTextBox(self.winBinding, expr)
                        binding = self.makeBinding("TextBox", expr.varname, t)
                        self.bindings = self.addBinding(binding)

                    elif(expr.type == "Image"):
                        self.checkVarname(expr)
                        i = self.makeImage(self.winBinding, expr)
                        binding = self.makeBinding("Image", expr.varname, i)
                        self.bindings = self.addBinding(binding)

                    elif(expr.type == "Text"):
                        self.checkVarname(expr)
                        t = self.makeText(self.winBinding, expr)
                        binding = self.makeBinding("Text", expr.varname, t)
                        self.bindings = self.addBinding(binding)

                    elif(expr.type == "FormattedText"):
                        self.checkVarname(expr)
                        ft = self.makeFormattedText(self.winBinding, expr)
                        binding = self.makeBinding("FormattedText", expr.varname, ft)
                        self.bindings = self.addBinding(binding)

                    elif(expr.type == "Checkboxes"):
                        self.checkVarname(expr)
                        cb = self.makeCheckboxes(self.winBinding, expr)
                        binding = self.makeBinding("Checkboxes", expr.varname, cb)
                        self.bindings = self.addBinding(binding)

                    elif(expr.type == "RadioButtons"):
                        self.checkVarname(expr)
                        rb = self.makeRadioButtons(self.winBinding, expr)
                        binding = self.makeBinding("RadioButtons", expr.varname, rb)
                        self.bindings = self.addBinding(binding)

                    else:
                        raise GooeyError("Object in Make statement not recognized. Make sure to capitalize the object name.")
                else:
                    raise GooeyError("No type name provided to Make statement.")


                    '''
-------------------- SET --------------------
                    '''
            elif(expr.__class__.__name__ == "GooeySet"):
                if hasattr(expr, "varname"):
                    if expr.varname in self.bindings:
                        obj = self.bindings[expr.varname]
                        if obj.bType == "Window":
                            win = self.getObject(expr)
                            assert win.bType == 'Window'
                            wColorBefore = win.frames.cget('bg')
                            w = self.setWindow(win,expr)
                            wColorAfter = w.frames.cget('bg')
                            if wColorBefore != wColorAfter:
                                self.bindings = self.fixObjectPadding(wColorAfter)
                            w = self.setWindow(win,expr)

                        elif(obj.bType == "Button"):
                            button = self.getObject(expr)
                            assert button.bType == 'Button'
                            b = self.setButton(button.bObject,self.winBinding, expr)

                        elif(obj.bType == "Menu"):
                            pass

                        elif(obj.bType == "MenuItem"):
                            pass
                        elif(obj.bType == "Text"):
                            t = self.getObject(expr)
                            assert t.bType == 'Text'
                            t = self.setText(t.bObject,self.winBinding, expr) #Change to be self.winbinding

                        elif(obj.bType == "TextBox"):
                            t = self.getObject(expr)
                            assert t.bType == 'TextBox'
                            tbox = t.bObject
                            tbox = self.setTextBox(tbox, self.winBinding, expr) #change to be winbinding

                        elif(obj.bType == "FormattedText"):
                            ft = self.getObject(expr)
                            assert ft.bType == 'FormattedText'
                            ft = self.setFormattedText(ft.bObject, self.winBinding, expr)

                        elif(obj.bType == "Checkboxes"):
                            cb = self.getObject(expr)
                            assert cb.bType == 'Checkboxes'
                            cb = self.setCheckboxes(cb.bObject, self.winBinding, expr)
                            obj.bObject = cb

                        elif(obj.bType == "RadioButtons"):
                            rb = self.getObject(expr)
                            assert rb.bType == 'RadioButtons'
                            rb = self.setRadioButtons(rb.bObject, self.winBinding, expr)
                            obj.bObject = rb

                        else:
                            raise GooeyError("Cannot set variable of type " + str(obj.bType))
                    else:
                        raise GooeyError(str(expr.varname) + " is undefined.")


            # Interprets all function definition statements
            elif(expr.__class__.__name__ == "FunctionDefinition"):
                if hasattr(expr, "funcname"):

                    #Checks bindings to see if function name is already there.
                    #If function isn't already defined, add it to bindings.
                    if expr.funcname not in self.bindings:
                        actions = []
                        for i in range(len(expr.funcaction)):
                            # For each line in the function, get its action
                            # (unwrap the Make, Set, or Return statement from within the Line/LastLine statement)
                            # and replace it in the expression's funcaction attribute
                            action = self.getFunctionLineAction(expr.funcaction[i])
                            actions.append(action)

                        # Fetch formal parameters if function has them
                        formalParams = []
                        if hasattr(expr, "params"):
                            formalParams = expr.params

                        # Add function definition to bindings
                        binding = self.makeBinding("Function", str(expr.funcname), actions, formalParams)
                        self.bindings = self.addBinding(binding)

                    else:
                        raise GooeyError("Sorry, this function name is already used.")
                else:
                    raise GooeyError("Sorry, you need to give your function a name.")

            #Interprets all function calls
            elif(expr.__class__.__name__ == "FunctionCall"):
                #Find function with that name
                function = expr.funcname
                if function in self.bindings:
                    # Fetch function from bindings
                    functionBinding = self.bindings[function]

                    if functionBinding.bType == 'Function':
                        wColorBefore = self.winBinding.frames.cget('bg') #NEEDED FOR BUTTON PADDING ADJUSTING

                        # Check if parameter and argument lists are same length
                        if len(expr.params) == len(functionBinding.params):

                            # Create new dictionary of local bindings for the function frame,
                            # and add arguments passed in to it.
                            localBindings = dict()
                            localI = Interpreter(self.winBinding.bObject,self.winBinding, localBindings)

                            # Add arguments passed to function to the local bindings with param names.
                            for paramIndex in range(len(expr.params)):
                                paramName = functionBinding.params[paramIndex]
                                argumentName = expr.params[paramIndex]
                                # Check for different arg types
                                try:
                                    intArg = int(argumentName)
                                    newLocalBinding = localI.makeBinding("Integer", paramName, intArg)
                                    localI.bindings = localI.addBinding(newLocalBinding)
                                except(ValueError):
                                    if argumentName.__class__.__name__ == "QuotedText":
                                        newLocalBinding = localI.makeBinding("String", paramName, argumentName)
                                        localI.bindings = localI.addBinding(newLocalBinding)
                                    elif argumentName in self.bindings:
                                        argument = self.bindings[argumentName]
                                        newLocalBinding = localI.makeBinding(argument.bType, paramName, argument.bObject, argument.params, argument.frames)
                                        localI.bindings = localI.addBinding(newLocalBinding)
                                        if argument.__class__.__name__ == 'Window':
                                            localI.winBinding = newLocalBinding
                                    else:
                                        raise GooeyError(str(argumentName) + " is undefined.")
                                        return self.bindings

                            # Interpret each line of the function
                            functionCode = functionBinding.bObject
                            for line in functionCode:
                                if line.__class__.__name__ == "Return":
                                    if hasattr(line, "param") and hasattr(expr, "returnTo"):
                                        returnValue = localI.bindings[line.param]
                                        returnedParam = self.makeBinding(returnValue.bType, expr.returnTo, returnValue.bObject, returnValue.params)
                                        self.bindings = self.addBinding(returnedParam)
                                else:
                                    (localI.bindings, self.winBinding) = localI.interpret([line])
                            #CHECK BUTTON PADDING HERE

                            wColorAfter = self.winBinding.frames.cget('bg')
                            if wColorBefore != wColorAfter:

                                # print("Colors didn't match")
                                self.bindings = self.fixObjectPadding(wColorAfter)
                                # print("tried to fix button padding")


                        else:
                            raise GooeyError("The function "+str(function)+" requires "+str(len(functionBinding.params))+" arguments; you have passed it "+str(len(expr.params))+" arguments.")
                    else:
                        raise GooeyError("Cannot call "+str(function)+" because it is not a function.")
                else:
                    raise GooeyError("This function isn't defined.")
            else:
                #Invalid first word
                raise GooeyError("Invalid command. Please start your command with Make, Set, or other valid start commands.")
        return (self.bindings,self.winBinding)


    '''
-------------------- FORMATTED TEXT --------------------
    '''
    def makeFormattedText(self,w,expr):
        settings = ["Untitled Text", "Times", 12, "black", False, False, False]
        if hasattr(expr, "attributes"):
            for item in expr.attributes:

                # print (item)

                if hasattr(item, "text"):
                    if item.text.value in self.bindings:
                        textBinding = self.bindings[item.text.value]
                        if textBinding.bType == "String":
                            settings[0] = textBinding.bObject
                        else:
                            raise GooeyError("Cannot set FormattedText text attribute to "+str(item.text.value)+".")
                    else:
                        settings[0] = item.text.value
                elif hasattr(item, "font"):
                    if item.font.name in self.bindings:
                        fontBinding = self.bindings[item.font.name]
                        if fontBinding.bType == "String":
                            settings[1] = fontBinding.bObject
                        else:
                            raise GooeyError("Cannot set FormattedText font attribute to "+str(item.font.value)+".")
                    else:
                        settings[1] = item.font.name
                elif hasattr(item, "size"):
                    if item.size.value in self.bindings:
                        sizeBinding = self.bindings[item.size.value]
                        if sizeBinding.bType == "Integer":
                            settings[2] = sizeBinding.bObject
                        else:
                            raise GooeyError("Cannot set FormattedText size attribute to "+str(item.size.value)+".")
                    else:
                        settings[2] = int(item.size.value)
                elif hasattr(item, "color"):
                    settings[3] = item.color.value
                elif hasattr(item, "bold"):
                    settings[4] = item.bold.value
                elif hasattr(item, "italic"):
                    settings[5] = item.italic.value
                elif hasattr(item, "underline"):
                    settings[6] = item.underline.value
                else:
                    raise GooeyError("FormattedText does not have that attribute.")

        return settings

    def setFormattedText(self, ft, win, expr):
        w = win.frames
        for item in expr.attributes:
            if hasattr(item, "text"):
                if item.text.value in self.bindings:
                    textBinding = self.bindings[item.text.value]
                    if textBinding.bType == "String":
                        ft[0] = textBinding.bObject
                    else:
                        raise GooeyError("Cannot set FormattedText text attribute to "+str(item.text.value)+".")
                else:
                    ft[0] = item.text.value
            elif hasattr(item, "font"):
                if item.font.value in self.bindings:
                    fontBinding = self.bindings[item.font.value]
                    if fontBinding.bType == "String":
                        ft[1] = fontBinding.bObject
                    else:
                        raise GooeyError("Cannot set FormattedText font attribute to "+str(item.font.value)+".")
                else:
                    ft[1] = item.font.name
            elif hasattr(item, "size"):
                if item.size.value in self.bindings:
                    sizeBinding = self.bindings[item.size.value]
                    if sizeBinding.bType == "Integer":
                        ft[2] = sizeBinding.bObject
                    else:
                        raise GooeyError("Cannot set FormattedText size attribute to "+str(item.size.value)+".")
                else:
                    ft[2] = int(item.size.value)
            elif hasattr(item, "color"):
                ft[3] = item.color.value
            elif hasattr(item, "bold"):
                ft[4] = item.bold.value
            elif hasattr(item, "italic"):
                ft[5] = item.italic.value
            elif hasattr(item, "underline"):
                ft[6] = item.underline.value


    '''
-------------------- CHECKBOXES --------------------
    '''
    def makeCheckboxes(self,w,expr):
        w = w.frames
        cbList = []
        cbSize = 1
        #cbRow, cbColumn = 0, 0
        width, height = 0, 0
        var = StringVar(master=w)
        cbTitle = "Untitled Checkboxes:"
        hasTitle = False
        hasOptions = False

        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'position'):
                    if hasattr(item.position.value, "r"):
                        width = int(item.position.value.r)
                        height = int(item.position.value.c)
#                        cbRow = int(item.position.value.r)
#                        cbColumn = int(item.position.value.c)
                    else:
                        width, height = 0, 0
                        #cbRow, cbColumn = 0, 0
                        #cbRow, cbColumn = self.getPositionByKeyword(item.position.value)
                if hasattr(item, 'size'):
                    cbSize = int(item.size.value)

            cbList.append([width, height, cbSize])

            for item in expr.attributes:
                if(hasattr(item, 'title')):
                    hasTitle = True
                    cbTitle = ""
                    if (hasattr(item.title, 'value')):
                        cbTitle = item.title.value
                    ttl = Label(w, text=cbTitle, bg = w.cget('bg'))
                    ttl.place(x=width, y=height)
                    #ttl.place(x=cbColumn,y=cbRow)
                    if hasattr(item.title, 'var'):
                        if (item.title.var in self.bindings):
                            a = self.bindings.get(item.title.var).bObject
                            special = ""

                            if (a[4] == BooleanValue('true')):
                                special += "bold "
                            if (a[5] == BooleanValue('true')):
                                special += "italic "
                            if (a[6] == BooleanValue('true')):
                                special += "underline"
                            special = special.strip() #ow owwwwww

                            font = (a[1], a[2], special)
                            ttl.configure(text=a[0], fg=a[3], font=font)
                            height += a[2] * 1.8# + 10
                            #cbColumn += a[2] + 10
                            cbList[0].append(a[2] + 10)
                        else:
                            raise GooeyError("No formatted text with that name.")
                    else:
                        ttl.configure(text=item.title.value)
                        height += 22
                        #cbColumn += 22
                        cbList[0].append(22)
                    cbList.append(ttl)

            if not hasTitle:
                ttl = Label(w, text=cbTitle,bg = w.cget('bg'))
                ttl.place(x=width,y=height)
                height += 22
                #ttl.place(x=cbColumn,y=cbRow)
                #cbColumn += 22
                cbList[0].append(22)
                cbList.append(ttl)

            for item in expr.attributes:
                if(hasattr(item, 'options')):

                    hasOptions = True
                    i = 0
                    j = 0
                    isDefault = False
                    while(i < len(item.options.options)):
                        if(item.options.options[i] != ""):
                            cb = self.makeCheckbox(w,item.options.options[i], j, width, height)
                            height += 20 * cbSize
                            #cbColumn += 20 * cbSize
                            cb.configure(height=cbSize)
                            if (isDefault):
                                cb.select()
                            # binding = self.makeBinding("Checkboxes", expr.varname, cb)
                            # self.bindings = self.addBinding(binding)
                            cbList.append(cb)
                            isDefault = False
                            j += 1
                        else:
                            isDefault = True
                        i += 1
                elif(hasattr(item, 'title')):
                    pass
                elif(hasattr(item, 'position')):
                    pass
                elif(hasattr(item, 'size')):
                    pass
                else:
                    raise GooeyError("Cannot make Checkboxes with an attribute that Checkboxes does not have.")

            if not hasOptions:
                i = 0
                j = 0
                while(i < 3):
                    optionText = "Option " + str(i + 1)
                    cb = self.makeCheckbox(w,optionText, j, width, height)
                    height += 20 * cbSize
                    #cbColumn += 20 * cbSize
                    cb.configure(height=cbSize)
                    # binding = self.makeBinding("Checkboxes", expr.varname, cb)
                    # self.bindings = self.addBinding(binding)
                    cbList.append(cb)
                    j += 1
                    i += 1

        else:
            cbTitle = "Untitled Checkboxes"
            width, height = 0, 0
            cbSize = 1
            ttl = Label(w, text=cbTitle,bg = w.cget('bg'))
            ttl.place(x=width,y=height)
            height += 22
            #cbColumn += 22
            cbList.append([0, 0, 1, 22])
            cbList.append(ttl)
            i = 0
            j = 0
            while(i < 3):
                optionText = "Option " + str(i + 1)
                cb = self.makeCheckbox(w,optionText, j, width, height)
                height += 20 * cbSize
                #cbColumns
                cb.configure(height=cbSize)
                # binding = self.makeBinding("Checkboxes", expr.varname, cb)
                # self.bindings = self.addBinding(binding)
                cbList.append(cb)
                j += 1
                i += 1

#        if hasattr(expr, "attributes"):
#            for item in expr.attributes:
#                if hasattr(item, 'position'):
#                    if hasattr(item.position.value, "r"):
#                        pass
#                    else:
#                        moveCheckboxbyKeyword(cbList)

        return cbList

    def moveCheckboxbyKeyword(self, cbList):

            pass

    def makeCheckbox(self,w,i,num, width, height):
        var = StringVar()
        op = Checkbutton(w, text=i, variable=var, anchor=W, bg = w.cget('bg'), highlightbackground=w.cget('bg'))
        op.place(x=width, y=height, bordermode="outside")
        return op

    def setCheckboxes(self, cb, win, expr):
        w = win.frames
        cbSize = cb[0][2]
        width = cb[0][0]
        height = cb[0][1]
        #cbRow = cb[0][0]
        #cbColumn = cb[0][1]
        ttlSize = cb[0][3]
        ttl = cb[1]
        for item in expr.attributes:
            if hasattr(item, "title"): # TEXT HERE
                if hasattr(item.title, "var"):

                    if (item.title.var in self.bindings):
                        a = self.bindings.get(item.title.var).bObject
                        special = ""
                        if (a[4] == BooleanValue('true')):
                            special += "bold "
                        if (a[5] == BooleanValue('true')):
                            special += "italic "
                        if (a[6] == BooleanValue('true')):
                            special += "underline"
                        special = special.strip()

                        font = (a[1], a[2], special)
                        ttl.configure(text=a[0], fg=a[3], font=font)
                        cb[1].place(x=width, y=height)
                        ttlSize = a[2] * 1.8# + 10
                    else:
                        raise GooeyError("No formatted text with that name.")
                else:
                    cb[1].place(x=width, y=height)
                    #ttlSize += 20
                    ttl.config(text=item.title.value, fg='black', font="system 10",bg = w.cget('bg'))
            elif hasattr(item, "options"):
                for a in cb[2:]:
                    a.place_forget()

                cb = cb[:2]
                i = 0
                j = 0
                isDefault = False
                while(i < len(item.options.options)):
                    if(item.options.options[i] != ""):
                        var = StringVar()
                        c = Checkbutton(w, text=item.options.options[i], variable=var, anchor=W,bg = w.cget('bg'),highlightbackground=w.cget('bg'))
                        c.configure(height=cbSize)
                        if (isDefault):
                            c.select()
                        # binding = self.makeBinding("Checkboxes", expr.varname, cb)
                        # self.bindings = self.addBinding(binding)
                        cb.append(c)
                        isDefault = False
                        j += 1
                    else:
                        isDefault = True
                    i += 1
            elif hasattr(item, "position"):
                if hasattr(item.position.value, "r"):
                    width = int(item.position.value.r)
                    height = int(item.position.value.c)
                else:
                    width, height = self.getPositionByKeyword(item.position.value)
            elif hasattr(item, "size"):
                cbSize = item.size.value

        cb[1].place(x=width, y=height)
        cb[1] = ttl
        cb[0] = [width, height, cbSize, ttlSize]
        height += ttlSize
        for i in cb[2:]:
            i.place(x=width, y=height)
            height += 20 * cbSize

        return cb

#    '''
#-------------------- RADIOBUTTONS--------------------
#    '''
#
#    #RADIOBUTTONS ARE A WORK IN PROGRESS
#    def makeRadioButtons(self,w,expr):
#        w=w.frames
#        rbList = []
#        selected = False
#        var = StringVar(master=w)
#        rbSize = 1
##        rbRow, rbColumn = 0, 0
#        width, height = 0, 0
#        rbTitle = "Untitled RadioButtons"
#        hasTitle = False
#        hasOptions = False
#        if hasattr(expr, "attributes"):
#            for item in expr.attributes:
#                if hasattr(item, 'position'):
#                    if hasattr(item.position.value, "r"):
#                        width = int(item.position.value.r)
#                        height = int(item.position.value.c)
##                        rbRow = int(item.position.value.r)
##                        rbColumn = int(item.position.value.c)
#                    else:
#                        width, height = self.getPositionByKeyword(item.position.value)
##                        rbRow, rbColumn = self.getPositionByKeyword(item.position.value)
#                if hasattr(item, 'size'):
#                    rbSize = item.size.value
#
#            rbList.append([width, height, rbSize])
#
#            for item in expr.attributes:
#                if(hasattr(item, 'title')): # TEXT HERE
#                    hasTitle = True
#                    rbTitle = ""
#                    if (hasattr(item.title, 'value')):
#                        rbTitle = item.title.value
#                    ttl = Label(w, text=rbTitle,bg = w.cget('bg'))
#                    ttl.place(x=width,y=height)
##                    ttl.place(x=rbColumn,y=rbRow)
#                    if hasattr(item.title, 'var'):
#                        if (item.title.var in self.bindings):
#                            a = self.bindings.get(item.title.var).bObject
#                            special = ""
#
#                            if (a[4] == BooleanValue('true')):
#                                special += "bold "
#                            if (a[5] == BooleanValue('true')):
#                                special += "italic "
#                            if (a[6] == BooleanValue('true')):
#                                special += "underline"
#                            special = special.strip()
#
#                            font = (a[1], a[2], special)
#                            ttl.configure(text=a[0], fg=a[3], font=font)
#                            height += a[2] * 1.8# + 10
##                            rbColumn += a[2] + 10
#                            rbList[0].append(a[2] + 10)
#                        else:
#                            raise GooeyError("No formatted text with that name.")
#                    else:
#                        ttl.configure(text=item.title.value)
#                        height += 22
##                        rbColumn += 22
#                        rbList[0].append(22)
#                    rbList.append(ttl)
#
#            if not hasTitle:
#                ttl = Label(w, text=rbTitle,bg = w.cget('bg'))
#                ttl.place(x=width,y=height)
#                height += 22
##                ttl.place(x=rbColumn,y=rbRow)
##                rbColumn += 22
#                rbList[0].append(22)
#                rbList.append(ttl)
#
#            for item in expr.attributes:
#                if(hasattr(item, 'options')):
#                    hasOptions = True
#                    count = 0
#                    for x in item.options.options:
#                        if (x == ""):
#                            count += 1
#                        if (count == 2):
#                            raise GooeyError("RadioButtons cannot have multiple default selected options.")
#
#                    i = 0
#                    j = 0
#                    while(i < len(item.options.options)):
#                        if (item.options.options[i] == ""):
#                            selected = True
#                        else:
#                            rb = self.makeRadioButton(w,item.options.options[i], j, width, height, var)
#                            rb.configure(height=rbSize)
#                            rb.deselect()
#                            rbList.append(rb)
#                            # if (selected):
#                            #     var.set(j)
#                            #     selected = False
#                            j += 1
#                        i += 1
#                elif(hasattr(item, 'title')):
#                    pass
#                elif(hasattr(item, 'position')):
#                    pass
#                elif(hasattr(item, 'size')):
#                    pass
#                else:
#                    raise GooeyError("Cannot make RadioButtons with an attribute that RadioButtons does not have.")
#
#            if not hasOptions:
#                i = 0
#                j = 0
#                while(i < 3):
#                    optionText = "Option " + str(i + 1)
#                    rb = self.makeRadioButton(w,optionText, j, width, height, var)
##                    rb = self.makeRadioButton(self.window,optionText, j, rbRow, rbColumn, var)
#                    height += 20 * rbSize
##                    rbColumn += 20 * rbSize
#                    rb.configure(height=rbSize)
#                    rbList.append(rb)
#                    j += 1
#                    i += 1
#
#        else:
#            rbTitle = "Untitled RadioButtons"
#            width, height = 0, 0
##            rbRow, rbColumn = 0, 0
#            rbSize = 1
#            ttl = Label(w, text=rbTitle,bg = w.cget('bg'))
#            ttl.place(x=width,y=height)
##            ttl.place(x=rbColumn,y=rbRow)
#            height += 22
##            rbColumn += 22
#            rbList.append([0, 0, 1, 22])
#            rbList.append(ttl)
#            i = 0
#            j = 0
#            while(i < 3):
#                optionText = "Option " + str(i + 1)
#                rb = self.makeRadioButton(w,optionText, j, width, height, var)
##                rb = self.makeRadioButton(self.window,optionText, j, rbRow, rbColumn, var)
#                height += 20 * rbSize
##                rbColumn += 20 * rbSize
#                rb.configure(height=rbSize)
#                rbList.append(rb)
#                j += 1
#                i += 1
#
#        return rbList
#
#    def makeRadioButton(self,w,i,num, width, height, v):
#        gg = Radiobutton(w, text=i, variable=v, value=num, anchor=W,bg = w.cget('bg'), highlightbackground=w.cget('bg'))
#        gg.place(x=width, y=height, bordermode="outside")
#        return gg
#
#    def setRadioButtons(self, rb, win, expr):
#        w = win.frames
#        rbSize = rb[0][2]
#        width = rb[0][0]
##        rbRow = rb[0][0]
#        height = rb[0][1]
##        rbColumn = rb[0][1]
#        ttlSize = rb[0][3]
#        ttl = rb[1]
#        for item in expr.attributes:
#            if hasattr(item, "title"):
#                if hasattr(item.title, "var"):
#
#                    if (item.title.var in self.bindings):
#                        a = self.bindings.get(item.title.var).bObject
#                        special = ""
#                        if (a[4] == BooleanValue('true')):
#                            special += "bold "
#                        if (a[5] == BooleanValue('true')):
#                            special += "italic "
#                        if (a[6] == BooleanValue('true')):
#                            special += "underline"
#                        special = special.strip()
#
#                        font = (a[1], a[2], special)
#                        ttl.configure(text=a[0], fg=a[3], font=font)
#                        rb[1].place(x=width, y=height)
#                        print("Just placed rb")
##                        rb[1].place(x=rbRow, y=rbColumn)
#                        ttlSize = int(a[2] * 1.8) #+ 10
#                    else:
#                        raise GooeyError("No formatted text with that name.")
#                else:
#                    rb[1].place(x=width, y=height)
##                    rb[1].place(x=rbRow, y=rbColumn)
#                    #ttlSize += 20
#                    ttl.config(text=item.title.value, fg='black', font="system 10")
#            elif hasattr(item, "options"):
#                for a in rb[2:]:
#                    a.place_forget()
#
#                rb = rb[:2]
#                i = 0
#                j = 0
#                var = StringVar(master=w)
#                while(i < len(item.options.options)):
#                    if (item.options.options[i] == ""):
#                        selected = True
#                    else:
#                        r = Radiobutton(w, text=item.options.options[i], variable=var, value=i, anchor=W,bg = w.cget('bg'), highlightbackground=w.cget('bg'))
#                        r.configure(height=rbSize)
#                        rb.append(r)
#                        # if (selected):
#                        #     var.set(j)
#                        #     selected = False
#                        j += 1
#                    i += 1
#            elif hasattr(item, "position"):
#                if hasattr(item.position.value, "r"):
#                    width = int(item.position.value.r)
##                    rbRow = int(item.position.value.r)
#                    height = int(item.position.value.c)
##                    rbColumn = int(item.position.value.c)
#                else:
#                    width, height = self.getPositionByKeyword(item.position.value)
##                    rbRow, rbColumn = self.getPositionByKeyword(item.position.value)
#            elif hasattr(item, "size"):
#                rbSize = item.size.value
#
#        rb[1].place(x=width, y=height)
##        rb[1].place(x=rbRow, y=rbColumn)
#        rb[1] = ttl
#        rb[0] = [width, height, rbSize, ttlSize]
##        rb[0] = [rbRow, rbColumn, rbSize, ttlSize]
#        height += ttlSize
##        rbColumn += ttlSize
#        for i in rb[2:]:
#            i.place(x=width, y=height)
##            i.place(x=rbRow, y=rbColumn)
#            height += 20 * rbSize
##            rbColumn += 20 * rbSize
#        return rb


    '''
-------------------- TEXT --------------------
    '''
    def makeDefaultText(self,w,defaults):
        tl = Label(w, text = defaults['text'], bg = w.cget('bg'))
        #needs position and size
        return tl

    def makeText(self,win,expr):
        w = win.frames
        defaults = self.getAllDefaults("Text")
        tl = self.makeDefaultText(w,defaults)
        #tl = Label(w, text="Text")
        width, height = 0, 0
        hide = False
        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'text'): # TEXT HERE
                    if hasattr(item.text, 'var'):
                        if (item.text.var in self.bindings):
                            a = self.bindings.get(item.text.var).bObject
                            special = ""

                            if (a[4] == BooleanValue('true')):
                                special += "bold "
                            if (a[5] == BooleanValue('true')):
                                special += "italic "
                            if (a[6] == BooleanValue('true')):
                                special += "underline"
                                special = special.strip()

                            font = (a[1], a[2], special)
                            tl.configure(text=a[0], fg=a[3], font=font)
                        else:
                            raise GooeyError("No formatted text with that name.")
                    else:
                        tl.configure(text=item.text.value)
                elif hasattr(item, 'position'):
                    if hasattr(item.position.value, "r"):
                        width = int(item.position.value.r)
                        height = int(item.position.value.c)
                    else:
                        width, height = self.getPositionByKeyword(tl, item.position.value)
                elif hasattr(item, 'color'):
                    color = self.checkRGBColor(item.color.value)
                    tl.configure(fg=color)
                elif hasattr(item, 'hidden'):
                    if item.hidden.value == "true":
                        hide = True
                else:
                    raise GooeyError("Can't set Text with an attribute that Text does not have.")
        #tl.grid(row=r, column=c, sticky=N+S+E+W)
        self.checkOccupied(tl, width, height)
        tl.place(x = width, y = height, bordermode="outside")
        if hide:
            tl.place_forget()
        return tl

    def setText(self,tl,win,expr):
        w = win.frames
        #r, c = 0, 0
        hide = False
        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'text'):
                    tl.configure(text=item.text.value)
                elif hasattr(item, 'position'):
                    if hasattr(item.position.value, "r"):
                        width = int(item.position.value.r)
                        height = int(item.position.value.c)
                    else:
                        width, height = self.getPositionByKeyword(tl, item.position.value)
                    self.checkOccupied(tl, width, height)
                    tl.place(x = width, y = height, bordermode="outside")
                elif hasattr(item, 'color'):
                    color = self.checkRGBColor(item.color.value)
                    tl.configure(fg=color)
                elif hasattr(item, 'hidden'):
                    if item.hidden.value == 'true':
                        hide = True
                        tl.place_forget()
                    elif item.hidden.value == 'false':
                        #####NOTE: THIS ISN'T GOING TO WORK COME BACK
                        tl.place(x=tl.winfo_x(), y=tl.winfo_y())
                else:
                    raise GooeyError("Can't set Text with an attribute that Text does not have.")
        #tl.grid(row=r, column=c, sticky=N+S+E+W)
        return tl

    def checkRGBColor(self,color):
        if color[0] == '(':
            color = color.replace("(","")
            color = color.replace(")","")
            color = color.replace(","," ")
            color = color.split(' ')
            rgbColor = "#%02x%02x%02x" % (int(color[0]), int(color[1]), int(color[2]))
            return rgbColor
        else:
            return color


    '''
-------------------- WINDOWS --------------------
    '''
    def makeDefaultWindow(self,w,defaults):
        '''Makes a window with default attributes'''
        #Configure the window with defaults
        w.deiconify()

        w.title(defaults['title'])

        #Set window size to default size
        w.configure(height=MED_WIN_SIZE, width=MED_WIN_SIZE)
        frames = self.setDefaultWindowSize(w, MED_WIN_SIZE, MED_WIN_SIZE)
        self.setWindowColor(frames,defaults['color'])


        return (w,frames)


    def setDefaultWindowSize(self, w, rows, columns):
        self.gRows = rows
        self.gColumns = columns
        backgroundColor = w.cget('bg')
        l = Frame(w, height = rows, width = columns)
        l.place(x = 0, y = 0, bordermode="outside")
        l.configure(bg = backgroundColor)
        return l


    def setWindowSize(self,w, frames,rows,columns):

        w.configure(height=rows,width=columns)
        frames.configure(height=rows,width=columns)


        return frames




    def setWindowColor(self,w,color):
        color = self.checkRGBColor(color)
        w.configure(bg = color)
        w.place(x = 0, y = 0, bordermode="outside")


    def makeWindow(self,w,expr):
        '''Makes a window given user attributes.
        It should set anything that the user has not specified to the defaults.'''
        #Construct the default window
        defaults = self.getAllDefaults("Window")
        (w,frames) = self.makeDefaultWindow(w,defaults)
        #If the user input any attributes, change the default window to reflect that
        if hasattr(expr, "attributes"):
            windowAttributeList = expr.attributes
            for item in windowAttributeList:

                if hasattr(item, 'color'):

                    self.setWindowColor(frames,item.color.value)
                elif hasattr(item,'size'):


                    if hasattr(item.size.value, "columns"):
                        rows = int(item.size.value.rows)
                        columns = int(item.size.value.columns)
                    else:
                        if item.size.value.lower() == "small":
                            rows = SMALL_WIN_SIZE
                            columns = SMALL_WIN_SIZE
                        elif item.size.value.lower() == "medium":
                            rows = MED_WIN_SIZE
                            columns = MED_WIN_SIZE
                        elif item.size.value.lower() == "large":
                            rows = LARGE_WIN_SIZE
                            columns = MED_WIN_SIZE

                    frames = self.setWindowSize(w,frames, rows, columns)




                elif hasattr(item, 'title'):
                    w.title(item.title.value)
                elif hasattr(item, 'font'):
                    pass
                elif hasattr(item, 'fontSize'):
                    pass
                elif hasattr(item, 'textColor'):
                    pass

        return (w,frames)




    #Takes in a master window binding and then uses frame and window object accordingly (should really just be doign stuff with frame)
    def setWindow(self,win,expr):

        w = win.bObject
        frames = win.frames
        '''Sets window attributes to those specified by the user.'''
        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'color'):

                    self.setWindowColor(frames,item.color.value)

                elif hasattr(item,'size'):

                    if hasattr(item.size.value, "columns"):
                        rows = int(item.size.value.rows)
                        columns = int(item.size.value.columns)
                    else:
                        if item.size.value.lower() == "small":
                            rows = SMALL_WIN_SIZE
                            columns = SMALL_WIN_SIZE
                        elif item.size.value.lower() == "medium":
                            rows = MED_WIN_SIZE
                            columns = MED_WIN_SIZE
                        elif item.size.value.lower() == "large":
                            rows = LARGE_WIN_SIZE
                            columns = LARGE_WIN_SIZE

                    self.setWindowSize(w,frames, rows, columns)


                elif hasattr(item, 'title'):
                    w.title(item.title.value)
                elif hasattr(item, 'font'):
                    pass
                elif hasattr(item, 'fontSize'):
                    pass
                elif hasattr(item, 'textColor'):
                    pass
                else: # raiseGooeyError
                    err = "Cannot set an attribute that Window does not have. Window only has the following attributes: "
                    for key in self.getAllDefaults('Window').keys():
                        err += str(key) + ', '
                    err = err[:-2]
                    raise GooeyError(err)
        return win




    '''
-------------------- TEXT BOX --------------------
    '''
    def makeDefaultTextBox(self,w,defaults):
        '''Makes a TextBox with default attributes'''
        t = Text(w)
        t.insert(END,defaults['text'])
        #need
        #title
        #Position
        #size
        #hidden
        if defaults['size'] == "small":
            TextBoxWidth = SMALL_TEXTBOX_WIDTH
            TextBoxHeight = SMALL_TEXTBOX_HEIGHT
        elif defaults['size'] == "medium":
            TextBoxWidth = MED_TEXTBOX_WIDTH
            TextBoxHeight = MED_TEXTBOX_HEIGHT
        elif defaults['size'] == "large":
            TextBoxWidth = LARGE_TEXTBOX_WIDTH
            TextBoxHeight = LARGE_TEXTBOX_HEIGHT
        t.configure(width=TextBoxWidth, height = TextBoxHeight, borderwidth=4)
        return t

    def makeTextBox(self,win,expr):
        w = win.frames
        '''Makes a text box with the user defined attributes.'''
        defaults = self.getAllDefaults("TextBox")
        t = self.makeDefaultTextBox(w,defaults)
        width, height = 0, 0
        hide = False
        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'text'): # TEXT HERE
                    t.delete("1.0",END)
                    t.insert(END, item.text.value)
                elif hasattr(item, 'position'):
                    if hasattr(item.position.value, "r"):
                        width = int(item.position.value.r)
                        height = int(item.position.value.c)
                    else:
                        width, height = self.getPositionByKeyword(t, item.position.value)
                elif hasattr(item, 'color'):
                    color = self.checkRGBColor(item.color.value)
                    t.configure(bg=color)
                elif hasattr(item, 'size'):
                    if item.size.value == "small":
                        TextBoxWidth = SMALL_TEXTBOX_WIDTH
                        TextBoxHeight = SMALL_TEXTBOX_HEIGHT
                    elif item.size.value == "medium":
                        TextBoxWidth = MED_TEXTBOX_WIDTH
                        TextBoxHeight = MED_TEXTBOX_HEIGHT
                    elif item.size.value == "large":
                        TextBoxWidth = LARGE_TEXTBOX_WIDTH
                        TextBoxHeight = LARGE_TEXTBOX_HEIGHT
                    else:
                        TextBoxWidth = item.size.value.columns
                        TextBoxHeight = item.size.value.rows
                    t.configure(width=TextBoxWidth, height = TextBoxHeight)
                elif hasattr(item, 'hidden'):
                    if item.hidden.value == "true":
                        hide = True
                else:
                    raise GooeyError("Can't make Textbox with an attribute that Textbox does not have.")
                    # Note: should be gooey error

        self.checkOccupied(t, width, height)
        t.place(x = width, y = height, bordermode="outside")
        if hide:
            t.place_forget(x=t.winfo_x(), y=t.winfo_y()) #Note: this will not work
        return t

    def setTextBox(self,t,win,expr):
        w = win.frames
        hide = False
        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'text'): #TEXT HERE
                    t.delete("1.0",END)
                    t.insert(END, item.text.value)
                elif hasattr(item, 'position'):
                    if hasattr(item.position.value, "r"):
                        width = int(item.position.value.r)
                        height = int(item.position.value.c)
                    else:
                        width, height = self.getPositionByKeyword(t, item.position.value)
                    self.checkOccupied(t, width, height)
                    t.place(x = width, y = height, bordermode="outside")
                elif hasattr(item, 'color'):
                    color = self.checkRGBColor(item.color.value)
                    t.configure(bg=color)
                elif hasattr(item, 'size'):
                    if item.size.value == "small":
                        TextBoxWidth = SMALL_TEXTBOX_WIDTH
                        TextBoxHeight = SMALL_TEXTBOX_HEIGHT
                    elif item.size.value == "medium":
                        TextBoxWidth = MED_TEXTBOX_WIDTH
                        TextBoxHeight = MED_TEXTBOX_HEIGHT
                    elif item.size.value == "large":
                        TextBoxWidth = LARGE_TEXTBOX_WIDTH
                        TextBoxHeight = LARGE_TEXTBOX_HEIGHT
                    else:
                        TextBoxWidth = item.size.value.columns
                        TextBoxHeight = item.size.value.rows
                    t.configure(width=TextBoxWidth, height = TextBoxHeight, borderwidth=4)
                elif hasattr(item, 'hidden'):
                    if item.hidden.value == "true":
                        hide = True
                        t.place_forget() #Note: won't work yet
                    elif item.hidden.value == "false":
                        t.place(x=t.winfo_x(), y=t.winfo_y())
                else:
                    raise GooeyError("Can't set Textbox with an attribute that Textbox does not have.")
                    #Note: raise gooey error

        return t


    '''
-------------------- BUTTONS --------------------
    '''
    def checkOccupied(self,obj, width, height):

        # print("\n\n\nCHECKOCCUPIED")


        # Checks to make sure nothing is in the space the user is trying to place an object
        # If something is there, raise an error saying which object is there, try again, and do not place object
        #print("this is the window height",self.winBinding.bObject.winfo_height())
        winHeight = self.winBinding.bObject.winfo_reqheight()
        winWidth = self.winBinding.bObject.winfo_reqwidth()

        # print(winHeight, winWidth)
#        winHeight = self.winBinding.bObject.winfo_height()
#        winWidth = self.winBinding.bObject.winfo_width()



        if obj.winfo_x()+obj.winfo_reqwidth() > winWidth:
            raise GooeyError("Object placed outside window. Choose a new width")
        if obj.winfo_y()+obj.winfo_reqheight() > winHeight:
            raise GooeyError("Object placed outside window. Choose a new height")
        #Go through the bindings and make sure we're not placing on top of other objects
        #See children of root window

        kids = self.winBinding.frames.winfo_children()

        # print("Here are the children",kids)
        for child in kids:
            pass
            # print("kid x",child.winfo_x())
#            print("HERE IS OUR CHILD:", child)
#            if child != obj:
#                print("here's our child's info")
#                print(child.winfo_pointerx(), child.winfo_pointery())
#            else:
#                print("Here's obj",obj)
            # else:
        #    print("Everything is hunky dory")
        #Check and raise an error if the object will appear outside the edge of the window, so fuck you



    def makeDefaultButton(self, w, defaults):
        '''Makes a button with default attributes'''
        #This is the current background color of the window
        #We need this to correct for padding issues on the mac
        hB = w.cget('bg')
        b = Button(w, highlightbackground = hB)
        #Need to add in position, size, color?
        b.configure(text=defaults['text'])
        return b


    def makeButton(self,w,expr):
        win = w.frames

        '''Makes a button by taking in the window the button should be made in
        and the expression given by the user.'''
        defaults = self.getAllDefaults('Button')
        b = self.makeDefaultButton(win,defaults)
        width, height = 0, 0
        hide = False
        if hasattr(expr, "attributes"):
            buttonAttributeList = expr.attributes
            for item in buttonAttributeList:
                if hasattr(item, 'color'):
                    color = self.checkRGBColor(item.color.value)
                    b.configure(bg=color)
                if hasattr(item, 'text'):
                    if hasattr(item.text, 'var'):
                        if (item.text.var in self.bindings):
                            if self.bindings[item.text.var].bType == "String":
                                b.configure(text=self.bindings[item.text.var].bObject)
                            else: #TODO: if Formatted text, check if not type you can change text to.
                                a = self.bindings.get(item.text.var).bObject
                                special = ""

                                if (a[4] == BooleanValue('true')):
                                    special += "bold "
                                if (a[5] == BooleanValue('true')):
                                    special += "italic "
                                if (a[6] == BooleanValue('true')):
                                    special += "underline"
                                special = special.strip()


                                font = (a[1], a[2], special)
                                b.configure(text=a[0], fg=a[3], font=font)

                        else:
                            raise GooeyError("The variable "+str(item.text.var)+" is undefined.")
                    else:
                        b.configure(text=item.text.value)
                elif hasattr(item,'size'):
                    if hasattr(item.size.value, 'columns'):
                        if item.size.value.columns in self.bindings:
                            sizeBinding = self.bindings[item.size.value.columns]
                            if sizeBinding.bType == "Integer":
                                b.configure(width=sizeBinding.bObject)
                            else:
                                raise GooeyError("Cannot set Button size attribute to variable of type "+str(sizeBinding.bType))
                        else:
                            b.configure(width=item.size.value.columns)
                    else: #TODO: button size by keyword
                        pass
                elif hasattr(item,'position'):
                    if hasattr(item.position.value, "r"):
                        if item.position.value.r in self.bindings:
                            posRowBinding = self.bindings[item.position.value.r]
                            if posRowBinding.bType == "Integer":
                                width = posRowBinding.bObject
                            else:
                                raise GooeyError("Cannot set Button position attribute to variable of type "+str(posRowBinding.bType))
                        else:
                            width = int(item.position.value.r)
                        if item.position.value.c in self.bindings:
                            posColBinding = self.bindings[item.position.value.c]
                            if posColBinding.bType == "Integer":
                                height = posColBinding.bObject
                            else:
                                raise GooeyError("Cannot set Button position attribute to variable of type "+str(posRowBinding.bType))
                        else:
                            height = int(item.position.value.c)
                    else:
                        width, height = self.getPositionByKeyword(b, item.position.value)

                # These are the action statements
                elif hasattr(item, 'action'):
                    if item.action.funcname in self.bindings:
                        f = self.bindings.get(item.action.funcname).bObject
                        b.configure(command=f)
                    else: #Gooey code function
                        args = []
                        if hasattr(item.action, "arguments"):
                            args = item.action.arguments
                        b.configure(command=lambda: self.gooeyCallAction(a, args)) #figure out params for this
                        #run this like we're running a function definition


                    # else:
                    #     print("You have entered a command that is not defined")
					
                elif hasattr(item, 'hidden'):
                    if item.hidden.value == "true":
                        hide = True
                else:
                    raise GooeyError("Can't set Button with attribute Button doesn't have.")
        #b.grid(row=r, column=c, sticky=N+S+E+W)
        self.checkOccupied(b, width, height)
        b.place(x = width, y = height, bordermode="outside")
        if hide:
            b.place_forget() #Note won't work yet
        return b


    def gooeyCallAction(self,action, params):
        #Create an interpreter with the bindings and winbinding of this interpreter
        #Execute the code in this button action
        #Modify global bindings accordingly

        gooeyStr = "run "+str(action)+"("
        for param in range(len(params)):
            if params[param].__class__.__name__ == "QuotedText":
                gooeyStr += "\"" + str(params[param]) + "\""
            else:
                gooeyStr += str(params[param])
            if param < len(params)-1:
                gooeyStr += ", "
        gooeyStr += ")."
        ast = parse(gooeyStr, Program)
        newI = Interpreter(self.winBinding.bObject, self.winBinding, self.bindings)
        (self.bindings, self.winBinding) = newI.interpret(ast)


    def setButton(self,b,win,expr):
        w = win.frames
        '''Sets button based on user attributes.'''
        buttonAttributeList = expr.attributes
        for item in buttonAttributeList:
            if hasattr(item, 'color'):
                color = self.checkRGBColor(item.color.value)
                b.configure(bg=color)
            if hasattr(item, 'text'):
                if hasattr(item.text, 'var'):
                    if (item.text.var in self.bindings):
                        if self.bindings[item.text.var].bType == "String":
                            b.configure(text=self.bindings[item.text.var].bObject)
                        else: #TODO: if Formatted text, check if not type you can change text to.
                            a = self.bindings.get(item.text.var).bObject
                            special = ""

                            if (a[4] == BooleanValue('true')):
                                special += "bold "
                            if (a[5] == BooleanValue('true')):
                                special += "italic "
                            if (a[6] == BooleanValue('true')):
                                special += "underline"
                            special = special.strip()

                            font = (a[1], a[2], special)
                            b.configure(text=a[0], fg=a[3], font=font)
                        #else:
                            #raise GooeyError("Can't set text to variable of type "+str(self.bindings[item.text.var].bType)+".")
                    else:
                        raise GooeyError("The variable "+str(item.text.var)+" is undefined.")
                else:
                    b.configure(text=item.text.value)

            elif hasattr(item,'size'):
                if hasattr(item.size.value, 'columns'):
                    if item.size.value.columns in self.bindings:
                        sizeBinding = self.bindings[item.size.value.columns]
                        if sizeBinding.bType == "Integer":
                            b.configure(width=sizeBinding.bObject)
                        else:
                            raise GooeyError("Cannot make Button size attribute with variable of type "+str(sizeBinding.bType))
                    else:
                        b.configure(width=item.size.value.columns)
                else: # TODO: button size by keyword
                    pass


            elif hasattr(item,'position'):
                if hasattr(item.position.value, "r"):
                    if item.position.value.r in self.bindings:
                        width = self.bindings[item.position.value.r].bObject
                    else:
                        width = int(item.position.value.r)
                    if item.position.value.c in self.bindings:
                        height = self.bindings[item.position.value.c].bObject
                    else:
                        height = int(item.position.value.c)
                else:
                    width, height = self.getPositionByKeyword(b, item.position.value)
                #b.grid(row=r, column=c, sticky=N+S+E+W)
                self.checkOccupied(b, width, height)
                b.place(x=width, y=height)

            elif hasattr(item, 'action'):
                #Cast action to string, otherwise you cannot find right action
                #This is temporary until I can call the action as a direct line in the command
                act = str(item.action.funcname)
                a = actionbuttons.findAction(item)
                if actionbuttons.checkActions(a):
                    b.configure(command=lambda: actionbuttons.callAction(w,item,act))
                else: #Gooey code function
                    args = []
                    if hasattr(item.action, "arguments"):
                        args = item.action.arguments
                    b.configure(command=lambda: self.gooeyCallAction(a, args)) #figure out params for this
                    #run this like we're running a function definition
                # else:
                #     print("You have entered a command that is not defined")
            elif hasattr(item, 'hidden'):
                if item.hidden.value == 'false':
                    b.place(x=b.winfo_x(), y=b.winfo_y()) #Note: won't work yet
                elif item.hidden.value == 'true':
                    b.place_forget() #Note: won't work yet
            else:
                raise GooeyError("Can't make Button with attribute Button doesn't have.")
        return b

    def fixObjectPadding(self,color):
        '''Fixes the padding around the buttons'''
        for i in self.bindings.keys():
            if self.bindings[i].bType == "Button":
                self.bindings[i].bObject.configure(highlightbackground = color)
            elif self.bindings[i].bType == "Checkboxes":
                for j in range(1,len(self.bindings[i].bObject)):
                    self.bindings[i].bObject[j].configure(bg = color)

        return self.bindings








    '''
-------------------- MENUS --------------------
    '''

    def makeDefaultMenu(self,w,defaults):
        pass

    def makeMenu(self,win,expr):

        #Not CAN ONLY HAPPEN IN ROOT WINDOW

        w = win.bObject

        rootMenu = None
        children = w.winfo_children()
        for c in children:
            if type(c).__name__ == "Menu":
                rootMenu = c
        if hasattr(expr,'attributes'):
            for item in expr.attributes:

                if hasattr(item,'menuoption'):

                    mop = item.menuoption.value
                    for mopItem in mop:
                        if hasattr(mopItem, 'text'):
                            if hasattr(mopItem, 'action'):
                                #mopItem.action = Menu(rootMenu,tearoff=0)
                                subm = Menu(rootMenu,tearoff=0)
                                binding = self.makeBinding("MenuItem",str(mopItem.action),subm)
                                self.bindings = self.addBinding(binding)
                                rootMenu.add_cascade(label=mopItem.text,menu=subm)
        w.config(menu=rootMenu)
        return rootMenu

    def makeDefaultMenuItem(self,w,defaults):
        pass

    def setMenu():
        pass

    def makeMenuItem(self,win,expr):
        w = win.bObject
        menuItem = None
        rootMenu = None
        children = w.winfo_children()
        for c in children:
            if type(c).__name__ == "Menu":
                rootMenu = c


        #check if menu item has already been defined as a child of some other menu or menuitem
        for key in self.bindings:

            if self.bindings[key].bType == "Menu":
                # print(expr.varname)
                if expr.varname in self.bindings.keys():
                    #print(self.bindings[key])
                    #binding found, add to submenu to rootMenu

                    #subMenu = Menu(self.bindings[key].bObject, tearoff=0)
                    subMenu = self.bindings[expr.varname].bObject
                    if hasattr(expr, 'attributes'):
                        for item in expr.attributes:
                            if hasattr(item,'menuoption'):
                                mop = item.menuoption.value
                                for mopItem in mop:
                                    if hasattr(mopItem, 'text'):
                                        if hasattr(mopItem, 'action'):
                                            subMenu.add_command(label=mopItem.text,command=None)#change this

                    # menuItem = subMenu
                    # w.config(menu=self.bindings[key].bObject)

        # return menuItem


        def setMenuItem():
            pass


    '''
-------------------- IMAGES - not in window right now! --------------------
    '''
    def makeDefaultImage(self,w,defaults):
        pass
    def makeImage(self, win, expr):
        w = win.frames
        '''Makes a images with the user defined attributes.'''
        defaults = self.getAllDefaults("Image")
        #(i,l) = self.makeDefaultImage(w,defaults)
        width, height = 0, 0
        hide = False
        if hasattr(expr, "attributes"):
            for item in expr.attributes:
                if hasattr(item, 'source'):


                    ######## Images only work when you read in from text file, otherwise source path is different

                    #directory = os.getcwd()
                    #print("OS : ", os.getcwd())
                    #directory = str(sys.path[0])
                    #directory = directory.append('/apple.gif')
                    #print("CURRENT WORKING DIR IS: ", directory+'/apple.gif')
                    #print("DIRECTORY IS: ", sys.path.append(os.path.dirname(os.path.abspath(__file__)))
                    #i = PhotoImage(file=open(directory+'/apple.gif'))


                    i = PhotoImage(file=item.source.value)
                    l = Label(w, image=i, bg = w.cget('bg'))
                    l.image = i
                else:
                    i = PhotoImage(file="gooeylogosmallest.gif")
                    raise GooeyError("Cannot make Image with attribute Image does not have.") # Note: change gooey error
                if hasattr(item, 'position'):
                        if hasattr(item.position.value, "r"):
                            width = int(item.position.value.r)
                            height = int(item.position.value.c)
                        else:
                            width, height = self.getPositionByKeyword(i, item.position.value)
        #l.grid(row=r, column=c, sticky=N+S+E+W)
        self.checkOccupied(l, width, height)
        l.place(x = width, y = height, bordermode="outside")
        if hide:
            l.grid_remove
        return l

    def setImage():
        pass




    '''
-------------------- HELPER METHODS --------------------
    '''
    def makeBinding(self,t,v,o,p=[],f=[]):
        '''Makes a binding for the object.'''
        binding = Binding(t,v,o,p,f)
        return binding

    def addBinding(self,b):
        '''Takes a binding and adds to the dictionary of bindings.'''
        self.bindings[b.varname] = b
        return self.bindings
    def get_by_varname(self,v):
        if v in self.bindings:
            return self.bindings[v].bObject
        else:
            return False
		
		
    def getFunctionLineAction(self, expr):
        '''Interprets one line of a function, returns the action that line does.'''
    #        if(expr.__class__.__name__ == "Return"):
    #            return expr
    #        else:
        return expr.lineAction



    def getOptions(self,expr):
        '''Get list of options, ie: make MenuItem with options [red green blue]. '''
        # print("Getting options")
        options = []
        for item in expr.attributes:
            if hasattr(item, 'menuoption'):
                # print("has a menuoption")
                mop = item.menuoption.value
                # print("mop",mop)
                for mopItem in mop:
                    # print('MOPITEM',mopItem)
                    if hasattr(mopItem,'action'):
                        # print('mopitemaction',mopItem.action)
                        options.append(mopItem.action)
            else:
                return None
        return options


    def getAllDefaults(self, typeName):
        '''Given a Gooey type name, like "Window" or "Button", consult our matrix
        and return the predetermined default attributes for that type'''
        defaults = {}
        for i in range(0,NUM_ATTRIBUTES):
            defaultAttr = getDefault(typeName, i)
            defaults[AttrName(i).name] = defaultAttr
            #Need to figure out how to return these
        return defaults

    def checkVarname(self,exp):
        if hasattr(exp, "varname"):
            #if expr.varname in bindings:
            if exp.varname in self.bindings:
                raise GooeyError(str(exp.varname)+" already defined.")


    def getObject(self,exp):
        if exp.varname in self.bindings:
            return self.bindings[exp.varname]
        else:
            raise GooeyError(str(exp.varname)+" undefined.")


    def getPositionByKeyword(self, obj, keyword):
        winwidth = self.winBinding.bObject.winfo_reqwidth()
        winheight = self.winBinding.bObject.winfo_reqheight()
        objwidth = obj.winfo_reqwidth()
        objheight = obj.winfo_reqheight()

        if keyword == "center":
            w = math.floor(winwidth/2 - objwidth/2)
            h = math.floor(winheight/2 - objheight/2)
        elif keyword == "top":
            w = math.floor(winwidth/2 - objwidth/2)
            h = 0
        elif keyword == "bottom":
            w = math.floor(winwidth/2 - objwidth/2)
            h = math.floor(winheight - objheight) - 1
        elif keyword == "left":
            w = 0
            h = math.floor(winheight/2 - objheight/2)
        elif keyword == "right":
            w = math.floor(winwidth - objwidth)
            h = math.floor(winheight/2-objheight/2)
        elif keyword == "topleft":
            w = 0
            h = 0
        elif keyword == "topright":
            w = math.floor(winwidth - objwidth)
            h = 0
        elif keyword == "bottomleft":
            w = 0
            h = math.floor(winheight - objheight) - 1
        elif keyword == "bottomright":
            w = winwidth - objwidth - 1
            h = math.floor(winheight - objheight) - 1

        return w, h
