# drawing figures with natural language commands
# presupposes 'gf -make DrawEng.gf (DrawSwe.gf ...)'

import pgf
from graphics import *
import sys
from random import randrange

# we assume this abstract syntax
absmodule = "Draw"

# change this to change input language
langname = absmodule + "Eng"

# the size of canvas
hsize, vsize = 1000,1000

# the mid point of the canvas
midpoint = (hsize/2,vsize/2)

# unit size granularity
sizeunit = hsize//10

# big and small size factors
bigsize = 2
smallsize = 0.2

# limits of radius and diameter/2
maxradius = sizeunit
minradius = sizeunit/2

# distance of movement
distunit = 2*sizeunit

def execute(command,win):
  "top level: execute a Command in a window (given in main)"
  fun,args = command.unpack()

  if fun == "drawCommand":
    obj = shape(args[0])
    obj.draw(win)
    return str(args[0]),obj,fun

  if fun == "removeCommand":
    key = reference(args[0])
    return key,None,fun
  
  if fun == "moveCommand":
    key = reference(args[0])
    return key,direction(args[1]),fun

def reference(objectref):
  fun,args = objectref.unpack()
  if fun == "theObjectRef":
    return(str(args[0]))
  else:
    return(str(objectref))

def shape(obj):
  "draw a Shape of random size and position, possibly with colour and rough size specified"
  fun,args = obj.unpack()

  sz,xx = args[0].unpack()
  if sz == "big_Size":
    factor = bigsize
  elif sz == "small_Size":
    factor = smallsize
  else:
    factor = 1
    
  midx,midy = midpoint
  x1 = midx + randrange(int(-midx),int(midx),1)
  y1 = midy + randrange(int(-midy),int(midy),1)
  r  = factor * randrange(int(minradius), int(maxradius), 1)
  d  = 2 * r
  x2 = x1 + d
  y2 = y1 + d
  sh,xx = args[2].unpack()
  if sh == "circle_Shape":
    shap = Circle(Point(x1,y1),r)
  elif sh == "square_Shape":
    shap = Rectangle(Point(x1,y1),Point(x2,y2))
  else:
    shap = None

  co,xx = args[1].unpack()
  if co == "green_Colour":
    shap.setFill('green')
  elif co == "red_Colour":
    shap.setFill('red')
  elif co == "blue_Colour":
    shap.setFill('blue')
  elif co == "yellow_Colour":
    shap.setFill('yellow')
  else:
    pass
    
  return shap

def direction(place):
  fun,args = place.unpack()
  if fun == "upPlace":
    return 0,-distunit
  if fun == "downPlace":
    return 0,distunit
  if fun == "leftPlace":
    return -distunit,0
  if fun == "rightPlace":
    return distunit,0
  else:
    return randrange(-2*distunit,2*distunit,1),randrange(-2*distunit,2*distunit,1)

def addRef(ref,obj,refs):
    "adds a reference and object to the top of the stack"
    return [(ref,obj)] + refs

def lookupRef(ref,refs):
    "return the first value and index of ref in a list of pairs refs"
    i = 0
    for ro in refs:
        r,obj = ro
        if matchRef(ref,r):
            return r,obj,i
        else:
            i = i + 1
    return None,None,None

def removeRef(ref,refs):
    "remove the first pair matching ref in refs"
    r,obj,i = lookupRef(ref,refs)
    refs.pop(i)
    return refs

def matchRef(ref,r):
    if ref == "itObjectRef":
        return True
    else:
        refws = ref.split()
        rws = r.split()
        m = True
        for i in range(1,4):
          if (refws[i][0:2] != "no") and (refws[i] != rws[i]):
              return False
        return m

def main():
  "initialize with a window, process Command input line by line; optional language argument"
  win = GraphWin("GF Draw", hsize, vsize)
  refs = []
  latest = "it"
  gr  = pgf.readPGF(absmodule + ".pgf")
  lang = langname
  if len(sys.argv) > 1:
    lang = absmodule + sys.argv[1]
  eng = gr.languages[lang]
  while True:
      try:
          line = input("")
      except EOFError:
          break
      if not(line):
          pass
      else:
          try:
              px = eng.parse(line.lower())
              p,tree = px.__next__()
              key,obj,co = execute(tree,win)
              if co == "drawCommand":
                  refs = addRef(key,obj,refs)
              elif co == "removeCommand":
                  ref,sh,i = lookupRef(key,refs)
                  if sh is None:
                    print("no such object")
                  else:
                    sh.undraw()
                    refs = removeRef(key,refs)
              elif co == "moveCommand":
                  x,y = obj
                  ref,sh,i = lookupRef(key,refs)
                  if sh is None:
                    print("no such object")
                  else:
                    sh.move(x,y)
                    refs = [(ref,sh)] + refs[:i] + refs[i+1:]
              else:
                  print("nothing else can be done")
              print(refs) ## debugging
          except pgf.ParseError:
              print("# NO PARSE", line)

main()


