import os
import glob
import re

import SCons.Tool
import SCons.Tool.cc
import SCons.Defaults

# Include file directories
INCLUDE_DIRS = [
    '.',
    'include00',
    'include01',
    'include02',
]

# force include files
FORCE_INCLUDE_FILES = [
    'include00/script_header_common01.h',
    'include00/script_header_common02.h'
]

# Define macros
DEFINE_MACROS = [
    'XXX',
    'YYY',
]

# Basic directories
SOURCE_DIR_TOP = 'src/'
PREPROCESS_DIR_TOP = 'preprocess/'

# File suffixes
SOURCE_FILE_SUFFIX = '.script'
PREPROCESS_FILE_SUFFIX = '.script.i'
DEPEND_FILE_SUFFIX = '.script.d'
DEPEND_FILE_ADJ_SUFFIX = '.script.d2'

# Source files
#SOURCE_FILES = [
#    'src/test00' + SOURCE_FILE_SUFFIX,
#    'src/test01/test01' + SOURCE_FILE_SUFFIX,
#    'src/test02/test02a' + SOURCE_FILE_SUFFIX,
#    'src/test02/test02b' + SOURCE_FILE_SUFFIX,
#]
#print 'SOURCE_FILES=', SOURCE_FILES
#SOURCE_FILES = glob.glob(SOURCE_DIR_TOP + '*'   + SOURCE_FILE_SUFFIX) + \
#               glob.glob(SOURCE_DIR_TOP + '*/*' + SOURCE_FILE_SUFFIX)
#print 'SOURCE_FILES=', SOURCE_FILES
#SOURCE_FILES = list(glob.iglob(SOURCE_DIR_TOP + '*' + SOURCE_FILE_SUFFIX)) + \
#               list(glob.iglob(SOURCE_DIR_TOP + '*/*' + SOURCE_FILE_SUFFIX))
#print 'SOURCE_FILES=', SOURCE_FILES
SOURCE_FILES = []
source_file_pattern = re.compile(SOURCE_FILE_SUFFIX.replace('.', '\\.') + '$')
for path,dirs,files in os.walk(SOURCE_DIR_TOP):
    for file in files:
        file_path = os.path.join(path, file).replace('\\', '/')
        if source_file_pattern.search(file_path) is not None:
            SOURCE_FILES = SOURCE_FILES + [file_path]
#print 'SOURCE_FILES=', SOURCE_FILES

# Source file path -> Preprocess file path
def convertSourceDirToPreprocess(source_file):
    preprocess_file = re.sub(
                          r'' + '^' + SOURCE_DIR_TOP.replace('/', '\\/'),
                          PREPROCESS_DIR_TOP, 
                          source_file.replace('\\', '/')
                      )
    return preprocess_file

# Source file path -> Target file path
def convertSourceToTarget(source_file):
    target_file = re.sub(
                      r'' + SOURCE_FILE_SUFFIX.replace('.', '\\.') + '$',
                      PREPROCESS_FILE_SUFFIX, 
                      convertSourceDirToPreprocess(source_file)
                  )
    return target_file

# Source file path -> Depend file path
def convertSourceToDepend(source_file):
    depend_file = re.sub(
                      r'' + SOURCE_FILE_SUFFIX.replace('.', '\\.') + '$',
                      DEPEND_FILE_SUFFIX, 
                      convertSourceDirToPreprocess(source_file)
                  )
    return depend_file

# Source file path -> Adjusted depend file path
def convertSourceToDependAdj(source_file):
    depend_file_adj = re.sub(
                          r'' + SOURCE_FILE_SUFFIX.replace('.', '\\.') + '$',
                          DEPEND_FILE_ADJ_SUFFIX, 
                          convertSourceDirToPreprocess(source_file)
                      )
    return depend_file_adj

# Depend file path -> Adjusted depend file path
def convertDependToDependAdj(depend_file):
    depend_file_adj = re.sub(
                          r'' + DEPEND_FILE_SUFFIX.replace('.', '\\.') + '$',
                          DEPEND_FILE_ADJ_SUFFIX, 
                          depend_file.replace('\\', '/')
                      )
    return depend_file_adj

# Depend file path -> Target file path
def convertDependToTarget(depend_file):
    target_file = re.sub(
                      r'' + DEPEND_FILE_SUFFIX.replace('.', '\\.') + '$',
                      PREPROCESS_FILE_SUFFIX, 
                      depend_file.replace('\\', '/')
                  )
    return target_file

# Depend file path -> Object file path (Dummy)
def convertDependToObject(depend_file):
    object_file = re.sub(
                      r'^.*\/',
                      '', 
                      re.sub(r'' + DEPEND_FILE_SUFFIX.replace('.', '\\.') + '$',
                          '.o',
                          depend_file.replace('\\', '/')
                      )
                  )
    return object_file

