###############################################################################
##                                                                           ##
##                        ALEXANDRIA DIGITAL LIBRARY                         ##
##                 University of California at Santa Barbara                 ##
##                                                                           ##
## ------------------------------------------------------------------------- ##
##                                                                           ##
##     Copyright (c) 2005 by the Regents of the University of California     ##
##                            All rights reserved                            ##
##                                                                           ##
## Redistribution and use in source and binary forms, with or without        ##
## modification, are permitted provided that the following conditions are    ##
## met:                                                                      ##
##                                                                           ##
##     1. Redistributions of source code must retain the above copyright     ##
##        notice, this list of conditions, and the following disclaimer.     ##
##                                                                           ##
##     2. Redistributions in binary form must reproduce the above copyright  ##
##        notice, this list of conditions, and the following disclaimer in   ##
##        the documentation and/or other materials provided with the         ##
##        distribution.                                                      ##
##                                                                           ##
##     3. All advertising materials mentioning features or use of this       ##
##        software must display the following acknowledgement: This product  ##
##        includes software developed by the Alexandria Digital Library,     ##
##        University of California at Santa Barbara, and its contributors.   ##
##                                                                           ##
##     4. Neither the name of the University nor the names of its            ##
##        contributors may be used to endorse or promote products derived    ##
##        from this software without specific prior written permission.      ##
##                                                                           ##
## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY ##
## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ##
## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE   ##
## DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR  ##
## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL    ##
## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   ##
## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)     ##
## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       ##
## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  ##
## ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           ##
## POSSIBILITY OF SUCH DAMAGE.                                               ##
##                                                                           ##
###############################################################################

# $Header: /export/home/gjanee/mm/bucket_types/RCS/temporal.py,v 1.1 2005/02/10 23:54:19 gjanee Exp $

# DESCRIPTION
#
#     The "temporal" bucket type.
#
# AUTHOR
#
#     Greg Janee
#     gjanee@alexandria.ucsb.edu
#
# HISTORY
#
#     $Log: temporal.py,v $
#     Revision 1.1  2005/02/10 23:54:19  gjanee
#     Initial revision
#

import re

from ADL_mapper import bucketType, fatal
from bucket_types.utils import checkValue, encodeField, fieldErrorClause

def _validate (bucket, field, value, strict):
    value = checkValue(bucket, "temporal", ["!", "!!"], field, value, strict)
    if value == None: return None
    for date in value:
        if _validateDate(bucket, field, date, strict) == None: return None
    if len(value) == 1:
        return (field, value)
    else:
        begin = value[0]
        end = value[1]
        while len(begin) < len(end): begin += "-01"
        while len(begin) > len(end):
            if len(end) == 4:
                end += "-12"
            else:
                end += "-31"
        if begin > end:
            if strict:
                fatal(("invalid value mapped to temporal bucket '%s'%s: " +\
                    "range end date precedes begin date: [%s, %s]") %\
                    (bucket, fieldErrorClause(field), begin, end))
            else:
                return None
        if begin == end:
            return (field, (begin,))
        else:
            return (field, (begin, end))

_monthLengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
_dateParser = re.compile("(\d{4})(-\d{2})?(-\d{2})?$")

def _validateDate (bucket, field, date, strict):
    match = _dateParser.match(date)
    if match:
        year = int(match.group(1))
        if match.group(2) != None:
            month = int(match.group(2)[1:])
            if month < 1 or month > 12:
                if strict:
                    fatal(("invalid value mapped to temporal bucket '%s'%s:" +\
                        " month out of range: %s") % (bucket,
                        fieldErrorClause(field), date))
                else:
                    return None
            if match.group(3) != None:
                day = int(match.group(3)[1:])
                if day < 1 or day > _monthLengths[month-1]:
                    if month == 2 and day == 29:
                        if year%4 != 0 or (year%100 == 0 and year%400 != 0):
                            if strict:
                                fatal(("invalid value mapped to temporal " +\
                                    "bucket '%s'%s: not a leap year: %s") %\
                                    (bucket, fieldErrorClause(field), date))
                            else:
                                return None
                    else:
                        if strict:
                            fatal(("invalid value mapped to temporal " +\
                                "bucket '%s'%s: day out of range: %s") %\
                                (bucket, fieldErrorClause(field), date))
                        else:
                            return None
        return date
    else:
        if strict:
            fatal(("invalid value mapped to temporal bucket '%s'%s: invalid" +\
                " date: %s") % (bucket, fieldErrorClause(field), date))
        else:
            return None

def _encode (document, field, value):
    tv = document.createElement("temporal-value")
    encodeField(document, tv, field)
    if len(value) == 1:
        d = document.createElement("date")
        d.appendChild(document.createTextNode(value[0]))
        tv.appendChild(d)
    else:
        r = document.createElement("range")
        b = document.createElement("begin")
        b.appendChild(document.createTextNode(value[0]))
        r.appendChild(b)
        e = document.createElement("end")
        e.appendChild(document.createTextNode(value[1]))
        r.appendChild(e)
        tv.appendChild(r)
    return tv

bucketType("temporal", _validate, _encode)
