#!/usr/bin/env python
# My First Python Program
# A terminal-window port of I7
# We assume that we're using it on the XO, so we can afford to be sloppy about
#  assuming what software is available.

import commands, string, os, sys, getopt, re

def printprompt(prompt="> ", default=""):
    r=""
    while not r:
        r=raw_input(prompt).rstrip()
        if not r:
            r = default
        if not r:
            print "I beg your pardon?"
    return r

def initialsettings():
    global settings
    settings = { "zcode":5 ,"blorb":1, "zsuf":"z5","format":"zcode" }

def initialidesettings():
    global idesettings
    idesettings['EDITOR'] = ""
    try:
        idesettings['EDITOR'] = os.environ['VISUAL']
    except:
        pass
    if idesettings['EDITOR'] == '':
        try:
            idesettings['EDITOR'] = os.environ['EDITOR']
        except:
            pass
    if not idesettings['EDITOR']:
        idesettings['EDITOR'] = "/usr/bin/nano"
    idesettings['EDITORBG'] = 0
    idesettings['BROWSER'] = ""
    try:
        idesettings['BROWSER'] = os.environ['BROWSER']
    except:
        pass
    idesettings['BROWSERBG'] = 0
    idesettings['ZTERPBG'] = 0
    idesettings['GTERPBG'] = 0
    idesettings['PREVIOUS'] = ""
    resetprefixsettings()

def resetprefixsettings():
    global NI, I6, BLORB, idesettings
    NI = idesettings['PREFIX'] + "/libexec/ni"
    I6 = idesettings['PREFIX'] + "/libexec/inform-6.31-biplatform"
    BLORB = idesettings['PREFIX'] + "/libexec/cBlorb"
    idesettings['ZTERP'] = idesettings['PREFIX'] + "/libexec/dumb-frotz"
    idesettings['GTERP'] = idesettings['PREFIX'] + "/libexec/dumb-glulxe"

def getoptions():
    global NONINTERACTIVE, idesettings, opt_s, proj
    try:
        opts, args = getopt.getopt(sys.argv[1:], "c:r:s:p:",
                                   ["compile=", "release=",
                                    "setting=","prefix="])
    except getopt.GetoptError:
        sys.exit(2)

    for o, a in opts:
        if o == "-c":
            NONINTERACTIVE=1
            proj = a
        if  o == "-r":
            NONINTERACTIVE=2
            proj = a
        if o == "-s":
            opt_s=a
        if o == "-p":
            idesettings['PREFIX'] = os.path.realpath(a)

    while not os.path.isdir(idesettings['PREFIX'] + "/share/inform7"):
        print ""
        print "I could not find the Inform 7 libraries under " + idesettings['PREFIX']
        if NONINTERACTIVE:
            sys.exit(2)

        idesettings['PREFIX']=printprompt("Please enter the path where you installed the i7 package > ");

def checkinitialdirs():
    if not NONINTERACTIVE:
        print "\n\n\n"
        # This should be adjusted for XO Activity-based paths
        if (not os.path.isdir(HOME + "/Inform/Documentation")) or (not os.path.isdir(HOME + "/Inform/Extensions")):
            print "This looks like the first time you've run Inform 7."
            print "I will now create the directories Inform, Inform/Extensions, and"
            print "Inform/Documentation in your home directory %s.\n" % HOME
            if not os.path.isdir(HOME + "/Inform/Extensions"):
                os.makedirs(HOME + "/Inform/Extensions")
            if not os.path.isdir(HOME + "/Inform/Documentation"):
                os.makedirs(HOME + "/Inform/Documentation")
    
        
def readideprefs(preffile):
    global idesettings
    prefs=open(preffile,"rU")
    try:
        print "opening %s" % preffile
        for line in prefs:
            line=line.strip()
            keypair = line.split("=")
            try:
                val=keypair[1].strip()
                key=keypair[0].strip()
                if key[-2:] == "BG":
                    val=int(val)
                idesettings[key]=val

            except IndexError:
                pass
    finally:
        prefs.close()
            
