#!/usr/bin/env python
# $Id: pyformex 1044 2009-06-13 08:17:58Z bverheg $
##
##  This file is part of pyFormex 0.8 Release Sat Jun 13 10:22:42 2009
##  pyFormex is a tool for generating, manipulating and transforming 3D
##  geometrical models by sequences of mathematical operations.
##  Website: http://pyformex.berlios.de/
##  Copyright (C) Benedict Verhegghe (bverheg@users.berlios.de) 
##  Distributed under the GNU General Public License version 3 or later.
##
##
##  This program is free software: you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
"""pyFormex, a free program for creating and manipulating 3D geometry.

pyFormex is a powerful tool for generating, manipulating, transforming and
displaying large structural models of 3D geometry.
Based on a powerful scripting language, pyFormex is exceptionally suited for
generating parametric models and for the automization of tedious and recurring
tasks in the handling of geometrical models.
Built around a fully open architecture pyFormex allows the user to combine the
program with nearly any other software and to extend the program to suit his
own needs.

pyFormex is being developed at the IBiTech, Ghent University, and can be
distributed under the GNU General Public License, version 3 or later.
(C) 2004-2009 Benedict Verhegghe (benedict.verhegghe@ugent.be)) 
"""

import warnings
warnings.filterwarnings('ignore','.*return_index.*',UserWarning,'numpy')


# Get the pyformex dir and put it on the head of sys.path
import sys,os
scriptdir = sys.path[0]

# In case we execute the pyformex script from inside the
# pyformex package dir: add the parent to the front of sys.path
# to pick up this package by preference

svnversion = False
if scriptdir.endswith('pyformex'):
    parent = os.path.dirname(scriptdir)
    sys.path[:0] = [ os.path.dirname(scriptdir) ]
    if os.path.exists(os.path.join(parent,'.svn')):
        svnversion = True

try:
    import pyformex
    # we could remove the sys.path[0] again?
except:
    print "Could not import pyformex."
    print "This probably means that pyFormex was not properly installed."

pyformexdir = pyformex.__path__[0]
sys.path[:0] = [ pyformexdir ]

GD = pyformex
import utils
from config import Config

###########################  main  ################################


def refLookup(key):
    """Lookup a key in the reference configuration."""
    return GD.refcfg[key]


def printcfg(key):
    try:
        print "!! refcfg[%s] = %s" % (key,GD.refcfg[key])
    except KeyError:
        pass
    print "!! cfg[%s] = %s" % (key,GD.cfg[key])


def setRevision():
    sta,out = utils.runCommand('cd %s && svnversion' % pyformex.cfg['pyformexdir'],quiet=True)
    if sta == 0 and not out.startswith('exported'):
        pyformex.__revision__ = "$Rev: %s $" % out.strip()



def remove_pyFormex(pyformexdir,scriptdir):
    """Remove the pyFormex installation."""
    print """
BEWARE!
This procedure will remove the complete pyFormex installation!
If you continue, pyFormex will exit and you will not be able to run it again.
The pyFormex installation is in: %s
The pyFormex executable script is in: %s
You will need proper permissions to actually delete the files.
""" % (pyformexdir,scriptdir)
    s = raw_input("Are you sure you want to remove pyFormex? yes/NO: ")
    if s == 'yes':
        print "Removing %s" % pyformexdir
        utils.removeTree(pyformexdir)
        script = os.path.join(scriptdir,'pyformex')
        egginfo = "%s-%s.egg-info" % (pyformexdir,GD.__version__.replace('-','_'))
        for f in [ script,egginfo ]:
            if os.path.exists(f):
                print "Removing %s" % f
                os.remove(f)
        print "\nBye, bye! I won't be back until you reinstall me!"
    elif s.startswith('y') or s.startswith('Y'):
        print "You need to type exactly 'yes' to remove me."
    else:
        print "Thanks for letting me stay this time."
    sys.exit()

