#!/usr/bin/env /usr/bin/ecell3-python


"""
A program for converting EML to EM.
This program is part of E-Cell Simulation Environment Version 3.
"""

__program__ = 'ecell3-eml2em'
__version__ = '0.1'
__author__ = 'Kentarou Takahashi and Koichi Takahashi <shafi@e-cell.org>'
__copyright__ = 'Copyright (C) 2002-2009 Keio University'
__license__ = 'GPL'



import sys
import os
import time
import getopt
import types
import re

import ecell.config
from ecell.ecssupport import *
from ecell.eml import *

# taken from emllib.
NumberPattern = r'^[+-]?(\d+(\.\d*)?|\d*\.\d+)([eE][+-]?\d+)?$'
UnquoteStringPattern = r'^[a-zA-Z_/\:][\w\:/\.]*$'
QuoteRe = re.compile( NumberPattern + '|' + UnquoteStringPattern )

def expandValueList( aValue, aLevel=0 ):
    aType = type( aValue )

    # Three cases: (1) string, (2) other non-list types, and
    #              (3) list (or tuple).

    # (1) string.  Quote it if necessary.
    if aType == types.StringType:
        if QuoteRe.match( aValue ) is None:
            return '"' + aValue + '"'
        else:
            return aValue
        
    # (2) other non-list types (such as numbers).  Simply stringify.
    if aType != types.TupleType and aType != types.ListType:
        return str( aValue )

    # (3) list or tuple.
    #     Recursively apply this method for nested lists.
    
    aValue = map( expandValueList, aValue, (aLevel+1,) * len( aValue ) )

    aValueString = ''

    # don't print a space before the first item
    if len( aValue ) > 0:
        aValueString += str( aValue[0] )
        
    for anItem in aValue[1:]:
        aValueString += ' '
        aValueString += str( anItem )

    # don't use [] in uppermost level
    if aLevel != 0:
        aValueString = '[ ' + aValueString + ' ]'

    return aValueString
        


def createObjectDef( aType, aClass, anArgList, aPropertyList, anOptional='' ):

    # declaration line
    anArgListString = ','.join( anArgList ) 
    aBuffer = '%s %s( %s )\n{\n' % ( aType, aClass, anArgListString )

    # properties
    if len( aPropertyList ) != 0:
        for aProperty in aPropertyList:
            aPropertyName = aProperty[0]
            aPropertyValueListString = expandValueList( aProperty[1] )
            aBuffer += '\t%s\t%s;\n' % ( aPropertyName,
                                         aPropertyValueListString )
#            print aPropertyName
    else:
        aBuffer += '\t# no property\n'
    
    # optional field
    if anOptional != '':
        aBuffer += '\n\t'
        aBuffer += anOptional.replace( '\n', '\n\t' )
        aBuffer += '\n'

    aBuffer += '}\n'
    
    return aBuffer


def createStepperList( anEml ):
    aBuffer = ''

    for aStepperID in anEml.getStepperList():
        aType = 'Stepper'
        aClass = anEml.getStepperClass( aStepperID )
        anArgList = ( aStepperID, )
        aPropertyNameList = anEml.getStepperPropertyList( aStepperID )
        aPropertyList = []
        for aPropertyName in aPropertyNameList:
            aPropertyValue = anEml.getStepperProperty( aStepperID,\
                                                       aPropertyName )
            aPropertyList.append( ( aPropertyName, aPropertyValue ) )

        aBuffer += createObjectDef( 'Stepper', aClass, anArgList,
                                    aPropertyList )
        aBuffer += '\n'

    return aBuffer

