#  ----------------------------------------------------------------
# Copyright 2016 Cisco Systems
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ------------------------------------------------------------------

"""
  api_model.py

 The meta-model of the generated API.
 Translation process converts the YANG model to classes defined in this module.
"""
from __future__ import absolute_import


from pyang.types import UnionTypeSpec


class Element(object):

    """
        The Element class.

        This is the super class of all modelled elements in the API.

        :attribute:: owned_elements
                    list of `Element` owned by this element

        :attribute:: owner
                    The owner of this `Element`.

        :attribute:: comment
                    The comments associated with this element.
    """

    def __init__(self):
        self.owned_elements = []
        self._owner = None
        self.comment = None
        self.revision = None

    @property
    def owner(self):
        return self._owner

    @owner.setter
    def owner(self, owner):
        self._owner = owner


class Deviation(Element):
    def __init__(self, iskeyword):
        Element.__init__(self)
        self.name = None
        self._stmt = None
        self.d_type = None
        self.d_target = None
        self.iskeyword = iskeyword

    @property
    def stmt(self):
        return self._stmt

    @stmt.setter
    def stmt(self, stmt):
        self._stmt = stmt
        self.name = stmt.arg

    def qn(self):
        names = []
        stmt = self.d_target
        while stmt.parent:
            if stmt.keyword not in ('container', 'list', 'rpc'):
                names.append(self.convert_prop_name(stmt))
            else:
                names.append(self.convert_owner_name(stmt))
            stmt = stmt.parent

        return '.'.join(reversed(names))

    def convert_prop_name(self, stmt):
        name = snake_case(stmt.arg)
        if self.iskeyword(name) or self.iskeyword(name.lower()):
            name = '%s_' % name

        if name.startswith('_'):
            name = '%s%s' % ('y', name)
        return name

    def convert_owner_name(self, stmt):
        name = escape_name(stmt.arg)
        if stmt.keyword == 'grouping':
            name = '%sGrouping' % camel_case(name)
        elif stmt.keyword == 'identity':
            name = '%sIdentity' % camel_case(name)
        elif stmt.keyword == 'rpc':
            name = camel_case(name) + 'Rpc'
        else:
            name = camel_case(name)
        if self.iskeyword(name) or self.iskeyword(name.lower()):
            name = '%s_' % name

        if name.startswith('_'):
            name = '%s%s' % ('Y', name)
        return name

    def get_package(self):
        if self.owner is None:
            return None
        if isinstance(self.owner, Package):
            return self.owner
        else:
            if hasattr(self.owner, 'get_package'):
                return self.owner.get_package()


class NamedElement(Element):

    '''

        An abstract element that may have a name
        The name is used for identification of the named element
        within the namespace that is defined or accessible

       :attribute:: name
                   The name of the Element

    '''

    def __init__(self):
        ''' The name of the named element'''
        super(NamedElement, self).__init__()
        self.name = None

    def get_py_mod_name(self):
        """
            Get the python module name that contains this
            NamedElement.
        """
        pkg = get_top_pkg(self)
        if not pkg.bundle_name:
            py_mod_name = 'ydk.models.%s' % pkg.name
        else:
            py_mod_name = 'ydk.models.%s.%s' % (pkg.bundle_name, pkg.name)
        return py_mod_name

    def get_cpp_header_name(self):
        """
            Get the c++ header that contains this
            NamedElement.
        """
        pkg = get_top_pkg(self)
        if pkg.curr_bundle_name == pkg.bundle_name:
            cpp_header_name = '%s.hpp' % pkg.name
        else:
            cpp_header_name = 'ydk_%s/%s.hpp' % (pkg.bundle_name, pkg.name)
        return cpp_header_name

    def get_meta_py_mod_name(self):
        """
            Get the python meta module that contains the meta model
            information about this NamedElement.

        """
        pkg = get_top_pkg(self)
        if not pkg.bundle_name:
            meta_py_mod_name = 'ydk.models._meta'
        else:
            meta_py_mod_name = 'ydk.models.%s._meta' % pkg.bundle_name
        return meta_py_mod_name

    def fqn(self):
        ''' get the Fully Qualified Name '''
        names = []
        element = self
        while element is not None:
            if isinstance(element, Deviation):
                element = element.owner
            names.append(element.name)
            element = element.owner
        return '.'.join(reversed(names))

    def qn(self):
        ''' get the qualified name , name sans
        package name '''
        names = []
        element = self
        while element is not None and not isinstance(element, Package):
            if isinstance(element, Deviation):
                element = element.owner
            names.append(element.name)
            element = element.owner
        return '.'.join(reversed(names))

    def qualified_cpp_name(self):
        ''' get the C++ qualified name , name sans
        package name '''