##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################

"""Commonly used utility functions."""

__version__='$Revision: 1.13 $'[11:-2]

import sys, os, time


# These are needed because the various date formats below must
# be in english per the RFCs. That means we can't use strftime,
# which is affected by different locale settings.
weekday_abbr = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
weekday_full = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
                'Friday', 'Saturday', 'Sunday']
monthname    = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']


def iso8601_date(ts=None):
    # Return an ISO 8601 formatted date string, required
    # for certain DAV properties.
    # '2000-11-10T16:21:09-08:00
    if ts is None: ts=time.time()
    return time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(ts))

def rfc850_date(ts=None):
    # Return an HTTP-date formatted date string.
    # 'Friday, 10-Nov-00 16:21:09 GMT'
    if ts is None: ts=time.time()
    year, month, day, hh, mm, ss, wd, y, z = time.gmtime(ts)
    return "%s, %02d-%3s-%2s %02d:%02d:%02d GMT" % (
            weekday_full[wd],
            day, monthname[month],
            str(year)[2:],
            hh, mm, ss)

def rfc1123_date(ts=None):
    # Return an RFC 1123 format date string, required for
    # use in HTTP Date headers per the HTTP 1.1 spec.
    # 'Fri, 10 Nov 2000 16:21:09 GMT'
    if ts is None: ts=time.time()
    year, month, day, hh, mm, ss, wd, y, z = time.gmtime(ts)
    return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (weekday_abbr[wd],
                                                    day, monthname[month],
                                                    year,
                                                    hh, mm, ss)

def absattr(attr, c=callable):
    # Return the absolute value of an attribute,
    # calling the attr if it is callable.
    if c(attr):
        return attr()
    return attr

def aq_base(ob, hasattr=hasattr):
    # Return the aq_base of an object.
    if hasattr(ob, 'aq_base'):
        return ob.aq_base
    return ob

def is_acquired(ob, hasattr=hasattr, aq_base=aq_base, absattr=absattr):
    # Return true if this object is not a direct
    # subobject of its aq_parent object.
    if not hasattr(ob, 'aq_parent'):
        return 0

    parent = aq_base(ob.aq_parent)
    absId  = absattr(ob.id)
    
    if hasattr(parent,'_objects'):
        if absId+' ' in parent.objectIds():
            return 0

    if hasattr(parent, absId):
        return 0
    if hasattr(aq_base(ob), 'isTopLevelPrincipiaApplicationObject') and \
            ob.isTopLevelPrincipiaApplicationObject:
        return 0
    return 1


def package_home(globals_dict):
    __name__=globals_dict['__name__']
    m=sys.modules[__name__]
    if hasattr(m,'__path__'):
        r=m.__path__[0]
    elif "." in __name__:
        r=sys.modules[__name__[:__name__.rfind('.')]].__path__[0]
    else:
        r=__name__
    return os.path.join(os.getcwd(), r)


def attrget(o,name,default):
    if hasattr(o,name): return getattr(o,name)
    return default

def Dictionary(**kw): return kw # Sorry Guido
    
def realpath(p):
    """ Computes the 'real' path of a file or directory devoid of
    any symlink in any element of the path """
    p = os.path.abspath(p)
    if os.name == 'posix':
        path_list = p.split(os.sep)
        orig_len = len(path_list)
        changed = 0
        i = 1
        while not changed and i <= orig_len:
            head = path_list[:i]
            tail = path_list[i:]
            head_s = os.sep.join(head)
            tail_s = os.sep.join(tail)
            if os.path.islink(head_s):
                head_s = os.path.join(os.sep.join(head[:-1]),
                                      os.readlink(head_s))
                path_list = head_s.split(os.sep)
                path_list.extend(tail)
                p = os.sep.join(path_list)
                p = realpath(p)
                changed = 1
            i = i + 1
    return p
