#
# Copyright (C) 2005 by Yasushi Saito (yasushi.saito@gmail.com)
# 
# Cxxchecker is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# Cxxchecker is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
import xml.sax
from elemtypes import *
import options

class DocumentHandler(xml.sax.ContentHandler):
    IGNORED_ELEMENTS = [ "GCC_XML" ]    
    def __init__(self, objs):
        xml.sax.ContentHandler.__init__(self)
        self.elemStack = []

        # mapping from element ID -> element
        # local to the file.
        self.ids = {}

        # global mapping from element name -> element.
        self.objs = objs
        
    def __isIgnoredDir(self, path):
        for dir in options.ignoredDirs:
            if path.startswith(dir) or ( path.find("../" + dir) != -1 ):
                return True
        return False
            
    def startDocument(self):
        pass
    def endDocument(self):
        for obj in self.ids.values():
            obj.patchReferences(self.ids)
            
        for obj in self.ids.values():
            if type(obj) in (Namespace, Function, Class, Enumeration,
                             Typedef, Variable):
                #if not getattr(obj, "file", False):
                #    continue
                if self.__isIgnoredDir(getattr(obj, "file", "")):
                    continue
                
                if getattr(obj, "name", False):
                    fullName = obj.enclosingNamespace() + obj.name
                    self.objs[fullName] = obj
            
    def startElement(self, elemType, attrs):
        if elemType in self.IGNORED_ELEMENTS:
            return
        
        if elemType in ("Function", "OperatorFunction", "FunctionType",
                    "Constructor", "Method", "MethodType", "OperatorMethod", "Destructor",
                    "Converter"):
            obj = Function(elemType, attrs)
        elif elemType in ("Field", "Variable"):
            obj = Variable(elemType, attrs)
        elif elemType in ("Typedef", ):
            obj = Typedef(elemType, attrs)
        elif elemType == "FundamentalType":
            obj = FundamentalType(elemType, attrs)
        elif elemType == "PointerType":
            obj = PointerType(elemType, attrs)
        elif elemType == "ReferenceType":
            obj = ReferenceType(elemType, attrs)
        elif elemType == "CvQualifiedType":
            obj = CvQualifiedType(elemType, attrs)
        elif elemType == "Enumeration":
            obj = Enumeration(elemType, attrs)
        elif elemType in ("EnumValue", ):
            obj = EnumValue(elemType, attrs)
        elif elemType in ("Class", "Struct", "Union"):
            obj = Class(elemType, attrs)
        elif elemType == "Argument":
            obj = Argument(attrs)
        elif elemType == "Namespace":
            obj = Namespace(elemType, attrs)
        else:
            obj = Element(elemType, attrs)
        # print "ATTR %s %s" % (elemType, obj.objectName)
        self.elemStack.append(obj)
        
        if obj.id and obj.id not in self.ids:
            self.ids[obj.id] = obj
        
    def endElement(self, elemType):
        if elemType in self.IGNORED_ELEMENTS:
            return
        obj = self.elemStack.pop()
        assert obj.elemType == elemType    
        if isinstance(obj, Argument):
            function = self.elemStack[-1]
            if not isinstance(function, Function):
                raise Exception, "Argument appeared outside function declaration: " + str(function)
            function.arguments.append(obj)
            obj.context = function
        elif isinstance(obj, EnumValue):
            enum = self.elemStack[-1]
            if not isinstance(enum, Enumeration):
                raise Exception, "EnumValue appeared outside enum declaration: " + str(enum)
            enum.values.append(obj)
            obj.context = enum
            
    pass

def parseFile(path, objs):
    handler = DocumentHandler(objs)
    xml.sax.parse(path, handler)
    
