"""Somewhat Looser ISO date format YYYY-MM-DD HH:mm:SS +HH:mm

    ISO_date_loose -- YYYY-MM-DD format, with a month and day optional,
        month or day may be specified without leading 0
    ISO_time_loose -- HH:mm:SS format, with minutes and seconds optional
        all numbers may be specified without leading 0
    ISO_date_time_loose -- YYYY-MM-DD HH:mm:SS +HH:mm format,
        with time optional and TimeZone offset optional,
        same format for date and time as above

Interpreter:
    MxInterpreter
        Interprets the parse tree as mx.DateTime values
        Date and DateTime -> DateTime objects
        Time only -> RelativeDateTime
"""
try:
    from mx import DateTime
    haveMX = 1
except ImportError:
    haveMX = 0
from simpleparse.parser import Parser
from simpleparse import common, objectgenerator
from simpleparse.common import chartypes, numbers
from simpleparse.dispatchprocessor import *

c = {}
declaration = """
<date_separator> := [-]
<time_separator> := ':'
offset_sign := [-+]

year    := int
month   := int
day     := int
hour    := int
minute  := int
second  := float/int
ISO_date_loose := year, (date_separator, month, (date_separator, day)?)?
ISO_time_loose := hour, (time_separator, minute, (time_separator, second)?)?
offset    := offset_sign, offset_hour, time_separator?, offset_minute?
offset_hour := digit, digit
offset_minute := digit, digit

ISO_date_time_loose  := ISO_date_loose, ([T ], ISO_time_loose)?, [ ]?, offset?
"""

_p = Parser( declaration )
for name in ["ISO_time_loose","ISO_date_time_loose", "ISO_date_loose"]:
    c[ name ] = objectgenerator.LibraryElement(
        generator = _p._generator,
        production = name,
    )
common.share( c )

if haveMX:
    class MxInterpreter(DispatchProcessor):
        """Interpret a parsed ISO_date_time_loose in GMT/UTC time or localtime
        """
        int = numbers.IntInterpreter()
        offset_minute = offset_hour = year = month = day = hour = minute = int

        float = numbers.FloatInterpreter()
        second =  float
        
        def __init__(
            self,
            inputLocal = 1,
            returnLocal = 1,
        ):
            self.inputLocal = inputLocal
            self.returnLocal = returnLocal
        dateName = 'ISO_date_loose'
        timeName = 'ISO_time_loose'
        def ISO_date_time_loose( self, info, buffer):
            """Interpret the loose ISO date + time format"""
            (tag, left, right, sublist) = info
            set = singleMap( sublist, self, buffer )
            base, time, offset = (
                set.get(self.dateName),
                set.get(self.timeName) or DateTime.RelativeDateTime(hour=0,minute=0,second=0),
                set.get( "offset" ),
            )
            base = base + time
            offset = set.get( "offset" )
            if offset is not None:
                # an explicit timezone was entered, convert to gmt and return as appropriate...
                gmt = base - offset
                if self.returnLocal:
                    return gmt.localtime()
                else:
                    return gmt
            # was in the default input locale (either gmt or local)
            if self.inputLocal and self.returnLocal:
                return base
            elif not self.inputLocal and not self.returnLocal:
                return base
            elif self.inputLocal and not self.returnLocal:
                # return gmt from local...
                return base.gmtime()
            else:
                return base.localtime()
        def ISO_date_loose( self, info, buffer):
            """Interpret the loose ISO date format"""
            (tag, left, right, sublist) = info
            set = singleMap( sublist, self, buffer )
            return DateTime.DateTime(
                set.get("year") or now().year,
                set.get("month") or 1,
                set.get("day") or 1,
            )
        def ISO_time_loose( self, info, buffer):
            """Interpret the loose ISO time format"""
            (tag, left, right, sublist) = info
            set = singleMap( sublist, self, buffer )
            return DateTime.RelativeDateTime(
                hour = set.get("hour") or 0,
                minute = set.get("minute") or 0,
                second = set.get("second") or 0,
            )

        
        def offset( self, info, buffer):
            """Calculate the time zone offset as a date-time delta"""
            (tag, left, right, sublist) = info
            set = singleMap( sublist, self, buffer )
            direction = set.get('offset_sign',1)
            hour = set.get( "offset_hour", 0)
            minute = set.get( "offset_minute", 0)
            delta = DateTime.DateTimeDelta( 0, hour*direction, minute*direction)
            return delta
            
        def offset_sign( self , info, buffer):
            """Interpret the offset sign as a multiplier"""
            (tag, left, right, sublist) = info
            v = buffer [left: right]
            if v in ' +':
                return 1
            else:
                return -1
                
