"""Mongodb implementations of authorization objects."""

# pylint: disable=no-init
#     Numerous classes don't require __init__.
# pylint: disable=too-many-public-methods,too-few-public-methods
#     Number of methods are defined in specification
# pylint: disable=protected-access
#     Access to protected methods allowed in package mongo package scope
# pylint: disable=too-many-ancestors
#     Inheritance defined in specification

#from ..id.objects import IdList
#import importlib


import importlib


from . import mdata_conf
from .. import utilities
from ...abstract_osid.authorization import objects as abc_authorization_objects
from ..id.objects import IdList
from ..osid import objects as osid_objects
from ..osid.metadata import Metadata
from ..primitives import Id
from ..utilities import get_provider_manager
from dlkit.abstract_osid.osid import errors
from dlkit.mongo.osid import objects as osid_objects
from dlkit.primordium.id.primitives import Id




class Authorization(abc_authorization_objects.Authorization, osid_objects.OsidRelationship):
    """An Authorization is a mapping among an actor, a ``Function`` and a ``Qualifier``.


    This interface is not required for performing authorization checks
    but is used for examining and managing authorizations.




    The actor of an authorization may be specified in a variety of
    forms.




      * ``Agent``
      * ``Resource:`` the authorization provider uses all the ``Agents``
        associated with a ``Resource`` for matching authorizations
      * ``Resource`` and ``Trust:`` the authorization provider uses the
        associated ``Agents`` within a cicle of ``Trust``








    An explicit ``Authorization`` represents the mappings as they are
    specified in the authorization provdier. Implicit authorizations may
    be retrieved which are authorizations inferred through the
    ``Function`` or ``Qualifier`` hierarchies. An implicit
    ``Authorization`` is one where ``is_implicit()`` is true and should
    not be used for modification as it is only available for auditing
    purposes.




    An ``Authorization`` containing a ``Resource`` may also provide the
    associated Agent in a request for implicit authorizations or for all
    the authorizations, both explicit and implicit, for a given
    ``Agent``.


    """


    _record_type_data_sets = {}
    _namespace = 'authorization.Authorization'


    def __init__(self, osid_object_map, runtime=None):
        osid_objects.OsidObject.__init__(self, osid_object_map, runtime)
        self._record_type_data_sets = self._get_registry('AUTHORIZATION_RECORD_TYPES')
        self._records = dict()
        self._load_records(osid_object_map['recordTypeIds'])
        self._catalog_name = 'vault'


    def is_implicit(self):
        """Tests if this authorization is implicit.


        return: (boolean) - ``true`` if this authorization is implicit,
                ``false`` otherwise
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.is_group_template
        return self._my_map['implicit']

    def has_resource(self):
        """Tests if this authorization has a ``Resource``.


        return: (boolean) - ``true`` if this authorization has a
                ``Resource,``  ``false`` otherwise
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.has_avatar_template
        return bool(self._my_map['resourceId'])

    def get_resource_id(self):
        """Gets the ``resource _id`` for this authorization.


        return: (osid.id.Id) - the ``Resource Id``
        raise:  IllegalState - ``has_resource()`` is ``false``
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.get_avatar_id_template
        if not self._my_map['resourceId']:
            raise errors.IllegalState('this Authorization has no resource')
        else:
            return Id(self._my_map['resourceId'])

    resource_id = property(fget=get_resource_id)

    def get_resource(self):
        """Gets the ``Resource`` for this authorization.


        return: (osid.resource.Resource) - the ``Resource``
        raise:  IllegalState - ``has_resource()`` is ``false``
        raise:  OperationFailed - unable to complete request
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.get_avatar_template
        if not self._my_map['resourceId']:
            raise errors.IllegalState('this Authorization has no resource')
        mgr = self._get_provider_manager('RESOURCE')
        if not mgr.supports_resource_lookup():
            raise errors.OperationFailed('Resource does not support Resource lookup')
        lookup_session = mgr.get_resource_lookup_session()
        lookup_session.use_federated_bin_view()
        osid_object = lookup_session.get_resource(self.get_resource_id())
        return osid_object

    resource = property(fget=get_resource)

    def has_trust(self):
        """Tests if this authorization has a ``Trust``.


        return: (boolean) - ``true`` if this authorization has a
                ``Trust,``  ``false`` otherwise
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.has_avatar_template
        return bool(self._my_map['trustId'])

    def get_trust_id(self):
        """Gets the ``Trust``  ``Id`` for this authorization.


        return: (osid.id.Id) - the trust ``Id``
        raise:  IllegalState - ``has_trust()`` is ``false``
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.get_avatar_id_template
        if not self._my_map['trustId']:
            raise errors.IllegalState('this Authorization has no trust')
        else:
            return Id(self._my_map['trustId'])

    trust_id = property(fget=get_trust_id)

    def get_trust(self):
        """Gets the ``Trust`` for this authorization.


        return: (osid.authentication.process.Trust) - the ``Trust``
        raise:  IllegalState - ``has_trust()`` is ``false``
        raise:  OperationFailed - unable to complete request
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.get_avatar_template
        if not self._my_map['trustId']:
            raise errors.IllegalState('this Authorization has no trust')
        mgr = self._get_provider_manager('AUTHENTICATION.PROCESS')
        if not mgr.supports_trust_lookup():
            raise errors.OperationFailed('Authentication.Process does not support Trust lookup')
        lookup_session = mgr.get_trust_lookup_session()
        lookup_session.use_federated_agency_view()
        osid_object = lookup_session.get_trust(self.get_trust_id())
        return osid_object

    trust = property(fget=get_trust)

    def has_agent(self):
        """Tests if this authorization has an ``Agent``.


        An implied authorization may have an ``Agent`` in addition to a
        specified ``Resource``.


        return: (boolean) - ``true`` if this authorization has an
                ``Agent,``  ``false`` otherwise
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.has_avatar_template
        return bool(self._my_map['agentId'])

    def get_agent_id(self):
        """Gets the ``Agent Id`` for this authorization.


        return: (osid.id.Id) - the ``Agent Id``
        raise:  IllegalState - ``has_agent()`` is ``false``
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.get_avatar_id_template
        if not self._my_map['agentId']:
            raise errors.IllegalState('this Authorization has no agent')
        else:
            return Id(self._my_map['agentId'])

    agent_id = property(fget=get_agent_id)

    def get_agent(self):
        """Gets the ``Agent`` for this authorization.


        return: (osid.authentication.Agent) - the ``Agent``
        raise:  IllegalState - ``has_agent()`` is ``false``
        raise:  OperationFailed - unable to complete request
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.resource.Resource.get_avatar_template
        if not self._my_map['agentId']:
            raise errors.IllegalState('this Authorization has no agent')
        mgr = self._get_provider_manager('AUTHENTICATION')
        if not mgr.supports_agent_lookup():
            raise errors.OperationFailed('Authentication does not support Agent lookup')
        lookup_session = mgr.get_agent_lookup_session()
        lookup_session.use_federated_agency_view()
        osid_object = lookup_session.get_agent(self.get_agent_id())
        return osid_object

    agent = property(fget=get_agent)

    def get_function_id(self):
        """Gets the ``Function Id`` for this authorization.


        return: (osid.id.Id) - the function ``Id``
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.learning.Activity.get_objective_id
        return Id(self._my_map['functionId'])

    function_id = property(fget=get_function_id)

    def get_function(self):
        """Gets the ``Function`` for this authorization.


        return: (osid.authorization.Function) - the function
        raise:  OperationFailed - unable to complete request
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.learning.Activity.get_objective
        mgr = self._get_provider_manager('AUTHORIZATION')
        if not mgr.supports_function_lookup():
            raise errors.OperationFailed('Authorization does not support Function lookup')
        lookup_session = mgr.get_function_lookup_session()
        lookup_session.use_federated_vault_view()
        return lookup_session.get_function(self.get_function_id())

    function = property(fget=get_function)

    def get_qualifier_id(self):
        """Gets the ``Qualifier Id`` for this authorization.


        return: (osid.id.Id) - the qualifier ``Id``
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.learning.Activity.get_objective_id
        return Id(self._my_map['qualifierId'])

    qualifier_id = property(fget=get_qualifier_id)

    def get_qualifier(self):
        """Gets the qualifier for this authorization.


        return: (osid.authorization.Qualifier) - the qualifier
        raise:  OperationFailed - unable to complete request
        *compliance: mandatory -- This method must be implemented.*


        """
        # Implemented from template for osid.learning.Activity.get_objective
        mgr = self._get_provider_manager('AUTHORIZATION')
        if not mgr.supports_qualifier_lookup():
            raise errors.OperationFailed('Authorization does not support Qualifier lookup')
        lookup_session = mgr.get_qualifier_lookup_session()
        lookup_session.use_federated_vault_view()
        return lookup_session.get_qualifier(self.get_qualifier_id())

    qualifier = property(fget=get_qualifier)

    @utilities.arguments_not_none
    def get_authorization_record(self, authorization_record_type):
        """Gets the authorization record corresponding to the given ``Authorization`` record ``Type``.


        This method is used to retrieve an object implementing the
        requested record. The ``authorization_record_type`` may be the
        ``Type`` returned in ``get_record_types()`` or any of its
        parents in a ``Type`` hierarchy where
        ``has_record_type(authorization_record_type)`` is ``true`` .


        arg:    authorization_record_type (osid.type.Type): the type of
                the record to retrieve
        return: (osid.authorization.records.AuthorizationRecord) - the
                authorization record
        raise:  NullArgument - ``authorization_record_type`` is ``null``
        raise:  OperationFailed - unable to complete request
        raise:  Unsupported -
                ``has_record_type(authorization_record_type)`` is
                ``false``
        *compliance: mandatory -- This method must be implemented.*


        """
        return self._get_record(authorization_record_type)


class AuthorizationForm(abc_authorization_objects.AuthorizationForm, osid_objects.OsidRelationshipForm):
    """This is the form for creating and updating ``Authorizations``.


    Like all ``OsidForm`` objects, various data elements may be set here
    for use in the create and update methods in the
    ``AuthorizationAdminSession``. For each data element that may be
    set, metadata may be examined to provide display hints or data
    constraints.


    """


    _record_type_data_sets = dict()
    _namespace = 'authorization.Authorization'


    def __init__(self, osid_object_map=None, record_types=None, runtime=None, **kwargs):
        osid_objects.OsidForm.__init__(self, runtime=runtime)
        self._record_type_data_sets = self._get_registry('AUTHORIZATION_RECORD_TYPES')
        self._kwargs = kwargs
        if 'catalog_id' in kwargs:
            self._catalog_id = kwargs['catalog_id']
        self._init_metadata(**kwargs)
        self._records = dict()
        self._supported_record_type_ids = []
        if osid_object_map is not None:
            self._for_update = True
            self._my_map = osid_object_map
            self._load_records(osid_object_map['recordTypeIds'])
        else:
            self._my_map = {}
            self._for_update = False
            self._init_map(**kwargs)
            if record_types is not None:
                self._init_records(record_types)
        self._supported_record_type_ids = self._my_map['recordTypeIds']


    def _init_metadata(self, **kwargs):
        osid_objects.OsidRelationshipForm._init_metadata(self, **kwargs)


    def _init_map(self, **kwargs):
        osid_objects.OsidRelationshipForm._init_map(self)
        self._my_map['assignedVaultIds'] = [str(kwargs['vault_id'])]
        self._my_map['functionId'] = str(kwargs['function_id'])
        self._my_map['qualifierId'] = str(kwargs['qualifier_id'])
        if 'agent_id' in kwargs:
            self._my_map['agentId'] = str(kwargs['agent_id'])
        if 'resource_id' in kwargs: