######################################################################
# setup script for the Python wrapper of ODE
######################################################################

# Note: ODE itself must already be compiled

# Set to the base of your ODE installation.
#ODE_BASE = '../ode'

# Set to True or False to force trimesh support to be enabled or disabled.
#TRIMESH_SUPPORT_OVERRIDE = True

######################################################################

from distutils.core import setup, Extension
import distutils.sysconfig
import shutil, os, os.path, sys, glob
from stat import *

# Windows?
if sys.platform=="win32":

    try:
        base = ODE_BASE
    except NameError:
        ODE_BASE = "../ode_single_trimesh"
        #ODE_BASE = "../ode_double_notrimesh"
    
    INC_DIRS = [os.path.join(ODE_BASE, "include")]
    LIB_DIRS = [os.path.join(ODE_BASE, "lib")]
    LIBS     = ["ode", "user32"]  # user32 because of the MessageBox() call
    CC_ARGS  = ["/ML"]

# Linux (and other)
else:

    try:
        base = ODE_BASE
    except NameError:
        ODE_BASE = "../ode"

    INC_DIRS = [os.path.join(ODE_BASE, "include")]
    LIB_DIRS = [os.path.join(ODE_BASE, "lib")]
    LIBS     = ["ode", "stdc++"]
    CC_ARGS  = []

######################################################################

def readODEConfig():
    config = {}
    
    filename = os.path.normpath(os.path.join(ODE_BASE, "config", "user-settings"))
    print 'Reading ODE configuration "%s"...' % filename

    try:
        f = file(filename)
    except IOError, e:
        print "ERROR:", e
        raise RuntimeError
        
    for line in f.readlines():
        s = line.strip()

        # remove comments
        i = s.find('#')
        if (i != -1):
            s = s[:i]

        if (s == ''):
            continue

        s = s.upper()

        a = s.split('=')
        if (len(a) == 2):
            k, v = a
            config[k] = v

    return config

######################################################################

# Determine the precision setting (SINGLE or DOUBLE?)
#try:
#    precisionfile = "_precision.pyx"
#    precision = determinePrecision()
#    print "Precision:",precision
#    print 'Creating file "%s"...'%precisionfile
#    f = file(precisionfile, "wt")
#    f.write("# This file was automatically generated by the setup script\n\n")
#    f.write('cdef extern from "ode/ode.h":\n')
#    f.write('    # Define the basic floating point type used in ODE\n')
#    f.write('    ctypedef %s dReal\n'%{"SINGLE":"float", "DOUBLE":"double"}[precision])
#    f.close()
#except RuntimeError:
#    print "Aborting!"
#    sys.exit()




# Generate the C source file (if necessary)
def generate(name, trimesh_support):
    # Generate the trimesh_switch file
    
    f = file("_trimesh_switch.pyx", "wt")
    print >>f, '# This file was generated by the setup script and is included in ode.pyx.\n'
    if (trimesh_support):
        print >>f, 'include "trimeshdata.pyx"'
        print >>f, 'include "trimesh.pyx"'
    else:
        print >>f, 'include "trimesh_dummy.pyx"'
    f.close()
    
    cmd = "pyrexc -o %s -I. -Isrc src/ode.pyx" % name
    pyrex_out = name

    # Check if the pyrex output is still up to date or if it has to be generated
    # (ode.c will be updated if any of the *.pyx files in the directory "src"
    # is newer than ode.c)
    if os.access(pyrex_out, os.F_OK):
        ctime = os.stat(pyrex_out)[ST_MTIME]
        for pyx in glob.glob("src/*.pyx"):
            pytime = os.stat(pyx)[ST_MTIME]
            if pytime>ctime:
                print "Updating",pyrex_out
                print cmd
                err = os.system(cmd)
                break
        else:
            print pyrex_out,"is up to date"
            err = 0
    else:
        print "Creating",pyrex_out
        print cmd
        err = os.system(cmd)

    # Check if calling pyrex produced an error
    if err!=0:
        print "An error occured while generating the C source file."
        sys.exit(err)

# Check if the ODE_BASE path does exist
if not os.path.exists(ODE_BASE):
    print """This Python ODE wrapper assumes that you have a compiled version of
the ODE library already somewhere on your system. The path to the ODE
distribution has to be set in the setup script via the variable
ODE_BASE. Currently it points to "%s".
However, that path does not exist. So please change the variable inside the
script so that it points to the actual location of the ODE directory."""%ODE_BASE
    sys.exit()

config = readODEConfig()

generate('ode_trimesh.c', True)
generate('ode_notrimesh.c', False)

try:
    wrap_trimesh = TRIMESH_SUPPORT_OVERRIDE
except NameError, e:
    wrap_trimesh = config.get('OPCODE_DIRECTORY', '')

if (wrap_trimesh):
    print "Installing with trimesh support."
    install = 'ode_trimesh.c'
else:
    print "Installing without trimesh support."
    install = 'ode_notrimesh.c'

# Compile the module
setup(name = "PyODE",
      version = "1.1.0",
      description = "Python wrapper for the Open Dynamics Engine",
      author = "see file AUTHORS",
      author_email = "timothy@stranex.com",
      license = "BSD or LGPL",
      url = "http://pyode.sourceforge.net/",
      packages = ["xode"],
      ext_modules = [Extension("ode", [install]
                     ,libraries=LIBS
                     ,include_dirs=INC_DIRS
                     ,library_dirs=LIB_DIRS
                     ,extra_compile_args=CC_ARGS)                   
                    ])
