# lscriptreader.py
# One of 7 python scripts that implement a simple L system. 
# Useage:
#    database = lscriptreader.parse(fullpath_to_script.dat)
#
# The returned database is a dictionary of values read from the
# script.dat. See the sample script.dat files suppled with this
# module. 
#
# Malcolm Kesson
# 18 Jan 2012, 26 Jan 2012
import os, copy
  
# A barebones default database
defaults = {
    'title': 'untitled',
    'axiom': '',
    'rules': {}, # example { 'a': ['random','aba','bba',aab'] }
    'generations': 1,
    'angle': [45.0, 45.0],
    'scale': [1.0, 1.0],
    'move':  [1.0, 1.0],
    'port': 0,
    'display': 'mel',        # either mel or rib
    'seed': 1,
    'script_path': "unknown",
    'curvewidth': [0.05],    # renderman curves only
    'rgb_delta': [0.0]        # renderman incr/decr for rgb components
    }
    
# Input: the full path to a script.dat file.
# Output: a list of lines of text
def read(path):
    result = []
    f = open(path, 'r')
    lines = f.readlines()
    for line in lines:
        result.append(line.strip())
    result.append('script_path "%s"' % path)
    f.close()
    return result
  
# Input: a list of lines of text and a dictionary
# Output: a customized version of the default dictionary.
def parse(text, in_database):
    database = copy.deepcopy(in_database)
    for line in text:
        # Remove comments
        index = line.find('#')
        if index > -1:
            line = line[:index]
        if len(line.strip()) == 0:
            continue
        tokens = line.split()
        name = tokens[0]
        tokens = tokens[1:]
        
        if name == 'rule':
            char,subst = tokens
            char = char.strip('"')
            subst = subst.strip('"')
            # A rule can be applied in ONE of three ways,
            # rule "a" "aab"  (normal substitution)
            # rule "~a" "aab" (random substitution)
            # rule "*a" "aab" (substitution on LAST rewrite only)
            # rule "!a" "aab" (substitution NOT on last rewrite)
            mode = 'normal'
            if len(char) > 1:
                if char[0] == '~':   mode = 'random'
                elif char[0] == '*': mode = 'last_gen_only'
                elif char[0] == '!': mode = 'ignore_last_gen'
                char = char[len(char)-1] # last character
                
            # A new entry in the dictionary, create a list
            # and initialize it with the mode.
            if database['rules'].has_key(char) == False:
                database['rules'][char] = []
                database['rules'][char].append(mode) # a placeholder
            database['rules'][char].append(subst)
            database['rules'][char][0] = mode
            
            #print database['rules'][char]
            
        # Handle single string parameters
        elif (name == 'axiom' or name == 'title' or
              name == 'display' or name == 'script_path'):
            database[name] = tokens[0].strip('"')
        # Ditto single integer parameters
        elif name == 'generations' or name == 'port' or name == 'seed':
            database[name] = int(tokens[0])
        # Other parameters are assigned to lists
        else:
            database[name] = []
            for tok in tokens:
                database[name].append(tok)
    return database