#!/usr/bin/env python

# If you're implemeting restful interfaces, read and comprehend:
# http://www.prescod.net/rest/mistakes/

import sys
import cherrypy
from httplib import OK, CREATED, FOUND, NO_CONTENT, METHOD_NOT_ALLOWED, RESET_CONTENT


status_map = {
    OK:'%s OK' % OK,
    CREATED:'%s Created' % CREATED,
    NO_CONTENT:'%s No Content' % NO_CONTENT,
    METHOD_NOT_ALLOWED:'%s Method Not Allowed' % METHOD_NOT_ALLOWED,
    RESET_CONTENT:'%s Reset Content' % RESET_CONTENT
    }

status_good = (OK, CREATED, FOUND, )


class RestfulFilter:
    def before_main(self):
        if not cherrypy.config.get('restful_filter.on'):
            return

        request = cherrypy.request
        handler, obj_path, virtual_path = request.mapPathToObject(request.object_path)
        method_name = request.method.lower()
        method = getattr(handler.im_self, method_name, None)
        exposed = getattr(method, 'exposed', False)
        
        if method is None or not exposed or not callable(method):
            raise cherrypy.HTTPError(status_map[METHOD_NOT_ALLOWED])

        obj_path = obj_path[1:-1]
        obj_path.append(method_name)
        request.object_path = str.join('/', obj_path)


    def before_finalize(self):
        if not cherrypy.config.get('restful_filter.on'):
            return

        method_name = cherrypy.request.method.lower()
        status = cherrypy.response.status
        status_okay = status in status_good

        if method_name == 'put' and status_okay:
            ## respond to successful PUT with CREATED
            cherrypy.response.status = status_map[CREATED]
        elif method_name == 'delete' and status_okay:
            ## respond to succesful DELETE with RESET
            cherrypy.response.status = status_map[RESET_CONTENT]
        ## etc.
        

class Test:
    ## we use this method to associate filters with handlers because it's much
    ## more simple to control which handlers get restful.
    _cp_filters = [RestfulFilter(), ]

    @cherrypy.expose()
    def index(self):
        return '''
        <html>
        <form action='/test/' method='POST'>
        <input type='text' name='foo' /><br />
        <input type='text' name='bar' /><br />
        <input type='submit' />
        </form>
        </html>
        '''
    get = index

    @cherrypy.expose()
    def post(self, foo, bar):
        return '''
        <html>POST foo="%s", bar="%s" to resource "%s"</html>
        ''' % (foo, bar, cherrypy.request.path)

    @cherrypy.expose()
    def put(self):
        return '''
        <html>PUT content %s to resource "%s"</html>
        ''' % ('', cherrypy.request.path, )

    @cherrypy.expose()
    def delete(self):
        return '''
        <html>DELETE resource "%s"</html>
        ''' % (cherrypy.request.path, )


class Root:
    @cherrypy.expose()
    def index(self):
        return '''<html>The resource you want <a href="/test">is here</a>.</html>'''

cherrypy.config.update({
    'restful_filter.on' : True,
    })


cherrypy.root = Root()
cherrypy.root.test = Test()
cherrypy.server.start()