#
def parseDependFile(node, env, path):
    depend_file = str(node)
    depend_file_adj = convertDependToDependAdj(depend_file)
    target_file = convertDependToTarget(depend_file)
    object_file = convertDependToObject(depend_file)
    #print '***** parseDependFile: depend_file=%s, depend_file_adj=%s, target_file=%s, object_file=%s' % (depend_file, depend_file_adj, target_file, object_file)
    file_text_adj_now = '';
    if os.path.exists(depend_file_adj):
        file_text_adj_now = open(depend_file_adj, 'r').read()
    file_text = '';
    if os.path.exists(depend_file):
        if os.path.exists(depend_file):
            #i = open(depend_file, 'r')
            #ile_text = fi.read()
            #i.close()
            file_text = open(depend_file, 'r').read()
    file_text_adj_new = re.sub(r'^' + object_file, target_file, file_text)
    if file_text_adj_now != file_text_adj_new:
        #fo = open(depend_file_adj, 'w')
        #print '    >>>>>>>>>>> depend_file_adj=', depend_file_adj, ', file_text_adj_new=', file_text_adj_new, ', fo=', fo
        #fo.write(file_text_adj_new)
        #fo.close()
        open(depend_file_adj, 'w').write(file_text_adj_new)
        if os.path.exists(depend_file_adj):
            print 'Created or updated "' + depend_file_adj + '".'
        else:
            print 'Failed to create "' + depend_file_adj + '".'
    return []

def parseDependFileAdj(node, env, path):
    depend_file_adj = str(node)
    #print '***** parseDependFileAdj: depend_file_adj=', depend_file_adj
    env.ParseDepends(depend_file_adj)
    return []

#
def checkDependFile(node, env):
    #print '***** checkDependFile:', str(node)
    return node.exists()

def checkDependFileAdj(node, env):
    #print '***** checkDependFileAdj:', str(node)
    return node.exists()

#
scan_depend_file = Scanner(
                       function = parseDependFile,
                       skeys = [ DEPEND_FILE_SUFFIX ],
                       scan_check = checkDependFile
                   )

scan_depend_adj_file = Scanner(
                           function = parseDependFileAdj,
                           skeys = [ DEPEND_FILE_ADJ_SUFFIX ],
                           scan_check = checkDependFileAdj
                       )

#
build_depend_file = Builder(
                        #anction = '$CC -MF $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES',
                        anction = 'ECHO +++++ build_depend_file: TARGET=$TARGET, SOURCE=$SOURCE',
                        suffix = DEPEND_FILE_ADJ_SUFFIX,
                        src_suffix = DEPEND_FILE_SUFFIX,
                    )

#
def dummy(target, source):
    return []

parse_depend_file = Builder(
                        #action = Copy('$TARGET', '$SOURCE'),
                        #action = 'TYPE $SOURCE > $TARGET',
                        action = dummy('$TARGET', '$SOURCE'),
                        suffix = DEPEND_FILE_ADJ_SUFFIX,
                        src_suffix = DEPEND_FILE_SUFFIX,
                        src_builer = build_depend_file,
                        source_scanner = scan_depend_file,
                        target_scanner = scan_depend_adj_file
                    )

# Environment
env = Environment(
    #LANG = 'ja_JP.UTF-8',
    #LANG = 'ja_JP.eucJP',
    LANG = 'ja_JP.SJIS',
    TOOLS = ['mingw'],
    ENV = os.environ,
    CC = 'g++',
    CPPFLAGS = [ '-x', 'c++', '-E' ],
    CPPSUFFIXES = [ SOURCE_FILE_SUFFIX ],
    OBJSUFFIX = PREPROCESS_FILE_SUFFIX,
    INCPREFIX = '-I',
    CPPPATH = INCLUDE_DIRS,
    CPPDEFPREFIX = '-D',
    CPPDEFINES = DEFINE_MACROS,
    BUILDERS = {'parseDependFile': parse_depend_file}
)

# Adjust environment
static_obj,shared_obj = SCons.Tool.createObjBuilders(env)
static_obj.add_action(SOURCE_FILE_SUFFIX, SCons.Defaults.CXXAction)
shared_obj.add_action(SOURCE_FILE_SUFFIX, SCons.Defaults.ShCXXAction)
static_obj.add_emitter(SOURCE_FILE_SUFFIX, SCons.Defaults.StaticObjectEmitter)
shared_obj.add_emitter(SOURCE_FILE_SUFFIX, SCons.Defaults.SharedObjectEmitter)

# Adjust environment
for force_include_file in FORCE_INCLUDE_FILES:
    env.Append(CPPFLAGS = '-include')
    env.Append(CPPFLAGS = force_include_file)

#print env.Dump()

# Matchin method for newest file
#env.Decider('timestamp-newer')
#env.Decider('make')
#env.Decider('timestamp-match')
#env.Decider('MD5-timestamp')
env.Decider('MD5')

# Run
for source_file in SOURCE_FILES:
    source_file = source_file.replace('\\', '/')
    target_file = convertSourceToTarget(source_file)
    depend_file = convertSourceToDepend(source_file)
    depend_file_adj = convertSourceToDependAdj(source_file)
    
    depend_file_obj = env.Object(target = depend_file, source = source_file, CCFLAGS = '-M', CCCOM = '$CC -MF $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES')
    depend_file_adj_obj = env.parseDependFile(target = depend_file_adj, source = depend_file)
    target_obj = env.Object(target = target_file, source = source_file)
    
    #env.Requires(depend_file_obj, source_file)
    #env.Requires(depend_file_adj_obj, depend_file_obj)
    #env.Requires(target_obj, depend_file_adj_obj)
    #env.Requires(target_obj, source_file)
    #env.SideEffect(source_file, target_obj)
    #env.SideEffect(depend_file_obj, target_obj)
    #env.SideEffect(depend_file_adj_obj, target_obj)