def createEntity( anEml, aFullID, anOptional='' ):

    aFullIDString = createFullIDString( aFullID )
    aType = ENTITYTYPE_STRING_LIST[ aFullID[ TYPE ] ]
    aClass = anEml.getEntityClass( aFullIDString )

    if aFullID[TYPE] != SYSTEM:
        anArgList = ( aFullID[ ID ], )
    else:
        if len( aFullID[SYSTEMPATH] ) == 0 or aFullID[SYSTEMPATH][-1] == '/':
            aSystemPath = aFullID[SYSTEMPATH] + aFullID[ID]
        else:
            aSystemPath = aFullID[SYSTEMPATH] + '/' + aFullID[ID]
        anArgList = ( aSystemPath, )

    aPropertyNameList = anEml.getEntityPropertyList( aFullIDString )
    aPropertyList = []
    for aPropertyName in aPropertyNameList:
        aFullPN = aFullIDString + ':' + aPropertyName
        aPropertyValue = anEml.getEntityProperty( aFullPN )
        aPropertyList.append( ( aPropertyName, aPropertyValue ) )
        
    return createObjectDef( aType, aClass, anArgList, aPropertyList,
                            anOptional )
    

def createSystemList( anEml, aSystemPath='/' ):
    aBuffer = ''

    anOptional = ''

    for anID in anEml.getEntityList( 'Variable', aSystemPath ):
        aFullID = ( VARIABLE, aSystemPath, anID )
        anOptional += createEntity( anEml, aFullID )
        anOptional += '\n'

    for anID in anEml.getEntityList( 'Process', aSystemPath ):
        aFullID = ( PROCESS, aSystemPath, anID )
        anOptional += createEntity( anEml, aFullID )
        anOptional += '\n'

    if aSystemPath == '':
        aFullID = ( SYSTEM, '', '/' )
    else:
        aLastSlash = aSystemPath.rindex( '/' )
        aPath = aSystemPath[:aLastSlash+1]
        anID = aSystemPath[aLastSlash+1:]
        aFullID = ( SYSTEM, aPath, anID )

    aBuffer += createEntity( anEml, aFullID, anOptional )
    aBuffer += '\n'

    for aSystem in anEml.getEntityList( 'System', aSystemPath ):
        aSubSystemPath = joinSystemPath( aSystemPath, aSystem )
        aBuffer += createSystemList( anEml, aSubSystemPath )

    return aBuffer

if __name__ == '__main__':
    def usage():
        aProgramName = os.path.basename( sys.argv[0] )

        print '''
%(appname)s -- convert a EML file to a EM file
        
Usage:
    %(appname)s [-h] [-f] [-o EMFILE] infile.eml

Options:
    -h or --help           : Print this message.
    -f or --force          : Forcefully overwrite EMLFILE
                             even if it already exists.
    -o or --outfile=EMFILE : Specify output file name. '-' means stdout.

''' % { 'appname': aProgramName }

    # commandline processing
    try:
        opts, args = getopt.getopt( sys.argv[1:], "hfo:",
                                    ["help","force", "outfile="] )
    except getopt.GetoptError:
        usage()
        sys.exit( 1 )

    anEmFileName = None
    aForceFlag = 0

    for anOption, anArg in opts:
        if anOption in ( "-h", '--help' ):
            usage()
            sys.exit( 0 )

        if anOption in ( "-f", '--force' ):
            aForceFlag = 1            

        if anOption in ( "-o", "--outfile" ):
            anEmFileName = anArg
            
    if len( args ) == 0:
        sys.stderr.write( "No input file.\n" )
        sys.exit( 1 )

    anEmlFileName = args[0]

    anEmlFile = open( anEmlFileName )
    anEml = Eml( anEmlFile )
    anEmlFile.close()

    aBaseName = os.path.basename( anEmlFileName )
    aBaseName, anExt = os.path.splitext( aBaseName )

    if anEmFileName == None:
        if anExt == '.eml' or anExt == '.xml':
            anExt = '.em'
        else:
            anExt += '.em'

        anEmFileName = aBaseName + anExt

    if anEmFileName == '-':
        anEmFile = sys.stdout
    else:
        if os.path.isfile( anEmFileName ) and aForceFlag == 0:
            sys.stderr.write( "Output file %s exists. Use -f to overwrite.\n"
                              % anEmFileName )
            sys.exit( 1 )

        anEmFile = open( anEmFileName, 'w' )
            

    aBuffer = '''
# created by eml2em program
# from file: %s, date: %s
#

''' % ( anEmlFileName, time.asctime( time.localtime() ) )

    aBuffer += createStepperList( anEml )
    aBuffer += createSystemList( anEml )

    anEmFile.write( aBuffer )

