# -*- mode:python -*-

# Copyright (c) 2004, 2005
# The Regents of The University of Michigan
# All Rights Reserved
#
# This code is part of the M5 simulator, developed by Nathan Binkert,
# Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions
# from Ron Dreslinski, Dave Greene, Lisa Hsu, Kevin Lim, Ali Saidi,
# and Andrew Schultz.
#
# Permission is granted to use, copy, create derivative works and
# redistribute this software and such derivative works for any
# purpose, so long as the copyright notice above, this grant of
# permission, and the disclaimer below appear in all copies made; and
# so long as the name of The University of Michigan is not used in any
# advertising or publicity pertaining to the use or distribution of
# this software without specific, written prior authorization.
#
# THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
# UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
# WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
# EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
# LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
# INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
# ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
# IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGES.

import os, os.path, re, sys

Import('env')

import scons_helper

def WriteEmbeddedPyFile(target, source, path, name, ext, filename):
    if isinstance(source, str):
        source = file(source, 'r')

    if isinstance(target, str):
        target = file(target, 'w')

    print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \
          (`path`, `name`, `ext`, `filename`)

    for line in source:
        line = line
        # escape existing backslashes
        line = line.replace('\\', '\\\\')
        # escape existing triple quotes
        line = line.replace("'''", r"\'\'\'")

        print >>target, line,

    print >>target, "''')"
    print >>target

def WriteCFile(target, source, name):
    if isinstance(source, str):
        source = file(source, 'r')

    if isinstance(target, str):
        target = file(target, 'w')

    print >>target, 'const char %s_string[] = {' % name

    count = 0
    from array import array
    try:
        while True:
            foo = array('B')
            foo.fromfile(source, 10000)
            l = [ str(i) for i in foo.tolist() ]
            count += len(l)
            for i in xrange(0,9999,20):
                print >>target, ','.join(l[i:i+20]) + ','
    except EOFError:
        l = [ str(i) for i in foo.tolist() ]
        count += len(l)
        for i in xrange(0,len(l),20):
            print >>target, ','.join(l[i:i+20]) + ','
        print >>target, ','.join(l[i:]) + ','

    print >>target, '};'
    print >>target, 'const int %s_length = %d;' % (name, count)
    print >>target

def splitpath(path):
    dir,file = os.path.split(path)
    path = []
    assert(file)
    while dir:
        dir,base = os.path.split(dir)
        path.insert(0, base)
    return path, file

def MakeEmbeddedPyFile(target, source, env):
    target = file(str(target[0]), 'w')
   
    tree = {}
    for src in source:
        src = str(src)
        path,pyfile = splitpath(src)
        node = tree
        for dir in path:
            if not node.has_key(dir):
                node[dir] = { }
            node = node[dir]

        name,ext = pyfile.split('.')
        if name == '__init__':
            node['.hasinit'] = True
        node[pyfile] = (src,name,ext,src)

    done = False
    while not done:
        done = True
        for name,entry in tree.items():
            if not isinstance(entry, dict): continue
            if entry.has_key('.hasinit'): continue

            done = False
            del tree[name]
            for key,val in entry.iteritems():
                if tree.has_key(key):
                    raise NameError, \
                          "dir already has %s can't add it again" % key
                tree[key] = val

    files = []
    def populate(node, path = []):
        names = node.keys()
        names.sort()
        for name in names:
            if name == '.hasinit':
                continue
            
            entry = node[name]
            if isinstance(entry, dict):
                if not entry.has_key('.hasinit'):
                    raise NameError, 'package directory missing __init__.py'
                populate(entry, path + [ name ])
            else:
                pyfile,name,ext,filename = entry
                files.append((pyfile, path, name, ext, filename))
    populate(tree)

    for pyfile, path, name, ext, filename in files:
        WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename)

def MakeDefinesPyFile(target, source, env):
    f = file(str(target[0]), 'w')
    print >>f, "import __main__"
    print >>f, "__main__.m5_build_env = ",
    print >>f, source[0]
    f.close()

CFileCounter = 0
def MakePythonCFile(target, source, env):
    global CFileCounter
    target = file(str(target[0]), 'w')

    print >>target, '''\
#include "base/embedfile.hh"

namespace {
'''
    for src in source:
        src = str(src)
        fname = os.path.basename(src)
        name = 'embedded_file%d' % CFileCounter
        CFileCounter += 1
        WriteCFile(target, src, name)
        print >>target, '''\
EmbedMap %(name)s("%(fname)s",
    %(name)s_string, %(name)s_length);

''' % locals()
    print >>target, '''\

/* namespace */ }
'''

# base list of .py files to embed
embedded_py_files = [ '../util/pbs/jobfile.py' ]
# add all .py files in python/m5 
objpath = os.path.join(env['SRCDIR'], 'python', 'm5')
for root, dirs, files in os.walk(objpath, topdown=True):
    for i,dir in enumerate(dirs):
        if dir == 'SCCS':
            del dirs[i]
            break

    assert(root.startswith(objpath))
    for f in files:
        if f.endswith('.py'):
            embedded_py_files.append(os.path.join(root, f))

embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh')

optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
env.Command('defines.py', Value(optionDict), MakeDefinesPyFile)

env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile)
env.Depends('embedded_py.cc', embedfile_hh)
env.Command('embedded_py.cc',
            ['string_importer.py', 'defines.py', 'embedded_py.py'],
            MakePythonCFile)