###########################  app  ################################

    
def main(argv=None):
    """This is a fairly generic main() function.

    It is responsible for reading the configuration file(s),
    processing the command line options and starting the application.
    The basic configuration file is 'pyformexrc' located in the pyformex
    directory. It should always be present and be left unchanged.
    You can copy this file to another location if you want to make changes.
    By default, pyformex will try to read the following extra configuration
    files (in this order:
        default settings:     <pyformexdir>/pyformexrc
        system-wide settings: /etc/pyformexrc
        user settings:        $HOME/.pyformex/pyformexrc
        local settings        $PWD/.pyformexrc
    Also, an extra config file can be specified in the command line.
    Config file settings always override previous ones.
    On exit, the preferences that were changed are written to the last
    read config file. Changed settings are those that differ from the settings
    in all but the last one.
    """
    # this allows us to call main from the interpreter
    if argv is None:
        argv = sys.argv[1:]

    # Create a config instance
    GD.cfg = Config()
    # Fill in the pyformexdir and homedir variables
    # (use a read, not an update)
    if os.name == 'posix':
        homedir = os.environ['HOME']
    elif os.name == 'nt':
        homedir = os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
    GD.cfg.read("pyformexdir = '%s'\n" % pyformexdir)
    GD.cfg.read("homedir = '%s'\n" % homedir)

    # Read the defaults (before the options)
    defaults = os.path.join(pyformexdir,"pyformexrc")
    GD.cfg.read(defaults)
    
    # Process options
    from optparse import OptionParser,make_option
    parser = OptionParser(
        usage = "usage: %prog [<options>] [ --  <Qapp-options> ] [[ scriptname [scriptargs]] ...]",
        version = pyformex.Version,
        option_list=[
        make_option("--gui", help="start the GUI (default if no scriptfile argument is given)",
                    action="store_true", dest="gui", default=None),
        make_option("--nogui", help="do not load the GUI (default if a scriptfile argument is given)",
                    action="store_false", dest="gui", default=None),
        make_option("--interactive",'-i', help="go into interactive mode after processing the command line parameters. This is implied by the --gui option.",
                    action="store_true", dest="interactive", default=False),
        make_option("--force-dri", help="Force use of Direct Rendering",
                    action="store_true", dest="dri", default=None),
        make_option("--force-nodri", help="Disables the Direct Rendering",
                    action="store_false", dest="dri", default=None),
        make_option("--uselib", help="Use the pyFormex C lib if available. This is the default.",
                    action="store_true", dest="uselib", default=None),
        make_option("--nouselib", help="Do not use the pyFormex C-lib.",
                    action="store_false", dest="uselib", default=None),
        make_option("--safelib", help="Convert data types to match C-lib. This is the default.",
                    action="store_true", dest="safelib", default=True),
        make_option("--unsafelib", help="Do not convert data types to match C-lib. BEWARE: this may make the C-lib calls impossible. Use only for debugging purposes.",
                    action="store_false", dest="safelib", default=True),
        make_option("--fastencode", help="Use a fast algorithm to encode edges.",
                    action="store_true", dest="fastencode", default=False),
        make_option("--config", help="Use file CONFIG for settings",
                    action="store", dest="config", default=None),
        make_option("--nodefaultconfig", help="Skip the default site and user config files. This option can only be used in conjunction with the --config option.",
                    action="store_true", dest="nodefaultconfig", default=False),
        make_option("--redirect", help="Redirect standard output to the message board (ignored with --nogui)",
                    action="store_true", dest="redirect", default=False),
        make_option("--detect", help="Detect helper software and print report.",
                    action="store_true", dest="detect", default=False),
        make_option("--debug", help="display debugging info to sys.stdout",
                    action="store_true", dest="debug", default=False),
        make_option("--classify", help="classify the examples in categories",
                    action="store_true", dest="classify", default=False),
        make_option("--whereami", help="show where the pyformex package is located",
                    action="store_true", dest="whereami", default=False),
        make_option("--remove", help="remove the pyformex installation",
                    action="store_true", dest="remove", default=False),
        make_option("--test", help="testing mode: only for developers!",
                    action="store_true", dest="test", default=False),
        make_option("--testdraw", help="draw testing mode: only for developers!",
                    action="store_true", dest="testdraw", default=False),
        make_option("--testhighlight", help="highlight testing mode: only for developers!",
                    action="store_true", dest="testhighlight", default=False),
        make_option("--executor", help="test alternate executor: only for developers!",
                    action="store_true", dest="executor", default=False),
        ])
    GD.options, args = parser.parse_args(argv)
    GD.print_help = parser.print_help


    # process options
    if GD.options.nodefaultconfig and not GD.options.config:
        print "\nInvalid options: --nodefaultconfig but no --config option\nDo pyformex --help for help on options.\n"
        sys.exit()

    if GD.options.debug:
        GD.debug = GD.debug_true
    else:
        GD.debug = GD.debug_false

    if GD.options.whereami:
        print "Script started from %s" % scriptdir
        print "I found pyFormex in %s " %  pyformexdir
        sys.exit()
        
    if GD.options.remove:
        remove_pyFormex(pyformexdir,scriptdir)
        
    if GD.options.detect:
        print "Detecting all installed helper software"
        utils.checkExternal()
        print utils.reportDetected()
        sys.exit()
        
    GD.debug("Options: %s" % GD.options)

    ########### Read the config files  ####################

    # Create the user conf dir
    if not os.path.exists(GD.cfg.userconfdir):
        os.mkdir(GD.cfg.userconfdir)

    # These values  should not be changed
    GD.cfg.userprefs = os.path.join(GD.cfg.userconfdir,'pyformexrc')
    GD.cfg.autorun = os.path.join(GD.cfg.userconfdir,'startup.py')

    # Migrate old user prefs
    olduserprefs = os.path.join(GD.cfg.homedir,'.pyformexrc')
    if not os.path.exists(GD.cfg.userprefs) and os.path.exists(olduserprefs):
        import shutil
        print "Moving user preferences to new location"
        print "%s --> %s" % (olduserprefs,GD.cfg.userprefs)
        shutil.move(olduserprefs,GD.cfg.userprefs)
    
    # Set the config files
    if GD.options.nodefaultconfig:
        sysprefs = []
        userprefs = []
    else:
        sysprefs = [ GD.cfg.siteprefs ]
        userprefs = [ GD.cfg.userprefs ]
        if os.path.exists(GD.cfg.localprefs):
            userprefs.append(GD.cfg.localprefs)


    if GD.options.config:
        userprefs.append(GD.options.config)

    if len(userprefs) == 0:
        # We should always have a place to store the user preferences
        userprefs = [ GD.cfg.userprefs ]

    GD.preffile = os.path.abspath(userprefs[-1]) # Settings will be saved here
   
    # Read all but the last as reference
    for f in filter(os.path.exists,sysprefs + userprefs[:-1]):
        GD.debug("Reading config file %s" % f)
        GD.cfg.read(f)
    GD.refcfg = GD.cfg
    GD.debug("RefConfig: %s" % GD.refcfg)

    # Use the last as place to save preferences
    GD.cfg = Config(default=refLookup)
    if os.path.exists(GD.preffile):
        GD.debug("Reading config file %s" % GD.preffile)
        GD.cfg.read(GD.preffile)
    GD.debug("Config: %s" % GD.cfg)

    # Set option from config if it was not explicitely given
    if GD.options.uselib is None:
        GD.options.uselib = GD.cfg['uselib'] 

    # Set default --nogui if first remaining argument is a pyformex script.
    if GD.options.gui is None:
        GD.options.gui = not (len(args) > 0 and utils.isPyFormex(args[0]))

    if GD.options.gui:
        GD.options.interactive = True

    # Set Revision if we run from an SVN version
    if svnversion:
        setRevision()

    GD.debug(utils.reportDetected())
    
    # Start the GUI if needed
    # Importing the gui should be done after the config is set !!
    if GD.options.gui:
        GD.debug("GUI version")
        from gui import gui
        gui.startGUI(args)
    #
    # Qt4 may have changed the locale.
    # Since a LC_NUMERIC setting other than C may cause lots of troubles
    # with reading and writing files (formats become incompatible!)
    # we put it back to a sane setting
    #
    utils.setSaneLocale()

    # Initialize the libraries
    #print "NOW LOAIDNG LIBS"
    #import lib
    #lib.init_libs(GD.options.uselib,GD.options.gui)


    # Prepend the autorun scripts
    ar = GD.cfg.get('autorun','')
    if ar :
        if type(ar) is str:
            ar = [ ar ]
        # expand tilde, as would bash
        ar = map(utils.tildeExpand,ar)
        args[0:0] = [ fn for fn in ar if os.path.exists(fn) ]

    # remaining args are interpreted as scripts and their parameters
    res = 0
    if args:
        try:
            GD.debug("Remaining args: %s" % args)
            from script import processArgs
            res = processArgs(args)
        except:
            GD.message("There was an error while executing one of the scripts")
            res = 1

    # after processing all args, go into interactive mode
    if GD.options.gui:
        res = gui.runGUI()

    elif GD.options.interactive:
        print "Enter your script and end with CTRL-D"
        from script import playScript
        playScript(sys.stdin)
        
    #Save the preferences that have changed
    GD.savePreferences()

    # Exit
    return res


# Go

if __name__ == "__main__":
    sys.exit(main())

# End
