# Copyright (c) 2004 Infrae. All rights reserved.
# See also LICENSE.txt

from mod_python import apache

import dav

import rr_config
import rr_util

###


def get_props ( request, uri=None ):
    if uri is None:
        uri = request.uri
    master_user, master_pw, local_dir, host, path = rr_config.DB.get_upload_data(request, rr_config.repo_name)
    rr_util.ap_debug(request, 'GET PROPS: %s, %s' % (host, path))
    # connect to dav server
    dav_url = 'http://' + host + uri
    conn = dav.DAVConnection(host)
    if rr_config.do_auth:
        # if authorization is enabled, use master account
        conn.set_auth(master_user, master_pw)
    try:
        dav_file = dav.DAVFile(dav_url, conn)
    except dav.DAVNoFileError:
        # file does not exits
        # no better idea yet...
        rr_util.ap_error(request, 'get_props resource not found: %s' % uri)
        raise
    except dav.DAVError, ex:
        rr_util.ap_error(request, 'get_props DAVError: %s' % `ex`)
        raise
    px = dav_file.get_all_properties()
    props = rr_util.decode_dict(px)
##     for k, v in px.iteritems():
##         v = v.decode('utf-8')
##         props[k] = v
    return props
#

def update_properties ( request, path=None ):
    repo_name = rr_config.repo_name
    try:
        repo_id, root_user, root_pw = rr_config.repo_master[repo_name]
    except KeyError:
        # unknown repository or config error
        rr_util.ap_error(request, "update_properties: couldn't find repository %s" % repo_name)
        rr_util.ap_error(request, "   ignoring update!")
        return
    # get resource id using the path
    if path is None:
        path = request.uri
    resid, objid = rr_config.DB.get_resource_id(request, path, repo_name)
    if resid is None:
        # XXX
        # resource not found in db, what to do?
        # for now, the db is ignored
        rr_util.ap_error(request, 'Resource %s not found in db!' % path)
        rr_util.ap_error(request, "   ignoring update!")
        return
    # get new property values
    # and store them in DB
    props = get_props(request, path)
    props[(u'lastmodified', u'RR:')] = rr_util.make_utc_timestamp()
    props = rr_util.encode_dict(props)
    rr_config.DB.store_properties(resid, props)
    rr_util.call_hooks('after-property-update', request, path)
    return
#

def update ( request, uri, body ):
    method = request.method
    if method not in ('PUT', 'POST', 'PROPPATCH'):
        return
    # update props in db
    if method == 'PROPPATCH':
        # update only if all properties were set!
        # parse result...
        result = dav.DAVResult()
        result.parse_data(body)
        if not result.has_errors():
            rr_util.ap_debug(request,'Property update (PROPPATCH) on %s' % uri)
            update_properties(request)
        else:
            rr_util.ap_warn(request,
                            'Property update skipped due to error(s) in PROPPATCH')
            rr_util.ap_warn(request, '%s' % body)
    elif method in ('POST', 'PUT') and 200 <= request.status < 300:
        rr_util.ap_debug(request,'Property update (%s) on %s' %
                          (method, uri))
        update_properties(request)
    else:
        rr_util.ap_warn(request, 'Property update (%s) skipped due to status %s' %
                        (method, request.status))
    return
#

def uploaded ( request ):
    if hasattr(request, 'new_uri'):
        path = request.new_uri
        update_properties(request, path)
    return
#

def delete ( request ):
    """If a DELETE request was performed successfully,
    delete the resource from the database.

    This will also delete all properties of this resource from the db.

    This function is registered with the request-cleanup hook and
    called from there.
    """
    if request.method != 'DELETE':
        return
    # delete resource and props in db
    # when dav deletion was successful
    if 200 <= request.status < 300:
        # remove resource and properties
        path = request.uri
        repo_name = rr_config.repo_name
        resid, objid = rr_config.DB.get_resource_id(request, path, repo_name)
        if resid is None:
            # not in db, write log and ignore
            rr_util.ap_error(request, 'Resource %s not found in db!' % path)
            rr_util.ap_error(request, "   ignoring delete!")
            return
        rr_config.DB.delete_resource(resid)
    else:
        # delete wasn't successfull
        # just write a log entry
        rr_util.ap_warn(request, 'Resource delete (%s) skipped due to status %s' %
                        (method, request.status))
    return
#
###

# init code
rr_util.register_hook('outputfilter', update)
rr_util.register_hook('upload', uploaded)
rr_util.register_hook('request-cleanup', delete)
