"""What does mu mean?

Nothing
"""

import os, types, urllib, cgi, cStringIO, sys, tempfile, Cookie
import mimetypes, time, traceback

from datetime import datetime

HTTP_TIME = '%a, %d %b %Y %H:%M:%S GMT'


def http_time(timestamp):
    return datetime.utcfromtimestamp(timestamp).strftime(HTTP_TIME)


class xml(object):
    """An object which contains only xml bytes.
    """
    def __init__(self, string):
        self.string = string


####################
####################
## Argument Converters
####################
####################


def arguments(*args):
    """A Decorator which you wrap around a function or a method to indicate
    which magical objects you want passed to your functions which are
    embedded in a Resource's template.

    The magical values you can pass are:
        REQUEST
        SITE
        RESOURCE
        METHOD
        URI

    For example, to pass a function the SiteMap instance, do this:

        @arguments(SITE)
        def foo(site):
            print "The site!"

    The values which you pass a string argument to get variables out of the
    request environment (which also take a default) are:

        QUERY
        QUERIES
        ARG
        ARGS
        COOKIE
        HEADER

    For example, to pass a query parameter to a function, with a default
    if the parameter is not present, do this:

        @arguments(QUERY('foo', 'default'))
        def foo(foo):
            print foo

    All the magic objects which take string values have a __getattr__
    implementation for syntatic convenience when you do not need to
    pass a default value (None will be used as the default value):

        @arguments(QUERY.foo)
        def foo(foo):
            print foo
    """
    def decorate(func):
        func.arguments = args
        return func
    return decorate


def rarguments(return_converter, *args):
    def decorate(func):
        func.returnConverter = return_converter
        func.arguments = args
        return func
    return decorate


class REQUEST(object):
    """The Request object representing the current web request.
    """


class SITE(object):
    """The SiteMap object in which the resource which is currently being
    rendered resides.
    """


class RESOURCE(object):
    """The currently-being-rendered resource.
    """


class METHOD(object):
    """The method of the current request.
    """


class URI(object):
    """The URI of the current request.
    """


class Thing(object):
    """A lazy thing. Lazy things have a name and a default
    value, and are looked up lazily from the request environment.
    """
    def __init__(self, name, default=None):
        self.name = name
        self.default = default

    def __getattr__(self, name):
        if name.startswith('_'):
            raise AttributeError, name
        return type(self)(name)

    def __call__(self, name, default=None):
        return type(self)(name, default)


class QUERY(Thing):
    """A query argument (url parameter)
    """


class QUERIES(Thing):
    """Produce a generator of all query arguments with the given name
    """


class ARG(Thing):
    """A form post variable.
    """


class ARGS(Thing):
    """All form post variables with the given name.
    """


class COOKIE(Thing):
    """A cookie with the given name.
    """


class HEADER(Thing):
    """A header with the given name.
    """


def getQueries(request, arg):
    queries = tuple(request.get_query(arg.name))
    if not queries:
        return arg.default
    return queries


def getQuery(request, arg):
    queries = getQueries(request, arg)
    if queries == arg.default:
        return arg.default
    return queries[0]


def getArgs(request, arg):
    val = request.get_arg_list(arg.name)
    if not val:
        return arg.default
    return val


def getCookie(request, arg):
    """get a cookie woot.
    """
    if not hasattr(request, '_simple_cookie'):
        cookie = request.get_header('Cookie')
        if not cookie:
            return arg.default
        c = Cookie.SimpleCookie()
        c.load(cookie)
        request._simple_cookie = c
    cook_value = request._simple_cookie.get(arg.name)
    if cook_value and cook_value.value:
        return cook_value.value
    return arg.default


## Argument converters are passed to the "arguments" decorator.
## Immediately before the decorated function is called, they are invoked.
## They are passed information about the current request
## and they should return the lazy value they represent.
argumentConverters = {
    REQUEST: lambda request, arg: request,
    SITE: lambda request, arg: request.site,
    RESOURCE: lambda request, arg: request.resource,
    METHOD: lambda request, arg: request.method(),
    URI: lambda request, arg: request.uri(),
    QUERY: getQuery,
    QUERIES: getQueries,
    ARG: lambda request, arg: request.get_arg(arg.name, arg.default),
    ARGS: getArgs,
    COOKIE: getCookie,
    HEADER: lambda request, arg: request.get_header(arg.name, arg.default),
}


def registerArgumentConverter(argType, converter):
    argumentConverters[argType] = converter


## These things are all prototype objects; they have __getattr__
## and __call__ factories which are used for generating clones
## of them. The lines below make the names that people use
## into instances instead of classes.
REQUEST = REQUEST()
SITE = SITE()
RESOURCE = RESOURCE()
METHOD = METHOD()
URI = URI()
QUERY = QUERY('')
QUERIES = QUERIES('')
ARG = ARG('')
ARGS = ARGS('')
COOKIE = COOKIE('')
HEADER = HEADER('')


####################
####################
## End Argument Converters
####################
####################


####################
####################
## Rendering Converters
####################
####################


## Rendering converters
## When objects are placed into a DOM which is rendered to be
## sent to the client as HTML, they are run through a series
## of rendering converters until nothing but a single "xml"
## instance is left.


def convertFunction(request, function):
    args = []
    for arg in getattr(function, 'arguments', ()):
        converter = argumentConverters.get(type(arg))
        if converter is None:
            args.append(arg)
        else:
            args.append(converter(request, arg))

    result = function(*args)

    converter = getattr(function, 'returnConverter', None)
    if converter is not None:
        result = converter(result)

    return result


convertSequence = lambda request, sequence: xml(
    ''.join([request.convert(request, x) for x in sequence]))


convertNumber = lambda request, number: xml(str(number))


class show(object):
    """A marker which will lazily look up a show_* method
    from the currently-being-rendered resource when encountered
    in a template.
    """
    def __init__(self, name, args=()):
        self.name = name
        self.args = args

    def __getattr__(self, name):
        if name.startswith('_'):
            raise AttributeError, name
        return type(self)(name)

    def __call__(self, *args):
        return type(self)(self.name, self.args + args)

    def __iter__(self):
        return iter(())

    def clone(self):
        return type(self)(self.name, self.args)

    def __repr__(self):
        return "show(%r, %r)" % (self.name, self.args)


def convertShow(request, theDirective):
    def convert(resource, *args):
        rv = getattr(resource, "show_%s" % (theDirective.name, ))
        rv.im_func.arguments = args
        return rv
    return arguments(RESOURCE, *theDirective.args)(convert)


class slot(object):
    """A marker which will be removed in rendering unless it
    is filled by calling stan.fill(name, value), in which case
    value will be rendered in it's place.
    """
    def __init__(self, name):
        self.slot = name
        self.show = ''

    def __getattr__(self, name):
        if name.startswith('_'):
            raise AttributeError, name
        return type(self)(name)

    def __iter__(self):
        return iter(())

    def clone(self):
        return type(self)(self.slot)

    def __repr__(self):
        return "slot(%r, %r)" % (self.slot, self.show)


def find(someStan, targetPattern):
    """Find a node marked with the given pattern, "targetPattern",
    in a DOM object, "someStan"
    """
    if isinstance(
        someStan, type(pattern)) and someStan.pattern == targetPattern:
        return type(pattern)('', clone_children(someStan.children))
    for child in getattr(someStan, 'children', ()):
        result = find(child, targetPattern)
        if result is not None:
            return result


def rfill(s, **kw):
    if isinstance(s, type(pattern)): return ''
    slot = getattr(s, 'slot', None)
    if slot in kw and not s.show:
        s.show = kw[slot]
    else:
        for child in (getattr(s, 'children', ())):
            rfill(child, **kw)


def fill(s, **kw):
    children = clone_children(s.children)
    for child in children:
        rfill(child, **kw)
    return type(pattern)('', children)


class pattern(object):
    """A marker which lets you find this branch of the tree
    again later.
    """
    def __init__(self, name, children=()):
        self.pattern = name
        if name:
            self.show = ''
        self.children = children

    def __getattr__(self, name):
        if name.startswith('_'):
            raise AttributeError, name
        return type(self)(name)

    def __getitem__(self, args):
        if not isinstance(args, (tuple, list)):
            args = (args, )
        return type(self)(
            self.pattern, [x for x in self.children] + list(args))

    def clone(self):
        return type(self)(
            self.pattern, clone_children(self.children))

    fill = fill
    find = find

    def __repr__(self):
        return "pattern(%r, %r)" % (
            self.pattern, self.children)


def convertPattern(request, pattern):
    ## Pattern originals left in the template are elided
    if pattern.pattern:
        return nothing
    return pattern.children


class attr(object):
    def __init__(self, name, children):
        self.name = name
        self.children = children

    def clone(self):
        if isinstance(self.children, basestring):
            children = self.children
        else:
            children = clone_children(self.children)
        return type(self)(self.name, children)

    def __repr__(self):
        return "attr(%r, %r)" % (
            self.name, self.children)


