# encoding: utf-8
"""
Literal.py

Created by Philip Cooper on 2008-02-09.
Copyright (c) 2008 Openvest. All rights reserved.
"""
from rdflib import (
    Namespace,
    Literal
)
from rdflib.term import bind as bindLiteral

import re
import logging

__all__ = ['Literal']

XSD = Namespace(u'http://www.w3.org/2001/XMLSchema#')

###############################################################################
# Let's fix the logging.  This seems like a lot of work...
# all that it does is not log rebinding errors.
# We know already about them ... and the warnings confuse the citizenry.
_log = logging.getLogger("rdflib")
if not _log.handlers:
    class rebindingLogFilter(logging.Filter):
        def filter(self, record):
            if record.getMessage().find("Rebinding") > -1:
                return False
            return True

    h = logging.StreamHandler()
    h.addFilter(rebindingLogFilter())
    _log.addHandler(h)

###############################################################################
## Default behavior returns untyped literals as literals
## this brings untyped literals back as unicode strings
bindLiteral(None, unicode)

###############################################################################
## Default behavior returns string literals as literals
## this brings  string literals back as unicode strings
bindLiteral(XSD.string, unicode)

###############################################################################
## Let's make toPython return a datetime if the literal has fractional seconds
## Note: dateparser adapted from http://www.mnot.net/python/isodate.py
## modified to: handle fractional seconds beyond tenths
##              and to allow pseudo iso i.e. "2001-12-15 22:43:46"
##                                        vs "2001-12-15T22:43:46"
import datetime

date_parser = re.compile(r"""^
    (?P<year>\d{4})
    (?:-
        (?P<month>\d{1,2})
        (?:-
            (?P<day>\d{1,2})
            (?:[T ]
                (?P<hour>\d{1,2})
                :
                (?P<minute>\d{1,2})
                (?::
                    (?P<second>\d{1,2})
                    (?P<dec_second>\.\d+)?
                )?
                (?:Z|(?:
                        (?P<tz_sign>[+-])
                        (?P<tz_hour>\d{1,2})
                        :?
                        (?P<tz_min>\d{2,2})
                     )
                )?
            )?
        )?
    )?
$""", re.VERBOSE)


def _strToDateTime(s):
        """ parse a string and return a datetime object. """
        assert isinstance(s, basestring)
        r = date_parser.search(s)
        try:
            a = r.groupdict('0')
        except:
            raise ValueError('invalid date string format')

        dt = datetime.datetime(int(a['year']),
                               int(a['month']) or 1,
                               int(a['day']) or 1,
                               # If not given these will default to 00:00:00.0
                               int(a['hour']),
                               int(a['minute']),
                               int(a['second']),
                               # Convert into microseconds
                               int(float(a['dec_second']) * 1000000),
                               )
        tz_hours_offset = int(a['tz_hour'])
        tz_mins_offset = int(a['tz_min'])
        if a.get('tz_sign', '+') == "-":
            return dt + datetime.timedelta(hours=tz_hours_offset,
                                           minutes=tz_mins_offset)
        else:
            return dt - datetime.timedelta(hours=tz_hours_offset,
                                           minutes=tz_mins_offset)

bindLiteral(XSD.dateTime, _strToDateTime)
