#!/usr/bin/python2

# the main GUI program. Relies on fract4d libs to do the real work
version = '3.0'

# python stdlib
import sys
import os
import getopt

# gettext
import gettext
os.environ.setdefault('LANG', 'en')
if os.path.isdir('po'):
    gettext.install('gnofract4d','po')
else:
    gettext.install('gnofract4d')

# gtk
try:
    import gtk
except ImportError, err:
    print _("Can't find PyGTK. You need to install it before you can run Gnofract 4D.")
    sys.exit(1)

# check for pygtk >=1.99
pygtk_ok = True
try:
    (major,minor,patch) = gtk.pygtk_version
    if major < 2:
        if minor < 99:
            pygtk_ok = False
    import gobject
    
except Exception:
    pygtk_ok = False

if not pygtk_ok:
    print _("Sorry, your PyGTK version (%d.%d.%d) is too old. You need at least 1.99" % \
            gtk.pygtk_version)
    sys.exit(1)

try:
    # newer pygtk's are incompatible with older ones. In most cases I 
    # try the new version and fall back to the older if it's missing. See utils.py.
    # In these cases I can't, so hiding the DeprecationWarnings so users
    # don't have to suffer
    import warnings

    # we use ItemFactory because I want this to carry on working with older PyGTK's,
    # so UIManager is out, and the differences between the 2 are too large to hide

    warnings.filterwarnings(
        "ignore",
        ".*UIManager.*",
        DeprecationWarning,
        ".*",
        0)

    # newer pygtk's don't need us to call gobject.type_register, but older ones
    # most certainly do.
    warnings.filterwarnings(
        "ignore",
        ".*GObject-registered.*",
        DeprecationWarning,
        ".*",
        0)

except Exception, exn :
    print exn
    pass

try:
    libdir = '/usr/lib'
    # we install our libs privately instead of to site-packages
    sys.path.append(os.path.join(libdir, 'gnofract4d-%s' % version))
    # gui modules
    from fract4dgui import main_window, preferences, utils
    from fract4d import fractal
    
except ImportError, err:
    print _('''
Can't import a required module.
If you haven't set up Gnofract 4D yet, run './setup.py build'
Error was: '%s' ''') % err
    sys.exit(1)

# Threads are optional because RedHat seem to compile pygtk
# without thread support. Grrr.
try:
    #gtk.gdk.threads_init()
    #utils.threads_enabled = True
    pass
except:
    pass

