"""
DBGET entry 
"""
from __future__ import absolute_import

__all__ = ["parser", "fields"]

from collections import defaultdict

from . import fields
from .parser import DBGETEntryParser

def entry_decorate(cls):
    """ Decorate the DBEntry subclass with properties for acessing
    the fields through the 'DBField._convert' interface
     
    """
    reserved_names_map = {"class": "class_", "def": "def_"}
    def construct_one(name):
        def get(self):
            field = getattr(self, name, None)
            if field is not None:
                return field._convert()
            else:
                return None
        return property(get, doc=name)
    
    def construct_multiple(name):
        def get(self):
            field = getattr(self, name, None)
            if field is not None:
                return [f._convert() for f in field]
            else:
                return None
        return property(get, doc=name)
    
    for name, field in cls.FIELDS:
        name_lower = name.lower()
        if not hasattr(cls, name_lower):
            if name in cls.MULTIPLE_FIELDS:
                prop = construct_multiple(name)
            else:
                prop = construct_one(name)
            setattr(cls, reserved_names_map.get(name_lower, name_lower), prop)
        
    return cls

class DBEntry(object):
    """ A DBGET entry object.
    """
    FIELDS = [("ENTRY", fields.DBEntryField),
              ]
    MULTIPLE_FIELDS = []
    
    def __init__(self, text=None):
        self._sections = {}
        if text is not None:
            self.parse(text)
            
    @property
    def entry_key(self):
        """ Primary entry key used for querying.
        """
        return self.entry.split(" ", 1)[0]
    
    def parse(self, text):
        parser = DBGETEntryParser()
        gen = parser.parse_string(text)
        entry_start = 0
        field_constructors = dict(self.FIELDS)
        sections = defaultdict(list)
        current = None
        current_subfield = None
        entry_fields = []
        for (event, title, text) in gen:
#            print event, title, text
            if event == DBGETEntryParser.SECTION_START:
                if title in field_constructors:
                    ftype = field_constructors[title]
                else:
                    ftype = fields.DBSimpleField
                current = ftype(text)
                if current.TITLE is None:
                    current.TITLE = title
            elif event == DBGETEntryParser.SECTION_END:
                entry_fields.append(current)
                current = None
            elif event == DBGETEntryParser.SUBSECTION_START:
                current_subfield = fields.DBSimpleField(text)
                current_subfield.TITLE = title
                if not isinstance(current, fields.DBFieldWithSubsections):
                    # Upgrade simple fields to FieldWithSubsection
                    new = fields.DBFieldWithSubsections(current.text)
                    new.TITLE = current.TITLE
                    current = new
                    
            elif event == DBGETEntryParser.SUBSECTION_END:
                current.subsections.append(current_subfield)
                current_subfield = None
            elif event == DBGETEntryParser.TEXT:
                if current_subfield is not None:
                    current_subfield.text += text
                elif current is not None:
                    current.text += text
            elif event == DBGETEntryParser.ENTRY_END:
                break
        
        self.fields = entry_fields
        self._consolidate()
        
    def _consolidate(self):
        """ Update mapping to field entries.
        """
        registered_fields = dict(self.FIELDS)
        multiple_fields = set(self.MULTIPLE_FIELDS)
        
        for field in self.fields:
            title = field.TITLE
            if title not in registered_fields:
                import warnings
                warnings.warn("Nonregisterd field %r in %r" % \
                                (title, type(self)))
            title_lower = title.lower()
            if title in multiple_fields:
                if not hasattr(self, title):
                    setattr(self, title, [])
                getattr(self, title).append(field)
            else:
                setattr(self, title, field)
        
    
    def __str__(self):
        return self.format()
    
    def format(self, section_indent=12):
        return "".join(f.format(section_indent)\
                       for f in self.fields)
        
    def get(self, key, default=None):
        raise NotImplementedError
    
        f = getattr(self, key, None)
        if f is not None:
            if key in self.MULTIPLE_FIELDS:
                return [f.text for f in f]
            else:
                return f.text
        else:
            return None