def writeideprefs():
    try:
        prefs=open(HOME+"/.i7rc","w")
        print >> prefs,"#These are specific to the XO stdio IDE\n"
        print >> prefs,"NAME       = "+idesettings['NAME']
        print >> prefs,"PREFIX     = "+idesettings['PREFIX']
        print >> prefs,"EDITOR     = "+idesettings['EDITOR']
        print >> prefs,"BROWSER    = "+idesettings['BROWSER']
        print >> prefs,"ZTERP      = "+idesettings['ZTERP']
        print >> prefs,"GTERP      = "+idesettings['GTERP']
        print >> prefs,"EDITORBG   = "+("%d" % idesettings['EDITORBG'])
        print >> prefs,"BROWSERBG  = "+("%d" % idesettings['BROWSERBG'])
        print >> prefs,"ZTERPBG    = "+("%d" % idesettings['ZTERPBG'])
        print >> prefs,"GTERPBG    = "+("%d" % idesettings['GTERPBG'])
        print >> prefs,"PREVIOUS   = "+idesettings['PREVIOUS']
    finally:
        prefs.close()

def checkname():
    global idesettings
    if ((not NONINTERACTIVE) and (not idesettings['NAME'])):
        idesettings['NAME'] = printprompt("Please enter your name > ")

def introloop():
    global proj
    while 1:
        if NONINTERACTIVE:
            proj = openproj()
            if proj:
                break
            sys.exit(1)

        print "WELCOME TO INFORM 7\n\n"
        print "(S)tart a new project."
        print "(O)pen an existing project."
        print "(Q)uit.\n"
        proj = os.getcwd()
        choice = printprompt()
        choice = choice[0].upper()
        if choice == "S":
            proj = newproj()
        elif choice == "O":
            proj = openproj()
        elif choice == "Q":
            print "Thanks for putting up with this so-called interface!"
            sys.exit(0)
        else:
            print "I don't see any %s here." % choice

        if proj:
            break
    idesettings['PREVIOUS'] = proj
    return

def detilde(dir):
    if dir == "~":
        return HOME
    if dir:
        if dir[0] == "~":
            if dir[1] == "/":
                dir = HOME + dir[1:]
            else:
                # Close enough for government work
                dir = "/home/" + dir[1:]
    return dir

def newproj():
    m = printprompt("Location of new project [%s] >" % proj,proj)
    if m[-7:] != ".inform":
        print m + " does not end in \".inform\" -- it will be appended"
        m = m + ".inform"
    m=detilde(m)
    l = os.path.abspath(m)

    if not l:
        print "Uh oh!  I can't turn %s into a directory name!" % m
        return ""

    if os.path.isdir(l):
        print "Uh oh!  %s already exists." % l
        print "Maybe you meant (O)pen?"
        return ""

    # We should probably fake something so all this is really one bundled file
    #  for the XO
    try:
        for i in ["/Build", "/Source", "/Index"]:
            os.makedirs(l + i)
    except os.error:
        print "Could not create project in " + l
        os.rmdirs(l)
        return ""
    uuid = commands.getoutput("uuidgen")
    uuid = uuid.strip()
    if not uuid:
        # We KNOW uuidgen is on the XO
        print "Could not generate UUID.  That's bizarre."
        return ""
    try:
        uf=open(l + "/uuid.txt","w")
        print >> uf, uuid,
    finally:
        uf.close()
    # We know the file ends in .inform
    projname = os.path.basename(l)
    projname = projname[0:-7]
    try:
        story=open(l + "/Source/story.ni","w")
        print >> story,"\"%s\" by \"%s\"" % (projname,idesettings['NAME'])
    finally:
        story.close()
    writesettings(l)
    return l

def openproj():
    global proj
    if not NONINTERACTIVE:
        try:
            proj = idesettings['PREVIOUS']
        except:
            pass
    else:
        m=proj
    m = printprompt("Location of existing project [%s] >" % proj,proj)
    m = detilde(m)
    l = os.path.abspath(m)
    if not l:
        if not NONINTERACTIVE:
            print "Uh oh!  I can't turn %s into a directory name." % m
        return ""
    bad = 0
    if not os.path.isdir(l):
        bad = 1
        if not NONINTERACTIVE:
            print "Uh oh!  %s does not exist." % l
        if l[-7:] != ".inform":
            l = l + ".inform"
            if not NONINTERACTIVE:
                print "Trying %s..." % l
            if os.path.isdir(l):
                bad = 0
            else:
                if not NONINTERACTIVE:
                    print l + " still does not exist."
    if bad:
        if not NONINTERACTIVE:
            print "Maybe you meant (S)tart a new project?"
        return ""
    if not os.path.isfile(l+"/uuid.txt"):
        if not NONINTERACTIVE:
            print "Uh oh!  Cannot find UUID.  Refusing to believe this is a project!"
        return ""
    if not os.path.isfile(l+"/Source/story.ni"):
        if not NONINTERACTIVE:
            print "Dude, where's the story?  Not in %s/Source/story.ni!" % l
        return ""
    return l