def clone_children(children):
    new_children = []
    for child in children:
        if hasattr(child, 'clone'):
            new_children.append(child.clone())
        elif isinstance(child, (list, tuple)):
            new_children.append(clone_children(child))
        else:
            new_children.append(child)
    return new_children


class stan(object):
    def __init__(
        self, tag, children, clone=False):
        (self.tag, self.children, self.clone_me) = (
            tag, children, clone)

    def __getitem__(self, args):
        """Add child nodes to this tag.
        """
        if not isinstance(args, (tuple, list)):
            args = (args, )

        if self.clone_me:
            return type(self)(
                self.tag, clone_children(self.children) + list(args), False)

        self.children.extend(args)
        return self

    def __call__(self, **kw):
        """Set attributes of this tag. There are two special names
        which are reserved:

            pattern
                Make it possible to find this node later using the
                findPattern function

            show
                When this node is rendered, instead render the
                value passed as the "show" value.
        """
        if self.clone_me:
            attrs = [
                attr(k, v)
                for (k, v) in kw.items()]

            children = clone_children(self.children)

            return type(self)(
                self.tag, attrs + children, False)

        for (k, v) in kw.items():
            self.children.insert(0, attr(k, v))
        return self

    def clone(self):
        return type(self)(
            self.tag, clone_children(self.children), True)

    def __repr__(self):
        return "stan(%r, %r, clone=%r)" % (
            self.tag, self.children, self.clone_me)

    find = find


class cdata(object):
    def __init__(self, data):
        self.data = data


def convertCdata(request, cdata):
    return xml('<![CDATA[%s]]>' % (cdata.data, ))


def tagFactory(tagName):
    return stan(tagName, [], True)


## TODO: Inline elements shouldn't have any whitespace after them or before
## the closing tag.


def convertStan(request, theStan):
    ## XXX this probably isn't necessary
    request.tag = theStan

    attrs = ''
    numattrs = 0
    for att in theStan.children:
        if not isinstance(att, attr):
            break
        numattrs += 1
        name = att.name
        if name.startswith('_'):
            name = name[1:]
        attrs += ' %s="%s"' % (
            name, request.convert(
                request, att.children).replace('"', '&quot;'))

    depth = getattr(request, 'depth', 0)
    indent = '  ' * depth
    request.depth = depth + 1
    if (theStan.tag in singleton_elements and not [
        x for x in theStan.children[numattrs:] if x]
    ):
        template = """<%(tag)s%(attrs)s />"""
    elif theStan.tag in inline_elements:
        template = """<%(tag)s%(attrs)s>%(children)s</%(tag)s>"""
    else:
        template = """
%(indent)s<%(tag)s%(attrs)s>
%(indent)s  %(children)s
%(indent)s</%(tag)s>
"""
    result = template % dict(
        indent=indent, tag=theStan.tag, attrs=attrs,
        children=request.convert(
            request, theStan.children[numattrs:]).strip())

    request.depth -= 1
    return xml(result)


inline_elements = [
    'a', 'abbr', 'acronym', 'b', 'basefont', 'bdo', 'big', 'br', 'cite',
    'code', 'dfn', 'em', 'font', 'i', 'img', 'input', 'kbd', 'label',
    'q', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong',
    'sub', 'sup', 'textarea', 'tt', 'u', 'var', 'pre']
inline_elements = dict([(x, True) for x in inline_elements])


singleton_elements = {}


tags_to_create = [
'a','abbr','acronym','address','applet','area','b','base','basefont','bdo',
'big','blockquote','body','br','button','caption','center','cite','code',
'col','colgroup','dd','dfn','div','dl','dt','em','fieldset','font','form',
'frame','frameset','h1','h2','h3','h4','h5','h6','head','hr','html','i',
'iframe','img','input','ins','isindex','kbd','label','legend','li','link',
'menu','meta','noframes','noscript','ol','optgroup','option','p','param',
'pre','q','s','samp','script','select','small','span','strike','strong',
'style','sub','sup','table','tbody','td','textarea','tfoot','th','thead',
'title','tr','tt','u','ul','var'
]


class tags(object):
    """A namespace for tags, so one can say "from ultramini import tags"
    and have access to all tags as tags.html, tags.foo, etc
    """
    pass


for tag in tags_to_create:
    T = tagFactory(tag)
    globals()[tag] = T
    setattr(tags, tag, T)
