#!/usr/bin/env python2.4

import sys, os, re
from optparse import OptionParser
import xml.parsers.expat

class postproc:
    def __init__(self, filename, repository, repoid):
        self.start_intro_re  = re.compile("/\*\*\* \+intro (\w+) \*\*\*/")
        self.end_intro_re    = re.compile("/\*\*\* \-intro (\w+) \*\*\*/")
        self.start_access_re = re.compile("/\*\*\* \+access ([(\w|::)]+) \*\*\*")
        self.access_op_re    = re.compile("/\*\*\* op ([(\w|::)]+) \*\*\*")
        self.end_access_re   = re.compile("/\*\*\* \-access ([(\w|::)]+) \*\*\*")
        self.cctor_start_re  = re.compile("/\*\*\* \+copy ctor for class (\w+) \*\*\*/")
        self.cctor_end_re    = re.compile("/\*\*\* \-copy ctor for class (\w+) \*\*\*/")
        self.start_decl_re   = re.compile("/\*\*\* \+class (\w+) \*\*\*/")
        self.end_decl_re     = re.compile("/\*\*\* \-class (\w+) \*\*\*/")
        self.junk_re         = re.compile("^(\n|#line)")
        self.in_class        = None
	self.includes        = {} # key: self.in_class, content: introduced lines
        self.repository      = repository
	self.repoid          = repoid
        self.file = open(filename)

    def entity_already_known(self, type, classname):
        self.tmp_result = False
	
        def start_element(name, attrs):
            if name == type:
                if attrs['sig'] == classname:
                    self.tmp_result = True

        p = xml.parsers.expat.ParserCreate()
        p.StartElementHandler = start_element
        repo = open(self.repository)
        p.ParseFile(repo)
	return self.tmp_result
        
    def process(self):
        """ Main loop of the processor.
        """
        while 1:
            line = self.skip_junk()

            # now try which regex matches on the current line
	    m = self.start_decl_re.search(line)
	    if m:
		self.in_class = m.group(1)
		continue

            m = self.start_intro_re.search(line)
            if m:
                including_aspect = m.group(1)

		# if both the aspect as well as the class are known in
		# the previous module, we must not strip off that
		# introduction!!
                if self.entity_already_known("class", self.in_class) and \
			self.entity_already_known("aspect", m.group(1)):
		    continue
		
		lines = self.skip_until_regex_reached(self.end_intro_re)
		self.includes[self.in_class] = lines
                continue

            if self.cctor_start_re.search(line):
                self.skip_until_regex_reached(self.cctor_end_re)
                continue

            m = self.end_decl_re.search(line)
            if m:
		self.in_class = None
                classname = m.group(1)
                self.insert_include(classname)
                continue
                
            m = self.start_access_re.search(line)
            if m:
                membername = m.group(1)
                self.parse_access_lines(membername)
                continue

            # no regex matched, just print this line
            print line,

    def parse_access_lines(self, membername):
        copy = ""
        member = None
        regex = re.compile("(.*)::(\w+)")
        m = regex.search(membername)
        classname = m.group(1)
        membername = m.group(2)
        print "IntroMap<%s::__Includes_%d>::getIntroElement("  \
	    % (classname, self.repoid),
        while 1:
            line = self.skip_junk()
                       
            m = self.access_op_re.search(line)
            if m:
                member = m.group(1)
                regex = re.compile(".*::(\w+)")
                m2 = regex.search(member)
                member = m2.group(1)
                line = self.skip_junk()
                m = re.compile("^\->(.*)$").search(line)
                if m:
                    # we have access using the -> operator
                    member = m.group(1)
                    print "%s->__intros)->%s" % (copy, member),
                else:
                    # we assume that we have access using the '.' operator
                    member = line.lstrip('.')
                    print "%s.__intros)->%s" % (copy, member),
                continue

            if self.end_access_re.search(line):
                # end access
                if member:
                    # there was an operator accesss
                    pass
                else:
                    print "this->__intros)->%s" % copy,
                return
            copy += line

    def skip_junk(self):
        """ skip lines which contain only junk """
        while 1:
            line = self.file.next()
            if self.junk_re.search(line):
                continue
            return line
        
    def skip_until_regex_reached(self, regex):
        """ Skips lines until a line matching a regex is reached.
        """
	lines = []
        while 1:
	    line = self.skip_junk()
            m = regex.search(line)
            if m:
                return lines
	    else:
		lines.append(line)
        
    def insert_include(self, classname):
	print "struct __Includes_%d : public IntroductionList { " % (self.repoid)
	for line in self.includes[classname]:
	    print line
	print "};"

def main():
    parser = OptionParser()
    parser.add_option("-r", dest="repository", help="path to repository file")
    parser.add_option("-m", dest="repoid", type="int", default=0, help="moduleid, defaults to 0")

    (options, args) = parser.parse_args()

    if len(args) == 0:
        parser.error('please give a filename to process')

    if options.repository == None:
        parser.error('please specify a repository to work on')
        
    p = postproc(args[0], options.repository, options.repoid)
    try:
        p.process()
    except StopIteration:
        pass
        
if __name__ == "__main__":
    main()
