#!/usr/bin/env python

import os
import sys
import StringIO
import optparse
import datetime

# import from modules/hardcore/scripts/:
if __name__ == "__main__":
    sys.path.insert(1, os.path.join(sys.path[0], '..', '..', 'hardcore', 'scripts'))
import util
import opera_module

class Probe:
    def __init__(self, modulename, probename):
        self.__modulename = modulename
        self.__probename = probename

    def module(self): return self.__modulename
    def name(self): return self.__probename

class ProbeParser:
    def __init__(self):
        self.__probes = []
        self.__modules = []

    def parseProbe(self, modulename, line, quiet=True):
        #first word is probename
        probename = line.split()[0]

        #create probe and add to list
        probe = Probe(modulename, probename)
        self.__probes.append(probe)

        #print probe
        if not quiet:
            print "\t%s:%s" % (modulename, probename)

    def parseProbefile(self, module, quiet=True):
        filename = module.getModuleFile("probes")
        if not util.fileTracker.addInput(filename):
            #print "\t<%s> module does not have a module.probes file" % (module.name())
            return

        #register module
        modulename = module.name()
        self.__modules.append(modulename)

        #read lines from file
        lines = open( filename , "r" ).readlines()
        for line in lines:

            #strip line
            line = line.strip();

            #skip empty lines && comments
            if len(line) <= 0 or line.startswith("#"):
                continue

            #parse line as probe
            self.parseProbe(modulename, line, quiet)

    def loadProbes(self, sourceRoot, quiet=True):
        if not quiet:
            print "Reading module.probes files from all modules:"
        for module in opera_module.modules(sourceRoot):
            self.parseProbefile(module, quiet)
        return True

    def generateProbeCode(self, sourceRoot, quiet=True):
        if not quiet:
            print "Generate probe code:"

        #-------------------------------------------------------------------------------
        #generate header file
        headerDir = os.path.join(sourceRoot, 'modules', 'probetools', 'generated')
        util.makedirs(headerDir)
        headerOrg = os.path.join(headerDir, 'probedefines.h')
        headerTmp = os.path.join(headerDir, 'temp_probedefines.h')

        if not quiet:
            print headerOrg

        headerFile = open(headerTmp, "w")
        headerFile.write("//%s\n" % (datetime.datetime.now()))
        headerFile.write("//Generated by modules/probetools/scripts/preprocess_probes.py\n");
        headerFile.write("//Don't modify unless you know what you do. Better to run script.\n\n");
        headerFile.write("#ifndef _PROBEDEFINES_H\n");
        headerFile.write("#define _PROBEDEFINES_H\n\n");

        headerFile.write("enum\n{\n\n");

        #global probecount
        probecode = 0
        modulecount = 0

        headerFile.write("\t//First probe is the root probe which is the parent of all top probes\n");
        probecode += 1 #we start at 1
        headerFile.write("\tOP_PROBE_ROOT = %s,\n\n" % (hex(probecode)));
        probecode += 1

        for module in self.__modules:
            probecount = 0
            headerFile.write("\t//---------------------\n");
            headerFile.write("\t//%s\n" % (module));
            for probe in self.__probes:
                if probe.module() == module:
                    headerFile.write("\t%s = %s,\n" % (probe.name(), hex(probecode)))
                    probecode += 1
                    probecount += 1
            modulecount += 1
            headerFile.write("\t//%i probes\n\n" % (probecount));

        headerFile.write("\t//Totally %i probes in %i modules\n" % (probecode, modulecount));
        headerFile.write("\tOP_PROBE_COUNT = %s\n\n" % (hex(probecode)));

        headerFile.write("};\n\n");#enum

        headerFile.write("#endif //_PROBEDEFINES_H\n");
        headerFile.close();

        changes = False

        #DID ANYTHING CHANGE?
        diff = 0
        if os.path.exists(headerOrg):

            headerOrgFile = open(headerOrg, "r")
            headerTmpFile = open(headerTmp, "r")
            headerOrgFileLines = headerOrgFile.readlines();
            headerTmpFileLines = headerTmpFile.readlines();
            headerOrgFile.close()
            headerTmpFile.close()

            x = 0
            for i in headerOrgFileLines:
                if x>0 and diff == 0 and i != headerTmpFileLines[x]: #don check timestamp in first line
                    diff = 1
                x += 1
            x = 0
            for i in headerTmpFileLines:
                if x>0 and diff == 0 and i != headerOrgFileLines[x]: #don check timestamp in first line
                    diff = 1
                x += 1
        else:
            diff = 1

        if diff == 1:
            if not quiet:
                print "Found diff in new header file!"
            if os.path.exists(headerOrg):
                os.remove(headerOrg)
            os.rename(headerTmp, headerOrg)
            changes = True
        else:
            if not quiet:
                print "No changes in new header file!"
            os.remove(headerTmp)

        #-------------------------------------------------------------------------------
        #generate cpp file
        codeOrg = os.path.join(sourceRoot, 'modules', 'probetools', 'generated', 'probedefines.cpp')
        codeTmp = os.path.join(sourceRoot, 'modules', 'probetools', 'generated', 'temp_probedefines.cpp')

        if not quiet:
            print codeOrg

        codeFile = open(codeTmp, "w")
        codeFile.write("//%s\n" % (datetime.datetime.now()))
        codeFile.write("//Generated by modules/probetools/scripts/preprocess_probes.py\n");
        codeFile.write("//Don't modify unless you know what you do. Better to run script.\n\n");

        codeFile.write("#include \"probedefines.h\"\n\n");

        #function probedefines get probename
        #codeFile.write("const char* probedefines_get_probename(int location)\n{\n")
        #codeFile.write("\t//Could be done faster by direct lookup in array, but code is only used when writing report\n")
        #codeFile.write("\tswitch(location)\n\t{\n")
        #codeFile.write("\t\tcase %s : return \"%s\";\n" % ("OP_PROBE_ROOT", "OP_PROBE_ROOT"))
        #for probe in self.__probes:
        #    codeFile.write("\t\tcase %s : return \"%s\";\n" % (probe.name(), probe.name()))
        #codeFile.write("\t\tdefault: return 0;\n")
        #codeFile.write("\t}\n}\n\n")

        #function probedefines get probemodule
        codeFile.write("static const char* probedefines_get_probemodule(int location)\n{\n")
        codeFile.write("\t//Could be done faster by direct lookup in array, but code is only used when writing report\n")
        codeFile.write("\tswitch(location)\n\t{\n")
        codeFile.write("\t\tcase %s : return \"%s\";\n" % ("OP_PROBE_ROOT", "none"))
        for probe in self.__probes:
            codeFile.write("\t\tcase %s : return \"%s\";\n" % (probe.name(), probe.module()))
        codeFile.write("\t\tdefault: OP_ASSERT(!\"Unknown probe module! Something is wrong.\"); return 0;\n")
        codeFile.write("\t}\n}\n\n")
        codeFile.close();

        #DID ANYTHING CHANGE?
        diff = 0
        if os.path.exists(codeOrg):

            codeOrgFile = open(codeOrg, "r")
            codeTmpFile = open(codeTmp, "r")
            codeOrgFileLines = codeOrgFile.readlines();
            codeTmpFileLines = codeTmpFile.readlines();
            codeOrgFile.close()
            codeTmpFile.close()

            x = 0
            for i in codeOrgFileLines:
                if x>0 and diff == 0 and i != codeTmpFileLines[x]: #don check timestamp in first line
                    diff = 1
                x += 1
            x = 0
            for i in codeTmpFileLines:
                if x>0 and diff == 0 and i != codeOrgFileLines[x]: #don check timestamp in first line
                    diff = 1
                x += 1
        else:
            diff = 1

        if diff == 1:
            if not quiet:
                print "Found diff in new header file!"
            if os.path.exists(codeOrg):
                os.remove(codeOrg)
            os.rename(codeTmp, codeOrg)
            changes = True
        else:
            if not quiet:
                print "No changes in new header file!"
            os.remove(codeTmp)

        return 2 if changes else 0