del tag
del T
del tags_to_create


nothing = xml('')


converters = {
    type(None): lambda request, n: xml('None'),
    unicode: lambda request, uni: uni.encode('utf8'),
    list: convertSequence,
    tuple: convertSequence,
    types.GeneratorType: convertSequence,
    types.FunctionType: convertFunction,
    types.MethodType: convertFunction,
    types.UnboundMethodType: convertFunction,
    int: convertNumber,
    float: convertNumber,
    long: convertNumber,
    show: convertShow,
    stan: convertStan,
    slot: lambda request, slot: slot.show,
    pattern: convertPattern,
    cdata: convertCdata,
    str: lambda request, string: xml(
        string.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"))
}
converters.update(argumentConverters)


show = show('')
slot = slot('')
pattern = pattern('')

def registerConverter(convertType, converter):
    """Call this to register a converter for one of your custom types.
    """
    converters[convertType] = converter


def convert(request, stuff):
    """Recursively apply stuff converters until we get an xml instance.
    """
    while not isinstance(stuff, xml):
        for cls in getattr(stuff, '__mro__', (type(stuff), )):
            convert = converters.get(cls)
            if convert is not None:
                stuff = convert(request, stuff)
                break
        else:
            raise RuntimeError, "Converter for type %r (%r) not found." % (
                type(stuff), stuff)

    return stuff.string


####################
####################
## End Rendering Converters
####################
####################



####################
####################
## Incoming Type Converters
####################
####################


## When arguments come in (as GET url parameters or POST arguments)
## they can be converted from strings to Python types using incoming
## type converters. To use them, wrap a get_* or post_* method
## using the annotate decorator. When a get_ or post_ method
## is called (by having a corresponding ?get= parameter or action
## argument) the arguments named in the decorator will be converted
## before they are passed to the method.


def rannotate(returnConverter, **kw):
    """annotate with a return value converter
    """
    def decorate(method):
        method.returnConverter = returnConverter
        method.types = kw
        return method
    return decorate


def annotate(**kw):
    """A decorator which annotates the types of arguments an action
    method will receive. Used by 'get' and 'post' methods; for
    example, to expose a method to be called by placing ?get=foo
    in the query string with a single parameter bar of type int:

    @annotate(bar=int)
    def get_foo(self, bar):
        print bar

    To expose a method to a POST with an action argument and a
    bar argument of type int:

    @annotate(bar=int)
    def post_foo(self, bar):
        print bar

    To express lists of things:
    @annotate(bar=[int])
    def post_foo(self, bar):
        for someInt in bar:
            print someInt

    TODO: Dicts of things should be expressed by presenting
    arguments with a common prefix separated by a dot. For
    example:

    ?get=foo&someDict.bar=1&someDict.baz=foo

    Would call:

    @annotate(someDict={bar: int, baz: str})
    def get_foo(self, someDict):
        print someDict['bar']
        print someDict['baz']

    This is still TODO. (Perhaps colon instead of dot?)
    """
    def decorate(method):
        method.returnConverter = None
        method.types = kw
        return method
    return decorate


def convertList(request, theList):
    request.target = request.target[0]
    if not isinstance(theList, list):
        theList = [theList]
    return [convertTypes(request, item) for item in theList]


def convertTuple(request, theTuple):
    stuff = []
    for i, subtype in enumerate(request.target):
        request.target = subtype
        stuff.append(convertTypes(request, theTuple[i]))
    return tuple(stuff)


def convertDict(request, nothing):
    theDict = {}
    for field in request.get_field_storage().list:
        if field.name.startswith(request.target_name + '.'):
            theDict[field.name.split('.', 1)[-1]] = field.value
    target = request.target
    result = {}
    for (key, value) in target.items():
        request.target = value
        result[key] = convertTypes(request, theDict[key])
    return result


typeConverters = converters.copy()
typeConverters.update({
    int: lambda target, value: int(value),
    float: lambda target, value: float(value),
    list: convertList,
    tuple: convertTuple,
    dict: convertDict,
    str: lambda target, value: value,
    unicode: lambda target, value: value.decode('utf8'),
    types.FunctionType: lambda request, value: request.target(request, value),
})


def registerTypeConverter(convertType, converter):
    typeConverters[convertType] = converter


def convertTypes(request, value):
    target = request.target
    converter = typeConverters.get(type(target))
    if converter is None:
        converter = typeConverters.get(target)
    if converter is None:
        raise ValueError, "No converter for type %s (%s)" % (target, value)
    return converter(request, value)


def applyWithTypeConversion(callable_method, request):
    types = getattr(callable_method, 'types', {})
    try:
        converted = {}
        fs = request.get_field_storage()
        for (key, value) in types.items():
            request.target_name = key
            request.target = value
            if fs.has_key(key):
                val = fs[key]
                if isinstance(val, list):
                    val = [v.value for v in val]
                else:
                    val = val.value
                converted[key] = convertTypes(request, val)
            else:
                try:
                    converted[key] = convertTypes(
                        request, getattr(value, 'default', None))
                except (TypeError, ValueError):
                    converted[key] = getattr(value, 'default', None)

        result = callable_method(**converted)
    except TypeError:
        print "Error calling action method", callable_method
        raise
    if result is None:
        result = ''
    returnConverter = getattr(callable_method, 'returnConverter', None)
    if returnConverter:
        result = returnConverter(result)
    return result


####################
####################
## End Incoming Converters
####################
####################


####################
####################
## Resource Converers
####################
####################

resourceConverters = {
    str: lambda s: File(s)
}


def registerResourceConverter(t, c):
    resourceConverters[t] = c


####################
####################
## End Resource Converers
####################
####################


####################
####################
## URL Traversal
####################
####################


## SiteMap has a root Resource and traverses the URL using the Resource
## interface.


class SiteMap(object):
    """An object which is capable of matching Resource objects to URLs and
    delegating rendering responsibility to the matched object.

    This class implements the corohttpd handler interface: match
    and handle_request. It adapts this interface to something more similar
    to the Nevow URL traversal interface: findChild and handle (like
    locateChild and renderHTTP in Nevow).
    """
    def __init__(self, root, cache=False):
        self.resources = {}
        self.root = root
        root.child_ = root
        self.cache = cache

    def handle_request(self, request): 
        request.convert = convert
        try:
            self._really_handle_request(request)
        except:
            request.protocol.server.log_exception(*sys.exc_info())
            ## Relative import
            import htmlexception
            request.response(500)
            request.write(tags.html[tags.body[htmlexception.formatException()]])
        del request.convert

    def _really_handle_request(self, request):
        request.site = self
        remaining = tuple([urllib.unquote_plus(x) for x in request._path.split('/')[1:]])
        ## Cache fastpath
        if remaining in self.resources:
            request.resource = self.resources[remaining]
            request.segments = remaining
            return True

        child = self.root

        while child is not None and remaining:
            child, handled, remaining = child.findChild(request, remaining)
            if type(child) in resourceConverters:
                child = resourceConverters[type(child)](child)

        if child is None:
            request.response(404)
            request.write('Not Found')
        else:
            ## Allow resources to delegate to someone else,
            ## even if they have been selected as the target of rendering
            newChild = child.willHandle(request)
            if newChild is not child:
                child = newChild
            request.segments = handled
            request.resource = child
            resource = request.resource
            resource.handle(request)
            if self.cache and resource.cache:
                self.resources[request.segments] = request.resource
            request.resource = None


class Resource(object):
    cache = True
    debug = False
    contentType = 'text/html'
    template = "Resources must provide a template attribute."

    def __call__(self, request, name):
        return self

    def willHandle(self, request):
        """This Resource is about to handle a request.
        If it wants to delegate to another Resource, it can return it here.
        """
        return self

    def findChild(self, request, segments):
        """External URL segment traversal API. This method MUST always
        return a tuple of:

            (child, handled, remaining)

        child may be None to indicate a 404. Handled should be a tuple
        of URL segments which were handled by this call to findChild;
        remaining should be a tuple of URL segments which were not
        handled by this call to findChild.

        findChild can be overriden to implement fancy URL traversal
        mechanisms such as handling multiple segments in one call,
        doing an internal server-side redirect to another resource and
        passing it segments to handle, or delegating this segment
        to another resource entirely. However, for most common use
        cases, you will not override findChild.

        Any methods or attributes named child_* will be mapped to
        URL segments. For example, if an instance of Root is set
        as the root object, the urls "/foo" and "/bar" will be valid:

        class Root(Resource):
            child_foo = Resource()

            def child_bar(self, request, bar):
                return Resource()

        Finally, if a childFactory method is defined it will be called
        with a single URL segment:

        class Root(Resource):
            def childFactory(self, request, childName):
                ## For URL "/foo" childName will be "foo"
                return Resource()
        """
        ## Refresh our code
        selfType = type(self)
        if self.debug and selfType.__module__ != '__main__':
            self.__class__ = getattr(
                reload(sys.modules[selfType.__module__]), selfType.__name__)

        current, remaining = segments[0], segments[1:]
        childFactory = getattr(self, 'child_%s' % (current, ), self.childFactory)
        if type(childFactory) in resourceConverters:
            childFactory = resourceConverters[type(childFactory)](childFactory)
        return childFactory(request, current), (current, ), remaining

    def childFactory(self, request, childName):
        """Override this to produce instances of Resource to represent the next
        url segment below self. The next segment is provided in childName.
        """
        return None

    def handle(self, request):
        ## Refresh our code
        selfType = type(self)
        if self.debug and selfType.__module__ != '__main__':
            self.__class__ = getattr(
                reload(sys.modules[selfType.__module__]), selfType.__name__)

        ## Handle the request
        request['Content-Type'] = self.contentType
        handler = getattr(
            self, "handle_%s" % (request.method(), ), self.handle_default)
        handler(request)

    def handle_default(self, request):
        request.push(
            "<html><body>No handler for method %r present.</body></html>" %
            (request.method(), ))

    def handle_get(self, request):
        get_method = self.getAction('get', request.get_field_storage())
        if get_method is None:
            request.write(self.template)
        else:
            result = applyWithTypeConversion(get_method, request)
            request.write(result)

    def getFieldStorage(self, request, data, headers, environ):
        """Given a file-like object, data, a dict of headers, and an environ dict,
        return an instance of cgi.FieldStorage or something which acts quite like
        one. This is provided as a hook for subclasses to override if they want
        to parse the incoming POST data differently than a basic FieldStorage
        does. For example, imgsrv/server overrides this to trick FieldStorage
        into saving binary parts directly into the image file directory, to avoid
        having to copy the file from a temporary file into the final location.
        """
        return cgi.FieldStorage(data, headers, environ=environ)

    def getAction(self, key, fs):
        if isinstance(fs, dict):
            value = dict.get(key, 'default')
        else:
            try:
                value = fs.getfirst(key, 'default')
            except TypeError:
                value = 'default'
        return getattr(self, '%s_%s' % (key, value), None)

    def handle_post(self, request):
        fs = request.get_field_storage()
        post_method = self.getAction('post', fs)
        if post_method is None:
            url = self.post(request, fs)
        else:
            url = applyWithTypeConversion(post_method, request)

        if url is not None:
            request['Location'] = request.convert(request, url)
            request.response(303)
            request.write('')
            return
        request.write(self.template)

    def post(self, request, form):
        """post

        Override this to handle a form post.
        Return a URL to be redirected to.

        request: An HttpRequest instance representing the place the form
                  was posted to.
        form: A cgi.FieldStorage instance representing the posted form.
        """
        return request.uri()


class MovedPermanently(Resource):
    cache = False
    def __init__(self, location):
        self.location = location

    def get_default(self, req):
        req.set_header(
            'Location',
            self.location)
        req.response(301) # Moved Permanently
        return self.location
    get_default = annotate(req=REQUEST)(get_default)


class Directory(Resource):
    def __init__(self, path):
        self.path = path

    def findChild(self, req, segments):
        full_path = os.path.join(*(self.path, ) + segments)
        if os.path.exists(full_path):
            return (
                File(full_path, mimetypes.guess_type(full_path)),
                segments, ())
        return (None, (), segments)


class File(Resource):
    def __init__(self, path, content_type='text/html'):
        self.path = path
        self.content_type = content_type

    def get_default(self, req):
        f = file(self.path, 'rb')
        finfo = os.stat(self.path)
        req.set_header('Content-Type', self.content_type)
        modtime = http_time(finfo.st_mtime)
        req.set_header('Last-Modified', modtime)

#        if req.get_header('If-Modified-Since') == modtime:
#            req.response(304)
#            req.push('')

        req.set_header('Content-Length', str(finfo.st_size))
        return xml(f.read())

        block = f.read(32*1024)
        if not block:
            req.send_error(204)
        else:
            while True:
                req.write_chunked(xml(block))
                block = f.read(32*1024)
                if not block:
                    break
    get_default = annotate(req=REQUEST)(get_default)


class Data(Resource):
    def __init__(self, data, content_type='text/html'):
        self.data = data
        self.content_type = content_type

    def get_default(self, req):
        req.set_header('Content-Type', self.content_type)
        req.set_header('Content-Length', len(self.data))
        req.write(self.data)
    get_default = annotate(req=REQUEST)(get_default)

