"use strict";

var fs = require('fs'),
    path = require('path'),
    prfun = require('prfun'),
    url = require('url'),
    qs = require('querystring'),
    RouteSwitch = require('routeswitch'),
    Verbs = require('./Verbs'),
    pathToRegexp = require('path-to-regexp'),
    readdir = Promise.promisify(fs.readdir),
    http = require('http'),
    log = function (level) {
        var msg = JSON.stringify(Array.prototype.slice.call(arguments), null, 2);
        if (/^error/.test(level)) {
            console.error(msg);
        } else {
            console.log(msg);
        }
    },
    app = {};

// Load all handlers from the handlers directory
function* loadHandlers (kind) {
    var handlerNames = yield readdir('./handlers/' + kind),
        handlers = [];
    handlerNames.forEach(function(handlerName) {
        try {
            handlers.push(require(path.resolve('./handlers/'
                        + kind + '/' + handlerName)));
        } catch (e) {
            log('error/handler', e, handlerName, e.stack);
        }
    });
    return handlers;
}

function* makeRouter (kind) {
	// Load routes & handlers
    var handlers = yield* loadHandlers(kind);
    var allRoutes = [];
    handlers.forEach(function(handler) {
        handler.routes.forEach(function(route) {
            allRoutes.push({
                pattern: route.path,
                methods: route.methods
            });
        });
    });
    log('notice', kind, allRoutes);
    return new RouteSwitch(allRoutes);
}

// Optimized URL parser
function parseURL (uri) {
    // Fast path
    var fastMatch = uri.match(/^(\/[^\?]*)(\?.*)?$/);
    if (fastMatch) {
        return {
            pathname: fastMatch[1],
            query: fastMatch[2] && qs.parse(fastMatch[2]) || {}
        };
    } else {
        return url.parse(uri, true);
    }
}


// Handle a single request
function* handleRequestGen (req, resp) {
    //log('request', 'New request:', req.url);
    var urlData = parseURL(req.url);
    var verbs = new Verbs(null, {}, app.frontendRouter, app.backendRouter);
    try {
        var newReq = {
            uri: urlData.pathname,
            query: urlData.query,
            method: req.method.toLowerCase(),
            headers: req.headers
        };
        var response = yield* verbs.request(newReq);

        var body = response.body;
        if (body) {
            if (body.constructor === Object) {
                body = JSON.stringify(body);
            }
            if (body.constructor === String) {
                response.headers['Content-Length'] = Buffer.byteLength(body);
            } else if (body.constructor === Buffer) {
                response.headers['Content-Length'] = body.length;
            }
            resp.writeHead(response.status || 500, '', response.headers);
            resp.end(body);
        }

    } catch (e) {
        log('error/request', e, e.stack);
		// XXX: proper error reporting
		resp.writeHead(500, "Internal error");
        resp.end(e);
    }
}
var handleRequest = Promise.async(handleRequestGen);


// Main app setup
function* mainGen() {
    // Load handlers & set up routers
    app.frontendRouter = yield* makeRouter('frontend');
    app.backendRouter = yield* makeRouter('backend');

    var server = new http.Server();
    server.on('request', handleRequest);
    server.listen(8888);
    yield log('notice', 'listening on port 8888');
}
var main = Promise.async(mainGen);

main()
.catch(function(e) {
	log('error', e, e.stack);
});

@@ -1527,166 +1527,524 @@
 pars
-er%0Afunction parseURL (uri) %7B%0A    // Fast path%0A    var fastMatch = uri.match(/%5E(%5C/%5B%5E%5C?%5D*)(%5C?.*)?$/);%0A    if (fastMatch) %7B%0A        return %7B%0A            pathname
+ing%0A// XXX: contribute patch to node proper?%0Avar SIMPLE_PATH = /%5E(%5C/(?!%5C/)%5B%5E%5C?#%5Cs%5D*)(%5C?%5B%5E#%5Cs%5D*)?$/;%0Afunction parseURL (uri) %7B%0A    // Fast path for simple path uris%0A    var fastMatch = SIMPLE_PATH.exec(uri);%0A    if (fastMatch) %7B%0A        return %7B%0A            protocol: null,%0A            slashes: null,%0A            auth: null,%0A            host: null,%0A            port: null,%0A            hostname: null,%0A            hash: null,%0A            search: fastMatch%5B2%5D %7C%7C '',%0A            pathname: fastMatch%5B1%5D,%0A            path
 : fa
@@ -2118,16 +2118,39 @@
 %5D) %7C%7C %7B%7D
+,%0A            href: uri
 %0A       
@@ -2356,32 +2356,72 @@
 rseURL(req.url);
+%0A%0A    // Create the virtual HTTP service
 %0A    var verbs =
@@ -2777,24 +2777,59 @@
 if (body) %7B%0A
+            // Convert to a buffer%0A
             
@@ -2886,16 +2886,27 @@
  body = 
+new Buffer(
 JSON.str
@@ -2913,24 +2913,25 @@
 ingify(body)
+)
 ;%0A          
@@ -2933,28 +2933,21 @@
        %7D
-%0A           
+ else
  if (bod
@@ -2964,18 +2964,18 @@
 tor 
-=== String
+!== Buffer
 ) %7B%0A
@@ -2994,128 +2994,47 @@
     
-response.headers%5B'Content-Length'%5D = Buffer.byteLength(body);%0A            %7D else if (body.constructor === Buffer) %7B%0A    
+body = new Buffer(body);%0A            %7D%0A
     
@@ -3091,30 +3091,16 @@
 length;%0A
-            %7D%0A
         
@@ -3631,53 +3631,27 @@
 er =
- new
  http.
+create
 Server(
-);%0A    server.on('request', 
 hand

Generalize & clean up url parsing