"""

http://relaxng.org/compact-tutorial-20030326.html

BUGS:
    repeats patterns
   

"""

from sys import stderr
import re

from objectmodel import ObjectModel, Class, Property
import qname
import langio

class Error(RuntimeError):
   pass

class Generator (langio.ModelGenerator):
    """
 
    >>> import loader
    >>> m = loader.load('test-data/poscond2.asn')
    
    >>> import rnc
    >>> g = rnc.Generator(model=m)

    >>> g.run()

    """

    def __init__(self, **kwargs):
       super(Generator, self).__init__(**kwargs)

    def qname(self, obj) :
       return self.map.qname(getattr(obj, "name", obj))
    
    def run(self):
       counts = self.model.namespaces_with_count(self.map)
       self.default_short = counts[-1][1]
       self.map.bind('', self.map.getLong(self.default_short))
       
       self.out('default namespace = "%s"\n' % self.map.getLong(''))
       
       pad = -1 * max([len(short) for count, short in counts])
       for (count, short) in counts:
          self.out('namespace %*s = "%s"\n' %
                 (pad, short, self.map.getLong(short)))

       self.out("start = ", self.qname(self.model.classes[0]))
       self.out("\n")
       self.out("#\n")
       self.out("# XML Elements corresponding to classes\n")
       self.out("#\n")

       for c in self.model.classes:
          self.outClass(c)

       self.out("\n")
       self.out("#\n")
       self.out("# XML Elements corresponding to properties\n")
       self.out("#\n")
       for prop in self.model.properties:
          self.out(self.qname(prop.name), "\n  = ")
          self.out(self.element_string(prop))
          elements = set()
          self.add_all_possible_elements(elements, clsuri=prop.to)
          for e in elements:
             self.out("  | " + e)

    def possible_elements(self, elements, item=None, clsuri=None):

       """add to the set all the elements we could reach by stripe
       skipping.  We need to enumerate them because rnc wont handle
       out-of-element recursive patterns."""

       if item is None:
          item = self.model.get_by_uri(clsuri)

       if isinstance(item, objectmodel.Class):
          s = self.string_for_class(item)
          if s in elements:
             return
          s.add(elements)
          # add all the subclasses
          # add all the properties of all subclasses

       if isinstance(item, objectmodel.Property):
          
       

    def outClassInner(self, c):
       iprops = [self.propertyString(x) for x in
                 self.model.propertiesForClassWithInheritance(c)]

       self.out("element", self.qname(c), "{",)
       if iprops:
          self.out(" & ".join(iprops))
       else:
           self.out("empty")
       self.out("}\n")

       
    def outClass(self, c):

       self.out(self.qname(c), "\n  = ")

       self.outClassInner(c)

       for sub in self.model.subclassesForClass(c):
          self.out("  | ")
          self.outClassInner(sub)

       for prop in self.model.propertiesForClassWithInheritance(c):
          self.out("  | ")
          self.outPropertyInner(prop)

       self.out("#\n")
       
    def propertyString(self, prop):
        result = self.qname(prop.name)
        return result

    def outPropertyInner(self, prop):
       name = self.qname(prop.name)

       if prop.list or prop.multi:
          suffix = "*"
       else:
          suffix = ""

       self.out("element", name, "{")
       self.out(self.qname(prop.to) + suffix)
       self.out("}\n")
       
    def outProperty(self, prop):

       name = self.qname(prop.name)

       self.out(name, "= ")
       self.outPropertyInner(prop)

       

      
if __name__ == "__main__":
    import doctest, sys
    doctest.testmod(sys.modules[__name__])
