# ===================================================================================
#                            formatmodeldbfile.py                                   |
# ===================================================================================
#                                                                                   |
# Programmer:     Sandy Wilson (KnightErrant)                                       |
#                                                                                   |
# Creation Date:  11 February 2007                                                  |
# Revision Dates: 13 February 2007 - Updated comments to actually correspond to the |
#                                       code.                                       |
#                                                                                   |
# ----------------------------------------------------------------------------------|
#                                                                                   |
#    This script reads the battle_models.modeldb text file and parses it out        |
# according to the recommendations of Kleemann, that is, one entry per line with    |
# the character count preceding the following file path string.  It also enforces   |
# the required "two spaces after a zero except for the last line" rule as stated    |
# by Kleemann.   This is a new version from the previous attempt which still left   |
# bad breaks for some units, didn't work on units with apostrophes in their names,  |
# and other nonuniform problems.                                                    |
#                                                                                   |
# ===================================================================================
import re
import array

# Read the whole thing into one string.
fidin                  = open( 'battle_models.modeldb', 'r' )
thewholething          = fidin.readline()
fidin.close()
numchars               = len( thewholething )

# Begin finding break points.

# First and main pattern is any sized integer number, then a space, followed by 
# a general string with underscores, apostrophes, forward slashes and
# periods (for file names), or numbers, finally followed by a space. 
re1                    = re.compile( "[0-9]+\s[a-zA-Z][a-zA-Z_'/.0-9]*\s" )
iter1                  = re1.finditer( thewholething )
indices1               = []
for match in iter1 :
    indices1.append( match.start() )

print 'Number of type 1 matches: ' + str( len( indices1 ) )

# Second pattern is to find all 0's followed by two spaces (the deadly two spaces),
# followed by a general integer number, followed by a space..  We want to 
# break AFTER the two spaces  so we will add 3 to the indices that we generate.
re2                    = re.compile( "0\s\s[0-9]*\s" )
iter2                  = re2.finditer( thewholething )
indices2               = []
for match in iter2 :
    indices2.append( match.start()+3 )

print 'Number of type 2 matches: ' + str( len( indices2 ) )

# Third pattern is to find all the weird entry termination strings
# of the form: 16 -0.090000004 0 0 -0.34999999 0.80000001 0.60000002 
# (We only search for \s # \s -0.090000004 because that matches them all.)
# Note that we add 1 to the indices to accout for the leading space.
re3                    = re.compile( "\s[0-9]+\s-0.090000004\s" )
iter3                  = re3.finditer( thewholething )
indices3               = []
for match in iter3 :
    indices3.append( match.start()+1 )

print 'Number of type 3 matches: ' + str( len( indices3 ) )

# Fourth pattern is to find \s # \s # \s lower case string
# Note that we add 1 to the indices to accout for the leading space.
re4                    = re.compile( "\s[0-9]+\s[0-9]+\s[a-z']*\s" )
iter4                  = re4.finditer( thewholething )
indices4               = []
for match in iter4 :
    indices4.append( match.start()+1 )

print 'Number of type 4 matches: ' + str( len( indices4 ) )

# Fifth pattern is to find \s single digit \s single digit \s general number \s general string
re5                    = re.compile( "\s[1-9]\s[1-9]\s[0-9]+\s[a-zA-Z][a-zA-Z_'/.0-9]*\s" )
iter5                  = re5.finditer( thewholething )
indices5               = []
for match in iter5 :
    indices5.append( match.start()+1 )

print 'Number of type 5 matches: ' + str( len( indices5 ) )

# Sixth pattern is to find all the horse type mount entries 
# of the form: 1.12 mesh_number
# that precede the mesh files entries for horse mounts.             
re6                    = re.compile( "\s1.12\s" )
iter6                  = re6.finditer( thewholething )
indices6               = []
for match in iter6 :
    indices6.append( match.start()+1 )

print 'Number of type 6 matches: ' + str( len( indices6 ) )

# Seventh pattern is to find all the entries of type: 
# 0 -1 0 0 0 0 0 0 but don't match 0 0 0 -1 0 0 0 0 0 0
# ( We match to a character starting this string. )
# For this one we have to add 2 to the start index.
re7                    = re.compile( "[a-z]\s0\s-1\s0\s0\s0\s0\s0\s0\s" )
iter7                  = re7.finditer( thewholething )
indices7               = []
for match in iter7 :
    indices7.append( match.start()+2 )

print 'Number of type 7 matches: ' + str( len( indices7 ) )

# Seventh pattern is to break the special string 0 0 24 0 0 s 
# that only occurs on the first horse mount: mount_pony unit.
re8                    = re.compile( "\s0\s0\s24\s0\s0\s" )
iter8                  = re8.finditer( thewholething )
indices8               = []
for match in iter8 :
    indices8.append( match.start()+1 )

print 'Number of type 8 matches: ' + str( len( indices8 ) )

# Merge the indices into one super-list and then sort them.
indices                = indices1 + indices2 + indices3 + indices4 + indices5 + indices6 + indices7 + indices8
indices.sort()

# Finally remove one bad index in the mount_pony entry.  Don't want
# to break the last 0 in the type 8 string 0 0 24 0 0.  This is at
# index 265 so find this index and remove it.
indices.remove( 265 )
ntotal                 = len( indices )

# Indices are NOT guarenteed to be unique.  This is a problem because it
# will break the line twice and introduce blank lines in the formatted
# modeldb file.  This will probably kill CA's parser.
uniqueindices          = []
for ii in range( ntotal-1 ) :
    if indices[ii] != indices[ii+1] :
        uniqueindices.append( indices[ii] )

uniqueindices.append( indices[ntotal-1] )
ntotalunique           = len( uniqueindices )

print 'total number of original matches: ' + str( ntotal )
print 'total number of unique matches: '   + str( ntotalunique )

# Note to self, Python's slice notation is at work here.
# When addressing into thewholething[i1:i2], the output DOES NOT
# include the character at index i2.  Python's way of explaining
# the slice notation is that the indicies point between the elements
# and not at the elements themselves.  Thus 0:1 brackets the 0th element
# and so only returns the 0th element.
fidout                 = open( 'formatted_battle_models.modeldb', 'w' )
fidout.write( thewholething[0:uniqueindices[0]] + '\n' )
for ii in range(ntotalunique-1) :
    fidout.write( thewholething[uniqueindices[ii]:uniqueindices[ii+1]] + '\n' )

numchars               = len( thewholething )
fidout.write( thewholething[uniqueindices[ntotalunique-1]:numchars] + '\n' )

fidout.close()