class Options:
    "Gathers command-line args, wraps crappy getOpt interface"
    def __init__(self,args):
        (self.basename,self.func) = (None,None)
        (self.innername,self.innerfunc) = (None,None)
        (self.outername,self.outerfunc) = (None,None)
        self.maxiter = -1
        self.trace = False
        self.paramchanges = {}
        self.quit_now = False
        self.quit_when_done = False
        self.output = ""
        self.explore = False
        self.save_filename = None
        self.extra_paths = []
        self.map = None
        (self.width, self.height) = (0,0)

        longparams = [
            "params=",
            "maxiter=",
            "width=",
            "height=",
            "save=",
            "help",
            "path=",
            "formula=",
            "inner=",
            "outer=",
            "map=",
            "xcenter=","ycenter=","zcenter=","wcenter=",
            "xyangle=","xzangle=","xwangle=","yzangle=","ywangle=","zwangle=",
            "magnitude=",
            "quit",
            "explorer",
            "trace",
            "version"]

        (opts, self.args) = getopt.getopt(
            args,
            "p:m:i:j:s:f:qhP:Xv", longparams)

        for (name, val) in opts:
            if name=="-p" or name=="--params":
                args.insert(0,val)
            if name=="-m" or name=="--maxiter":
                self.maxiter=int(val)
            elif name=="-q" or name=="--quit":
                self.quit_when_done = True
            elif name=="-s" or name=="--save":
                self.save_filename = val
            elif name=="-i" or name=="--width":
                self.width = int(val)
            elif name=="-j" or name=="--height":
                self.height = int(val)
            elif name=="-h" or name=="--help":
                self.output += help()
                self.quit_now = True
            elif name=="-P" or name=="--path":
                self.extra_paths.append(val)
            elif name=="-X" or name=="--explorer":
                self.explore = True
            elif name=="-f" or name=="--formula":
                (self.basename,self.func) = self.splitarg(val,name)
            elif name=="--inner":
                (self.innername,self.innerfunc) = self.splitarg(val,name)
            elif name=="--outer":
                (self.outername,self.outerfunc) = self.splitarg(val,name)
            elif (name=="--map"):
                self.map = val
            elif name=="--version" or name=="-v":
                self.print_version()
                self.quit_now = True
            elif name=="--trace":
                self.trace = True
            else:
                # see if it's a positional param
                pname = name[2:].upper()
                if hasattr(fractal.T,pname):
                    pnum = getattr(fractal.T,pname)
                    self.paramchanges[pnum]= val
                else:
                    print "Unknown argument", name, val

    def splitarg(self,val, name):
        n = val.rfind('#')
        if n==-1:
            help()
            print "ERROR: %s should be file#func" % name
            sys.exit(1)
        (file, func) = (val[:n], val[n+1:])
        path = os.path.dirname(file)
        if path:
            self.extra_paths.append(path)

        basename = os.path.basename(file)
        return (basename,func)

    def print_version(self):
        try:
            gtk_version = "%d.%d.%d" % gtk.gtk_version
        except:
            gtk_version = "unknown"

        try:
            pygtk_version = "%d.%d.%d" % gtk.pygtk_version
        except:
            pygtk_version = "unknown"

        self.output += """Gnofract 4D %s
GTK %s
PyGTK %s""" % (version, gtk_version, pygtk_version)
               
    
def help():
    return """Gnofract 4D %s
Usage: gnofract4d [flags] [paramfile]

To generate an image non-interactively, use:
gnofract4d -s myimage.png -q myfractal.fct 

General Flags:
-h --help\t\tShow this message
-v --version\t\tShow version info
-q --quit\t\tExit as soon as the image is finished
-X --explorer\t\tStart in explorer mode

Fractal Settings:
-p --params FILE\tUse FILE as a parameter file
-s --save IMAGEFILE\tSave image to IMAGEFILE after calculation
-i --width N\t\tMake image N pixels wide
-j --height N\t\tMake image N pixels tall
-P --path P\t\tAdd P to the formula search path
-f --formula F#func\tUse formula 'func' from file F
   --inner F#func\tUse coloring algorithm 'func' from file F
   --outer F#func\tUse coloring algorithm 'func' from file F
-m --maxiter N\t\tUse N as maximum number of iterations
   --map FILE\t\tLoad map file FILE
   
Positional Parameters:
   --xcenter N
   --ycenter N
   --zcenter N
   --wcenter N
   --xyangle N
   --xzangle N
   --xwangle N
   --yzangle N
   --ywangle N
   --zwangle N
   --magnitude N

Obscure settings:
   --trace\t\tProduce voluminous tracing output
""" % version

def main():    
    # parse the options    
    try:
        options = Options(sys.argv[1:])
    except getopt.GetoptError, err:
        print help()

        print "Error parsing arguments: %s" % err
        return 1

    # having parsed them, apply them. The reason for this 2-pass
    # approach is that it matters what order these operations are
    # done in, but it shouldn't matter what order params are
    # presented on the command-line
    if len(options.output) > 0:
        print options.output
        
    if options.quit_now:
        sys.exit(0)

    mainWindow = main_window.MainWindow()

    mainWindow.apply_options(options)
    
    if mainWindow.f.thaw():
        mainWindow.on_fractal_change()

    gtk.main()

def main_n(n):
    for i in xrange(n):
        main()

if __name__ == '__main__':
    if os.environ.get("DO_GF4D_PROFILE"):
        import hotshot
        prof = hotshot.Profile("gf4d.prof")
        prof.runcall(main_n, 5)
        prof.close()
    else:
        main()