def readsettings(pfile):
    try:
        prefs=open(pfile,"rU")
        state=0
        matchstr=re.compile("<integer>(\d+)</integer")
        for line in prefs:
            line=line.strip().lower()
            if line.find("<key>IFSettingCreateBlorb</key>".lower()) != -1:
                state = 1
            if line.find("<key>IFSettingZcodeVersion</key>".lower()) != -1:
                state = 2
            if state == 1:
                if line.find("<true/>") != -1:
                    settings['blorb'] = 1
                    state = 0
                if line.find("<false/>") != -1:
                    settings['blorb'] = 0
                    state =0
            if state == 2:
                m=matchstr.search(line)
                if m:
                    settings['zcode']=int(m.group(1))
                    state=0
        a=settings['zcode']
        zset(a)
    finally:
        prefs.close()

def writesettings(l):
    try:
        pfile=open(l+"/Settings.plist","w")
        if settings['blorb']:
            do_blorb="<true/>"
        else:
            do_blorb="<false/>"
        zver=str(settings['zcode'])
        print >> pfile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
        print >> pfile,"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
        print >> pfile,"<plist version=\"1.0\">"
        print >> pfile,"<dict>"
        print >> pfile,"        <key>IFCompilerOptions</key>"
        print >> pfile,"        <dict>"
        print >> pfile,"                <key>IFSettingNaturalInform</key>"
        print >> pfile,"                <true/>"
        print >> pfile,"        </dict>"
        print >> pfile,"        <key>IFInform6Extensions</key>"
        print >> pfile,"        <dict/>"
        print >> pfile,"                <key>IFLibrarySettings</key>"
        print >> pfile,"                <dict>"
        print >> pfile,"                        <key>IFSettingLibraryToUse</key>"
        print >> pfile,"                        <string>Natural</string>"
        print >> pfile,"                </dict>"
        print >> pfile,"                <key>IFMiscSettings</key>"
        print >> pfile,"                <dict>"
        print >> pfile,"                        <key>IFSettingInfix</key>"
        print >> pfile,"                        <false/>"
        print >> pfile,"                </dict>"
        print >> pfile,"                <key>IFOutputSettings</key>"
        print >> pfile,"                <dict>"
        print >> pfile,"                        <key>IFSettingCreateBlorb</key>"
        print >> pfile,"                        %s" % do_blorb
        print >> pfile,"                <key>IFSettingZcodeVersion</key>"
        print >> pfile,"                <integer>%s</integer>" % zver
        print >> pfile,"        </dict>"
        print >> pfile,"</dict>"
        print >> pfile,"</plist>"

    finally:
        pfile.close()

def zset(a):
    if a=="g" or a=="G":
        a=256
        settings['zcode']=a
    if (a != 5 ) and (a != 6 ) and (a != 8) and (a != 256):
        return 0
    if a == 256:
        settings['format']="glulx"
        settings['suffix']="gblorb"
        settings['zsuf']="ulx"
    else:
        settings['format']="zcode"
        settings['suffix']="zblorb"
        settings['zsuf']="z"+str(a)
    return a