def main(sourceRoot, feature_def=None, outputRoot=None, quiet=True):
    parser = ProbeParser()
    if parser.loadProbes(sourceRoot, "yes"):
        result = parser.generateProbeCode(outputRoot or sourceRoot, "yes")
        if result == 2:
            if not quiet:
                print "Probetools script executed successfully with changes."
        elif result == 1:
            if not quiet:
                print "Probetools script executed successfully without changes."
        else:
            if not quiet:
                print "Probetools could not generate code."
        return result
    else:
        if not quiet:
            print "Errors encountered while reading probe files from modules."
        return 1

if __name__ == "__main__":
    import sys

    # Figure out where the root is by looking for a core/pch.h file with a
    # matching modules/hardcore/CVS/Repository.
    #level = 0

    #while level < 17:
    #    if (os.path.exists(os.path.join(*([os.getcwd()] + [".."] * level + ["core", "pch.h"]))) and
    #        os.path.exists(os.path.join(*([os.getcwd()] + [".."] * level + ["modules", "hardcore", "CVS", "Repository"])))):
    #        Repository = None
    #        try:
    #            Repository = open(os.path.join(*([os.getcwd()] + [".."] * level + ["modules", "hardcore", "CVS", "Repository"])))
    #            if Repository.read().strip() == "hardcore":
    #                break
    #        finally:
    #            if Repository: Repository.close()
    #    level += 1

    #if level == 17:
    #    print >>sys.stderr, "%s: can't figure out where the root of this checkout is" % sys.argv[0]
    #    sys.exit(1)

    #sourceRoot = os.path.normpath(os.path.join(*([os.getcwd()] + [".."] * level)))

    #sys.path.insert(1, os.path.join(sourceRoot, "modules", "hardcore", "scripts"))

    #sys.exit(main(os.path.join(sys.path[0], '..', '..', 'hardcore', 'scripts')))

    sourceRoot = os.path.join(sys.path[0], '..', '..', '..');

    sys.exit(main(sourceRoot,None,None,"no"))
