#
# Copyright 2010 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-gsm
#
# GNU Radio 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 3, or (at your option)
# any later version.
#
# GNU Radio 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.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
"""
A base class is created.

Classes based upon this are used to make more user-friendly interfaces
to the doxygen xml docs than the generated classes provide.
"""
from __future__ import print_function
from __future__ import unicode_literals

import os
import pdb

from xml.parsers.expat import ExpatError

from .generated import compound


class Base(object):

    class Duplicate(Exception):
        pass

    class NoSuchMember(Exception):
        pass

    class ParsingError(Exception):
        pass

    def __init__(self, parse_data, top=None):
        self._parsed = False
        self._error = False
        self._parse_data = parse_data
        self._members = []
        self._dict_members = {}
        self._in_category = {}
        self._data = {}
        if top is not None:
            self._xml_path = top._xml_path
            # Set up holder of references
        else:
            top = self
            self._refs = {}
            self._xml_path = parse_data
        self.top = top

    @classmethod
    def from_refid(cls, refid, top=None):
        """ Instantiate class from a refid rather than parsing object. """
        # First check to see if its already been instantiated.
        if top is not None and refid in top._refs:
            return top._refs[refid]
        # Otherwise create a new instance and set refid.
        inst = cls(None, top=top)
        inst.refid = refid
        inst.add_ref(inst)
        return inst

    @classmethod
    def from_parse_data(cls, parse_data, top=None):
        refid = getattr(parse_data, 'refid', None)
        if refid is not None and top is not None and refid in top._refs:
            return top._refs[refid]
        inst = cls(parse_data, top=top)
        if refid is not None:
            inst.refid = refid
            inst.add_ref(inst)
        return inst

    def add_ref(self, obj):
        if hasattr(obj, 'refid'):
            self.top._refs[obj.refid] = obj

    mem_classes = []

    def get_cls(self, mem):
        for cls in self.mem_classes:
            if cls.can_parse(mem):
                return cls
        raise Exception(("Did not find a class for object '%s'." \
                                 % (mem.get_name())))

    def convert_mem(self, mem):
        try:
            cls = self.get_cls(mem)
            converted = cls.from_parse_data(mem, self.top)
            if converted is None:
                raise Exception('No class matched this object.')
            self.add_ref(converted)
            return converted
        except Exception as e:
            print(e)

    @classmethod
    def includes(cls, inst):
        return isinstance(inst, cls)

    @classmethod
    def can_parse(cls, obj):
        return False

    def _parse(self):
        self._parsed = True

    def _get_dict_members(self, cat=None):
        """
        For given category a dictionary is returned mapping member names to
        members of that category.  For names that are duplicated the name is
        mapped to None.
        """
        self.confirm_no_error()
        if cat not in self._dict_members:
            new_dict = {}
            for mem in self.in_category(cat):
                if mem.name() not in new_dict:
                    new_dict[mem.name()] = mem
                else:
                    new_dict[mem.name()] = self.Duplicate
            self._dict_members[cat] = new_dict
        return self._dict_members[cat]

    def in_category(self, cat):
        self.confirm_no_error()
        if cat is None:
            return self._members
        if cat not in self._in_category:
            self._in_category[cat] = [mem for mem in self._members
                                      if cat.includes(mem)]
        return self._in_category[cat]

    def get_member(self, name, cat=None):
        self.confirm_no_error()
        # Check if it's in a namespace or class.
        bits = name.split('::')
        first = bits[0]
        rest = '::'.join(bits[1:])
        member = self._get_dict_members(cat).get(first, self.NoSuchMember)
        # Raise any errors that are returned.
        if member in set([self.NoSuchMember, self.Duplicate]):
            raise member()
        if rest:
            return member.get_member(rest, cat=cat)
        return member

    def has_member(self, name, cat=None):
        try:
            mem = self.get_member(name, cat=cat)
            return True
        except self.NoSuchMember:
            return False

    def data(self):
        self.confirm_no_error()
        return self._data

    def members(self):
        self.confirm_no_error()
        return self._members

    def process_memberdefs(self):
        mdtss = []
        for sec in self._retrieved_data.compounddef.sectiondef:
            mdtss += sec.memberdef
        # At the moment we lose all information associated with sections.
        # Sometimes a memberdef is in several sectiondef.
        # We make sure we don't get duplicates here.
        uniques = set([])
        for mem in mdtss:
            converted = self.convert_mem(mem)
            pair = (mem.name, mem.__class__)
            if pair not in uniques:
                uniques.add(pair)
                self._members.append(converted)

    def retrieve_data(self):
        filename = os.path.join(self._xml_path, self.refid + '.xml')
        try:
            self._retrieved_data = compound.parse(filename)
        except ExpatError:
            print('Error in xml in file %s' % filename)
            self._error = True
            self._retrieved_data = None

    def check_parsed(self):
        if not self._parsed:
            self._parse()

    def confirm_no_error(self):
        self.check_parsed()
        if self._error:
            raise self.ParsingError()

    def error(self):
        self.check_parsed()
        return self._error

    def name(self):
        # first see if we can do it without processing.
        if self._parse_data is not None:
            return self._parse_data.name
        self.check_parsed()
        return self._retrieved_data.compounddef.name
