# file eulfedora/xml.py
#
#   Copyright 2010,2011 Emory University Libraries
#
#   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.

from __future__ import unicode_literals
from eulxml import xmlmap
from eulxml.xmlmap.fields import Field, SingleNodeManager, NodeMapper, \
                                 DateTimeField

from eulfedora.util import datetime_to_fedoratime, fedoratime_to_datetime

class FedoraDateMapper(xmlmap.fields.DateTimeMapper):
    def to_python(self, node):
        rep = self.XPATH(node)
        return fedoratime_to_datetime(rep)

    def to_xml(self, dt):
        return datetime_to_fedoratime(dt)

class FedoraDateField(xmlmap.fields.Field):
    """Map an XPath expression to a single Python `datetime.datetime`.
    Assumes date-time format in use by Fedora, e.g. 2010-05-20T18:42:52.766Z
    """
    def __init__(self, xpath):
        super(FedoraDateField, self).__init__(xpath,
                manager = xmlmap.fields.SingleNodeManager(),
                mapper = FedoraDateMapper())

class FedoraDateListField(xmlmap.fields.Field):
    """Map an XPath expression to a list of Python `datetime.datetime`.
    Assumes date-time format in use by Fedora, e.g. 2010-05-20T18:42:52.766Z.
    If the XPath expression evaluates to an empty NodeList, evaluates to
    an empty list."""

    def __init__(self, xpath):
        super(FedoraDateListField, self).__init__(xpath,
                manager = xmlmap.fields.NodeListManager(),
                mapper = FedoraDateMapper())


# xml objects to wrap around xml returns from fedora

FEDORA_MANAGE_NS = 'http://www.fedora.info/definitions/1/0/management/'
FEDORA_ACCESS_NS = 'http://www.fedora.info/definitions/1/0/access/'
FEDORA_DATASTREAM_NS = 'info:fedora/fedora-system:def/dsCompositeModel#'
FEDORA_TYPES_NS = 'http://www.fedora.info/definitions/1/0/types/'
FEDORA_AUDIT_NS = 'info:fedora/fedora-system:def/audit#'


class _FedoraBase(xmlmap.XmlObject):
    '''Common Fedora REST API namespace declarations.'''
    ROOT_NAMESPACES = {
        'm' : FEDORA_MANAGE_NS,
        'a' : FEDORA_ACCESS_NS,
        'ds': FEDORA_DATASTREAM_NS,
        't': FEDORA_TYPES_NS,
        'audit': FEDORA_AUDIT_NS
    }

class ObjectDatastream(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for a single datastream as returned
        by :meth:`REST_API.listDatastreams` """
    ROOT_NAME = 'datastream'
    dsid = xmlmap.StringField('@dsid')
    "datastream id - `@dsid`"
    label = xmlmap.StringField('@label')
    "datastream label - `@label`"
    mimeType = xmlmap.StringField('@mimeType')
    "datastream mime type - `@mimeType`"

class ObjectDatastreams(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for the list of a single object's
        datastreams, as returned by  :meth:`REST_API.listDatastreams`"""
    # listDatastreams result default namespace is fedora access
    ROOT_NAME = 'objectDatastreams'
    pid = xmlmap.StringField('@pid')
    "object pid - `@pid`"
    datastreams = xmlmap.NodeListField('a:datastream', ObjectDatastream)
    "list of :class:`ObjectDatastream`"

class ObjectProfile(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for object profile information
        returned by :meth:`REST_API.getObjectProfile`."""
    # objectProfile result default namespace is fedora access
    ROOT_NAME = 'objectProfile'
    label = xmlmap.StringField('a:objLabel')
    "object label"
    owner = xmlmap.StringField('a:objOwnerId')
    "object owner"
    created = FedoraDateField('a:objCreateDate')
    "date the object was created"
    modified = FedoraDateField('a:objLastModDate')
    "date the object was last modified"
    # do we care about these? probably not useful in this context...
    # - disseminator index view url
    # - object item index view url
    state = xmlmap.StringField('a:objState')
    "object state (A/I/D - Active, Inactive, Deleted)"

class ObjectHistory(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for object history information
        returned by :meth:`REST_API.getObjectHistory`."""
    # objectHistory result default namespace is fedora access
    ROOT_NAME = 'fedoraObjectHistory'
    pid = xmlmap.StringField('@pid')
    changed = FedoraDateListField('a:objectChangeDate')

class ObjectMethodService(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for object method services; included
    in :class:`ObjectMethods` for data returned by  :meth:`REST_API.listMethods`."""
    # default namespace is fedora access
    ROOT_NAME = 'sDef'
    pid = xmlmap.StringField('@pid')
    methods = xmlmap.StringListField('a:method/@name')

class ObjectMethods(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for object method information
    returned by  :meth:`REST_API.listMethods`."""
    # default namespace is fedora access
    ROOT_NAME = 'objectMethods'
    service_definitions = xmlmap.NodeListField('a:sDef', ObjectMethodService)

class DatastreamProfile(_FedoraBase):
    """:class:`~eulxml.xmlmap.XmlObject` for datastream profile information
    returned by  :meth:`REST_API.getDatastream`."""
    # default namespace is fedora manage
    ROOT_NAME = 'datastreamProfile'
    label = xmlmap.StringField('m:dsLabel')
    "datastream label"
    version_id = xmlmap.StringField('m:dsVersionID')
    "current datastream version id"
    created = FedoraDateField('m:dsCreateDate')