def mainloop():
    while 1:
        if NONINTERACTIVE == 0:
            print "\n\nMAIN MENU\n\n"
            if not idesettings['BROWSER']:
                print "Set the environment variable BROWSER (or set your browser preferences in the"
                print "preference panel) to allow browsing the generated HTML index."
            if idesettings['EDITOR']:
                print "(E)dit the story with %s." % idesettings['EDITOR']
            else:
                print "Apply the editor of your choice (set in the preference panel, or in the"
                print "environment variables VISUAL or EDITOR) to %s/Source/story.ni" % proj
                print "After you have saved your work, do one of the following:"
            print "\n(C)ompile the story."
            print "(G)o -- compile and run the story."
            print "(R)elease the story.\n"
            if idesettings['BROWSER']:
                print "(I)ndex -- open the generated story index with %s.\n" % idesettings['BROWSER']
            print "Change (S)ettings."
            print "(Q)uit.\n"
            r = printprompt()
            r = r[0].upper()
            if r == "E" and idesettings['EDITOR']:
                s = proj + "/Source/story.ni"
                if os.path.isfile(s):
                    cmd = "\"%s\" \"%s\"" % (idesettings['EDITOR'],s)
                    if (idesettings['EDITORBG']):
                        cmd = cmd + " &"
                    os.system(cmd)
                else:
                    print "\n\n*** Cannot find story file %s! ***\n" % s
            elif r == "C":
                bad = compile()
                if bad:
                    print "\n\n*** COMPILATION HAD ERRORS\n"
                else:
                    print "\n\nCompile succeeded: test your game by running %s/Build/output.%s with the %s interpreter of your choice.\n" % (proj,settings["zsuf"],settings["format"])
            elif r == "G":
                bad = compile()
                if bad:
                    print "\n\n*** COMPILATION HAD ERRORS\n"
                else:
                    terpstr="TERP"
                    if settings['format'] == "glulx":
                        terpstr = "G"+terpstr
                    else:
                        terpstr = "Z"+terpstr
                    bgstr=terpstr+"BG"
                    terp=idesettings[terpstr]
                    terpbg=idesettings[bgstr]
                    terpbgstr=""
                    if terpbg:
                        terpbgstr=" &"
                    cmd = "\"%s\" \"%s/Build/output.%s\"%s" % (terp,proj,settings['zsuf'],terpbgstr)
                    if terpbg:
                        terpbgstr="  Exit interpreter to return to i7."
                    print "\n\nCompile succeeded.  Proceeding to interpreter.%s\n" % terpbgstr
                    os.system(cmd)
                    print "\n"
            elif r == "R":
                bad=compile("--release")
                if bad:
                    print "\n\n*** COMPILATION HAD ERRORS\n"
                else:
                    target=release()
                    if not target:
                        print "\n\n*** COULD NOT GENERATE BLORB ***\n"
                    else:
                        print "\n\nRelease succeeded.  Blorb file is in %s\n" % target
            elif r == "I" and idesettings['BROWSER']:
                browse()
            elif r == "S":
                setsettings()
            elif r == "Q":
                print "\n\nThanks for putting up with this so-called interface!"
                if CLEANUP:
                    os.remove(CLEANUP)
                os.chdir(oldpwd)
                sys.exit(0)
            else:
                print "\n\nI don't see any %s here!\n" % r
        elif NONINTERACTIVE == 1:
            rc=compile()
            sys.exit(rc)
        else:
            rc=compile()
            if rc:
                sys.exit(rc)
            rcstr=release()
            if not rcstr:
                sys.exit(4)
            sys.exit(0)
        
def compile(arg=""):
    ns = "--rules \"%s/share/inform7/Inform7/Extensions\"" % idesettings['PREFIX']
    cmd = "\"%s\" %s %s --extension=%s --package \"%s\"" % (NI,arg,ns,settings['zsuf'],proj)
    rc=os.system(cmd)
    if rc:
        return rc
    i6opts = "-kE2SDw"
    i6lib = "+\"%s/share/inform7/Library/Natural\"" % idesettings['PREFIX']
    if settings['zcode'] == 5:
        i6opts = i6opts+"v5"
    elif settings['zcode'] == 6:
        i6opts = i6opts+"v6"
    elif settings['zcode'] == 8:
        i6opts = i6opts+"v8"
    else:
        i6opts = i6opts + "G"
    i6opts = i6opts + "x"
    cmd = "\"%s\" %s %s \"%s/Build/auto.inf\" -o \"%s/Build/output.%s\"" % (I6,i6opts,i6lib,proj,proj,settings['zsuf'])
    print "cmd is "+cmd
    rc = os.system(cmd)
    return rc

def release():
    if not settings['blorb']:
        if not NONINTERACTIVE:
            print "Release-as-blorb is NO"
            print "Story can be found in %s/Build/output/%s\n" % (proj,settings['zsuf'])
        return "%s/Build/output.%s" % (proj,settings['zsuf'])
    cmd = "\"%s\" \"%s/Release.blurb\"" % (BLORB,proj)
    rc = os.system(cmd)
    if rc:
        return ""
    src = proj + "/story.zblorb"
    target = ""
    try:
        blurb=open(proj+"/Release.blurb","rU")
        matchstr=re.compile("\"(.*)\"")
        for line in blurb:
            if line.find("destination")==0:
                m=matchstr.search(line)
                if m:
                    target = m.group(1)
                    break
    finally:
        blurb.close()
    if target == "" and settings['zcode'] == 256:
        target = l + "/story.gblorb"
    if target:
        try:
            rc=os.rename(src,target)
        except:
            print "Rename of blorb file %s to %s failed" % (src,target)
            return ""
        return target
    return src

def browse():
    global CLEANUP
    idir = proj + "/Index"
    ifi = idir + "/_index.html";
    try:
        ifile=open(ifi,"w")
        print >> ifile, "<html>"
        print >> ifile, "<head>"
        print >> ifile, "<title>"
        print >> ifile, "Inform Index"
        print >> ifile, "</title>"
        print >> ifile, "</head>"
        print >> ifile, "<body>"
        print >> ifile, "<a href=\"./Actions.html\">Actions</a><p>"
        print >> ifile, "<a href=\"./Contents.html\">Contents</a><p>"
        print >> ifile, "<a href=\"./Kinds.html\">Kinds</a><p>"
        print >> ifile, "<a href=\"./Phrasebook.html\">Phrasebook</a><p>"
        print >> ifile, "<a href=\"./Scenes.html\">Scenes</a><p>"
        print >> ifile, "<a href=\"./World.html\">World</a><p>"
        print >> ifile, "<a href=\"../Build/Problems.html\">Errors</a></p>"
        print >> ifile, "<a href=\"%s/share/inform7/Documentation/index.html\">Documentation</a></p>" % idesettings['PREFIX']
        print >> ifile, "</body>"
        print >> ifile, "</html>"                               
    finally: ifile.close()
    if idesettings['BROWSER']:
        print "Using %s as your browser." % idesettings['BROWSER']
        if not idesettings['BROWSERBG']:
            print "Exit the browser to return to i7."
        print "\n"
        cmd=idesettings['BROWSER']
        if cmd.find("\%s") != -1:
            cmd.replace("\%s",ifi)
        else:
            cmd = cmd + " " + ifi
        if idesettings['BROWSERBG']:
            cmd = cmd + " &"
        os.system(cmd)
        print "\n"
        if idesettings['BROWSERBG']:
            CLEANUP = ifi
        else:
            os.remove(ifi)
    return 0

def setsettings():
    target = { 5:"Zcode version 5 (z5)",6:"Zcode version 6 (z6)",8:"Zcode version 8 (z8)",256:"Glulx (ulx)" }
    blorbtarget = { 1:"yes",0:"no" }
    while 1:
        print "\n\nSETTINGS\n\n"
        print "Target: (currently %s)\n" % target[settings['zcode']]
        print "Compile to Zcode version (5)"
        print "Compile to Zcode version (6)"
        print "Compile to Zcode version (8)"
        print "Compile to (G)lulx\n\n"
        print "Toggle (B)lorb release: (currently %s)\n" % blorbtarget[settings['blorb']]
        print "(I)DE Options\n"
        print "(R)eturn to main menu\n"
        r = printprompt()
        r = r.upper()
        r = r[0]
        if r == "R":
            writesettings(proj)
            break
        elif r == "B":
            settings['blorb'] = 1 - settings['blorb']
        elif r == "5":
            settings['format'] = "zcode"
            settings['zcode'] = 5
            settings['suffix'] = "zblorb"
            settings['zsuf'] = "z5"
        elif r == "6":
            settings['format'] = "zcode"
            settings['zcode'] = 6
            settings['suffix'] = "zblorb"
            settings['zsuf'] = "z6"
        elif r == "8":
            settings['format'] = "zcode"
            settings['zcode'] = 8
            settings['suffix'] = "zblorb"
            settings['zsuf'] = "z8"
        elif r == "G":
            settings['format'] = "glulx"
            settings['zcode'] = 256
            settings['suffix'] = "gblorb"
            settings['zsuf'] = "ulx"
        elif r == "I":
            setidesettings()
        else:
            print "\nI don't see any %s here!" % r
    return

def setidesettings():
    while 1:
        print "\n\nIDE SETTINGS\n\n"
        estr = ""
        if idesettings['EDITOR']:
            estr = " (currently %s)" % idesettings['EDITOR']
        print "Set (E)ditor%s" % estr
        estr=" (currently "
        if idesettings['EDITORBG']:
            estr += "ON)"
        else:
            estr += "OFF)"
        print "(&) Toggle running editor in background %s\n" % estr
        estr = ""
        if idesettings['BROWSER']:
            estr = " (currently %s)" % idesettings['BROWSER']
        print "Set (B)rowser%s" % estr
        estr=" (currently "
        if idesettings['BROWSERBG']:
            estr += "ON)"
        else:
            estr += "OFF)"
        print "Toggle running browser in bac(K)ground %s\n" % estr
        estr = ""
        if idesettings['ZTERP']:
            estr = " (currently %s)" % idesettings['ZTERP']
        print "Set (Z)-code interpreter%s" % estr
        estr=" (currently "
        if idesettings['ZTERPBG']:
            estr += "ON)"
        else:
            estr += "OFF)"
        print "Toggle running Z-code interpreter in ba(C)kground %s\n" % estr
        estr = ""
        if idesettings['GTERP']:
            estr = " (currently %s)" % idesettings['GTERP']
        print "Set (G)lulx interpreter%s" % estr
        estr=" (currently "
        if idesettings['GTERPBG']:
            estr += "ON)"
        else:
            estr += "OFF)"
        print "Toggle running Glulx interpreter in backgroun(D) %s\n" % estr
        print "(R)eturn to main menu\n"
        r=printprompt()
        r=r[0]
        r=r.upper()
        if r == "R":
            writeideprefs()
            break
        elif r == "E":
            idesettings['EDITOR'] = printprompt("Editor [%s]> "%idesettings['EDITOR'],idesettings['EDITOR'])
        elif r == "B":
            idesettings['BROWSER'] = printprompt("Browser [%s]> "%idesettings['BROWSER'],idesettings['BROWSER'])
        elif r == "Z":
            idesettings['ZTERP'] = printprompt("Z-code interpreter [%s]> "%idesettings['ZTERP'],idesettings['ZTERP'])
        elif r == "G":
            idesettings['GTERP'] = printprompt("Glulx interpreter [%s]> "%idesettings['GTERP'],idesettings['GTERP'])
        elif r == "&":
            idesettings['EDITORBG']=1-idesettings['EDITORBG']
        elif r == "K":
            idesettings['BROWSERBG']=1-idesettings['BROWSERBG']
        elif r == "C":
            idesettings['ZTERPBG']=1-idesettings['ZTERPBG']
        elif r == "D":
            idesettings['GTERPBG']=1-idesettings['GTERPBG']
        else:
            print "\nI don't see any %s here!" % r
    return
            

# Mainline code starts here

idesettings = {'PREFIX': "/usr/local", 'NAME': "" }
VERSION = "5U92"
NONINTERACTIVE = 0
HOME = os.environ['HOME']
OS = string.strip(commands.getoutput("uname"))
CLEANUP = ""
I6 = ""
NI = ""
BLORB = ""
proj = ""
opt_s = ""
print "XO I7 shell, cheesy Python edition, version " + VERSION
print "  Adam Thornton (<adam@io.com>), 2007-2008"
initialsettings()
getoptions()
initialidesettings()
checkinitialdirs()
if os.path.isfile(HOME+"/.i7rc"):
    readideprefs(HOME + "/.i7rc")
checkname()
if not NONINTERACTIVE:
    writeideprefs()
introloop()

readsettings(proj+"/Settings.plist")
# If you pass settings on the command line, they override the previous ones
if opt_s:
    for p in opt_s.split(","):
        for l in p.split("="):
            k=l[0]
            v=l[1]
            settings[k]=l
    writesettings(proj)
oldpwd = os.getcwd()
os.chdir(proj)
mainloop()
# And we never reach here
sys.exit(1)
