/// <reference path="express.d.ts" />

import express = require('express');
var app = express();

//////////////////////////

var hash: any;

// config

app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');

// middleware

app.use(express.bodyParser());
app.use(express.cookieParser('shhhh, very secret'));
app.use(express.session());

// Session-persisted message middleware

app.use(function (req, res, next) {
    var err = req.session.error
      , msg = req.session.success;
    delete req.session.error;
    delete req.session.success;
    res.locals.message = '';
    if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
    if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
    next();
});

// dummy database

var users = <any>{
    tj: { name: 'tj' }
};

// when you create a user, generate a salt
// and hash the password ('foobar' is the pass here)

hash('foobar', function (err, salt, hash) {
    if (err) throw err;
    // store the salt & hash in the "db"
    users.tj.salt = salt;
    users.tj.hash = hash;
});


// Authenticate using our plain-object database of doom!

function authenticate(name, pass, fn) {
    if (!module.parent) console.log('authenticating %s:%s', name, pass);
    var user = users[name];
    // query the db for the given username
    if (!user) return fn(new Error('cannot find user'));
    // apply the same algorithm to the POSTed password, applying
    // the hash against the pass / salt, if there is a match we
    // found the user
    hash(pass, user.salt, function (err, hash) {
        if (err) return fn(err);
        if (hash == user.hash) return fn(null, user);
        fn(new Error('invalid password'));
    })
}

function restrict(req: ExpressServerRequest, res: ExpressServerResponse, next?: Function) {
    if (req.session.user) {
        next();
    } else {
        req.session.error = 'Access denied!';
        res.redirect('/login');
    }
}

app.get('/', function (req, res) {
    res.redirect('login');
});

app.get('/restricted', restrict, function (req, res) {
    res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>');
});

app.get('/logout', function (req, res) {
    // destroy the user's session to log them out
    // will be re-created next request
    req.session.destroy(function () {
        res.redirect('/');
    });
});

app.get('/login', function (req, res) {
    res.render('login');
});

app.post('/login', function (req, res) {
    authenticate(req.body.username, req.body.password, function (err, user) {
        if (user) {
            // Regenerate session when signing in
            // to prevent fixation 
            req.session.regenerate(function () {
                // Store the user's primary key 
                // in the session store to be retrieved,
                // or in this case the entire user object
                req.session.user = user;
                req.session.success = 'Authenticated as ' + user.name
                  + ' click to <a href="/logout">logout</a>. '
                  + ' You may now access <a href="/restricted">/restricted</a>.';
                res.redirect('back');
            });
        } else {
            req.session.error = 'Authentication failed, please check your '
              + ' username and password.'
              + ' (use "tj" and "foobar")';
            res.redirect('login');
        }
    });
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

//////////////

app.set('views', __dirname);
app.set('view engine', 'jade');

var pets = [];

var n = 1000;
while (n--) {
    pets.push({ name: 'Tobi', age: 2, species: 'ferret' });
    pets.push({ name: 'Loki', age: 1, species: 'ferret' });
    pets.push({ name: 'Jane', age: 6, species: 'ferret' });
}

app.use(express.logger('dev'));

app.get('/', function (req, res) {
    res.render('pets', { pets: pets });
});

app.listen(3000);
console.log('Express listening on port 3000');

/////////////

app.get('/', function (req, res) {
    res.format({
        html: function () {
            res.send('<ul>' + users.map(function (user) {
                return '<li>' + user.name + '</li>';
            }).join('') + '</ul>');
        },

        text: function () {
            res.send(users.map(function (user) {
                return ' - ' + user.name + '\n';
            }).join(''));
        },

        json: function () {
            res.json(users);
        }
    })
});

// or you could write a tiny middleware like
// this to abstract make things a bit more declarative:

function format(mod) {
    var obj = require(mod);
    return function (req, res) {
        res.format(obj);
    }
}

app.get('/users', format('./users'));

if (!module.parent) {
    app.listen(3000);
    console.log('listening on port 3000');
}

/////////////////////////

// add favicon() before logger() so
// GET /favicon.ico requests are not
// logged, because this middleware
// reponds to /favicon.ico and does not
// call next()
app.use(express.favicon());

// custom log format
if ('test' != process.env.NODE_ENV)
    app.use(express.logger(':method :url'));

// parses request cookies, populating
// req.cookies and req.signedCookies
// when the secret is passed, used 
// for signing the cookies.
app.use(express.cookieParser('my secret here'));

// parses json, x-www-form-urlencoded, and multipart/form-data
app.use(express.bodyParser());

app.get('/', function (req, res) {
    if (req.cookies.remember) {
        res.send('Remembered :). Click to <a href="/forget">forget</a>!.');
    } else {
        res.send('<form method="post"><p>Check to <label>'
          + '<input type="checkbox" name="remember"/> remember me</label> '
          + '<input type="submit" value="Submit"/>.</p></form>');
    }
});

app.get('/forget', function (req, res) {
    res.clearCookie('remember');
    res.redirect('back');
});

app.post('/', function (req, res) {
    var minute = 60000;
    if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
    res.redirect('back');
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

///////////////////

// ignore GET /favicon.ico
app.use(express.favicon());

// pass a secret to cookieParser() for signed cookies
app.use(express.cookieParser('manny is cool'));

// add req.session cookie support
app.use(express.cookieSession());

// do something with the session
app.use(count);

// custom middleware
function count(req, res) {
    req.session.count = req.session.count || 0;
    var n = req.session.count++;
    res.send('viewed ' + n + ' times\n');
}

if (!module.parent) {
    app.listen(3000);
    console.log('Express server listening on port 3000');
}

///////////////

var api = app;

app.use(express.static(__dirname + '/public'));

// api middleware

api.use(express.logger('dev'));
api.use(express.bodyParser());

/**
 * CORS support.
 */

api.all('*', function (req, res, next) {
    if (!req.get('Origin')) return next();
    // use "*" here to accept any origin
    res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.set('Access-Control-Allow-Methods', 'GET, POST');
    res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
    // res.set('Access-Control-Allow-Max-Age', 3600);
    if ('OPTIONS' == req.method) return res.send(200);
    next();
});

/**
 * POST a user.
 */

api.post('/user', function (req, res) {
    console.log(req.body);
    res.send(201);
});

app.listen(3000);
api.listen(3001);

console.log('app listening on 3000');
console.log('api listening on 3001');

////////////////////

app.get('/', function (req, res) {
    res.send('<ul>'
      + '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
      + '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
      + '</ul>');
});

// /files/* is accessed via req.params[0]
// but here we name it :file
app.get('/files/:file(*)', function (req, res, next?) {
    var file = req.params.file
      , path = __dirname + '/files/' + file;

    res.download(path);
});

// error handling middleware. Because it's
// below our routes, you will be able to
// "intercept" errors, otherwise Connect
// will respond with 500 "Internal Server Error".
app.use(function (err, req, res, next) {
    // special-case 404s,
    // remember you could
    // render a 404 template here
    if (404 == err.status) {
        res.statusCode = 404;
        res.send('Cant find that file, sorry!');
    } else {
        next(err);
    }
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

///////////////////

// Register ejs as .html. If we did
// not call this, we would need to
// name our views foo.ejs instead
// of foo.html. The __express method
// is simply a function that engines
// use to hook into the Express view
// system by default, so if we want
// to change "foo.ejs" to "foo.html"
// we simply pass _any_ function, in this
// case `ejs.__express`.

app.engine('.html', require('ejs').__express);

// Optional since express defaults to CWD/views

app.set('views', __dirname + '/views');

// Without this you would need to
// supply the extension to res.render()
// ex: res.render('users.html').
app.set('view engine', 'html');

app.get('/', function (req, res) {
    res.render('users', {
        users: users,
        title: "EJS example",
        header: "Some users"
    });
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express app started on port 3000');
}

////////////////////

var test: any;

if (!test) app.use(express.logger('dev'));
app.use(app.router);

// the error handler is strategically
// placed *below* the app.router; if it
// were above it would not receive errors
// from app.get() etc 
app.use(error);

// error handling middleware have an arity of 4
// instead of the typical (req, res, next),
// otherwise they behave exactly like regular
// middleware, you may have several of them,
// in different orders etc.

function error(err, req, res, next) {
    // log it
    if (!test) console.error(err.stack);

    // respond with 500 "Internal Server Error".
    res.send(500);
}

app.get('/', function (req, res) {
    // Caught and passed down to the errorHandler middleware
    throw new Error('something broke!');
});

app.get('/next', function (req, res, next) {
    // We can also pass exceptions to next()
    process.nextTick(function () {
        next(new Error('oh no!'));
    });
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

/////////////////////

var silent: any;

// general config
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');

// our custom "verbose errors" setting
// which we can use in the templates
// via settings['verbose errors']
app.enable('verbose errors');

// disable them in production
// use $ NODE_ENV=production node examples/error-pages
if ('production' == app.settings.env) {
    app.disable('verbose errors');
}

app.use(express.favicon());

silent || app.use(express.logger('dev'));

// "app.router" positions our routes 
// above the middleware defined below,
// this means that Express will attempt
// to match & call routes _before_ continuing
// on, at which point we assume it's a 404 because
// no route has handled the request.

app.use(app.router);

// Since this is the last non-error-handling
// middleware use()d, we assume 404, as nothing else
// responded.

// $ curl http://localhost:3000/notfound
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"

app.use(function (req, res, next) {
    res.status(404);

    // respond with html page
    if (req.accepts('html')) {
        res.render('404', { url: req.url });
        return;
    }

    // respond with json
    if (req.accepts('json')) {
        res.send({ error: 'Not found' });
        return;
    }

    // default to plain-text. send()
    res.type('txt').send('Not found');
});

// error-handling middleware, take the same form
// as regular middleware, however they require an
// arity of 4, aka the signature (err, req, res, next).
// when connect has an error, it will invoke ONLY error-handling
// middleware.

// If we were to next() here any remaining non-error-handling
// middleware would then be executed, or if we next(err) to
// continue passing the error, only error-handling middleware
// would remain being executed, however here
// we simply respond with an error page.

app.use(function (err, req, res, next) {
    // we may use properties of the error object
    // here and next(err) appropriately, or if
    // we possibly recovered from the error, simply next().
    res.status(err.status || 500);
    res.render('500', { error: err });
});

// Routes

app.get('/', function (req, res) {
    res.render('index.jade');
});

app.get('/404', function (req, res, next) {
    // trigger a 404 since no other middleware
    // will match /404 after this one, and we're not
    // responding here
    next();
});

app.get('/403', function (req, res, next) {
    // trigger a 403 error
    var err = <any>new Error('not allowed!');
    err.status = 403;
    next(err);
});

app.get('/500', function (req, res, next) {
    // trigger a generic (500) error
    next(new Error('keyboard cat!'));
});

if (!module.parent) {
    app.listen(3000);
    //silent ||  console.log('Express started on port 3000');
}

///////////////

var fs: any;
var md: any;

app.set('view engine', 'jade');
app.set('views', __dirname + '/views');

function User(name) {
    this.private = 'heyyyy';
    this.secret = 'something';
    this.name = name;
    this.id = 123;
}

// You'll probably want to do
// something like this so you
// dont expose "secret" data.

User.prototype.toJSON = function () {
    return {
        id: this.id,
        name: this.name
    }
};

app.use(express.logger('dev'));

// earlier on expose an object
// that we can tack properties on.
// all res.locals props are exposed
// to the templates, so "expose" will
// be present.

app.use(function (req, res, next) {
    res.locals.expose = {};
    // you could alias this as req or res.expose
    // to make it shorter and less annoying
    next();
});

// pretend we loaded a user

app.use(function (req, res, next) {
    req.user = new User('Tobi');
    next();
});

app.get('/', function (req, res) {
    res.redirect('/user');
});

app.get('/user', function (req, res) {
    // we only want to expose the user
    // to the client for this route:
    res.locals.expose.user = req.user;
    res.render('page');
});

app.listen(3000);
console.log('app listening on port 3000');

///////////////////////

app.get('/', function (req, res) {
    res.send('Hello World');
});

app.listen(3000);
console.log('Express started on port 3000');

////////////////////

// register .md as an engine in express view system

app.engine('md', function (path, options, fn) {
    fs.readFile(path, 'utf8', function (err, str) {
        if (err) return fn(err);
        try {
            var html = md(str);
            html = html.replace(/\{([^}]+)\}/g, function (_, name) {
                return options[name] || '';
            })
            fn(null, html);
        } catch (err) {
            fn(err);
        }
    });
})

app.set('views', __dirname + '/views');

// make it the default so we dont need .md
app.set('view engine', 'md');

app.get('/', function (req, res) {
    res.render('index', { title: 'Markdown Example' });
})

app.get('/fail', function (req, res) {
    res.render('missing', { title: 'Markdown Example' });
})

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

///////////////////////

var mformat: any;

// bodyParser in connect 2.x uses node-formidable to parse 
// the multipart form data.
app.use(express.bodyParser())

app.get('/', function (req, res) {
    res.send('<form method="post" enctype="multipart/form-data">'
      + '<p>Title: <input type="text" name="title" /></p>'
      + '<p>Image: <input type="file" name="image" /></p>'
      + '<p><input type="submit" value="Upload" /></p>'
      + '</form>');
});

app.post('/', function (req, res, next) {
    // the uploaded file can be found as `req.files.image` and the
    // title field as `req.body.title`
    res.send(mformat('\nuploaded %s (%d Kb) to %s as %s'
      , req.files.image.name
      , req.files.image.size / 1024 | 0
      , req.files.image.path
      , req.body.title));
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

//////////////////


// first:
// $ npm install redis online
// $ redis-server

/**
 * Module dependencies.
 */

var online: any;
var redis: any;
var db: any;

// online

online = online(db);

// activity tracking, in this case using
// the UA string, you would use req.user.id etc

app.use(function (req, res, next) {
    // fire-and-forget
    online.add(req.headers['user-agent']);
    next();
});

/**
 * List helper.
 */

function list(ids) {
    return '<ul>' + ids.map(function (id) {
        return '<li>' + id + '</li>';
    }).join('') + '</ul>';
}

/**
 * GET users online.
 */

app.get('/', function (req, res, next) {
    online.last(5, function (err, ids) {
        if (err) return next(err);
        res.send('<p>Users online: ' + ids.length + '</p>' + list(ids));
    });
});

app.listen(3000);
console.log('listening on port 3000');

///////////////////

// Convert :to and :from to integers

app.param(['to', 'from'], function (req, res, next, num, name) {
    req.params[name] = num = parseInt(num, 10);
    if (isNaN(num)) {
        next(new Error('failed to parseInt ' + num));
    } else {
        next();
    }
});

// Load user by id

app.param('user', function (req, res, next, id) {
    if (req.user = users[id]) {
        next();
    } else {
        next(new Error('failed to find user'));
    }
});

/**
 * GET index.
 */

app.get('/', function (req, res) {
    res.send('Visit /user/0 or /users/0-2');
});

/**
 * GET :user.
 */

app.get('/user/:user', function (req, res, next) {
    res.send('user ' + req.user.name);
});

/**
 * GET users :from - :to.
 */

app.get('/users/:from-:to', function (req, res, next) {
    var from = req.params.from
      , to = req.params.to
      , names = users.map(function (user) { return user.name; });
    res.send('users ' + names.slice(from, to).join(', '));
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

//////////////////

// Ad-hoc example resource method

app.resource = function (path, obj) {
    this.get(path, obj.index);
    this.get(path + '/:a..:b.:format?', function (req, res) {
        var a = parseInt(req.params.a, 10)
          , b = parseInt(req.params.b, 10)
          , format = req.params.format;
        obj.range(req, res, a, b, format);
    });
    this.get(path + '/:id', obj.show);
    this.del(path + '/:id', obj.destroy);
};

// Fake controller.

var FUser = {
    index: function (req, res) {
        res.send(users);
    },
    show: function (req, res) {
        res.send(users[req.params.id] || { error: 'Cannot find user' });
    },
    destroy: function (req, res) {
        var id = req.params.id;
        var destroyed = id in users;
        delete users[id];
        res.send(destroyed ? 'destroyed' : 'Cannot find user');
    },
    range: function (req, res, a, b, format) {
        var range = users.slice(a, b + 1);
        switch (format) {
            case 'json':
                res.send(range);
                break;
            case 'html':
            default:
                var html = '<ul>' + range.map(function (user) {
                    return '<li>' + user.name + '</li>';
                }).join('\n') + '</ul>';
                res.send(html);
                break;
        }
    }
};

// curl http://localhost:3000/users     -- responds with all users
// curl http://localhost:3000/users/1   -- responds with user 1
// curl http://localhost:3000/users/4   -- responds with error
// curl http://localhost:3000/users/1..3 -- responds with several users
// curl -X DELETE http://localhost:3000/users/1  -- deletes the user

app.resource('/users', FUser);

app.get('/', function (req, res) {
    res.send([
        '<h1>Examples:</h1> <ul>'
      , '<li>GET /users</li>'
      , '<li>GET /users/1</li>'
      , '<li>GET /users/3</li>'
      , '<li>GET /users/1..3</li>'
      , '<li>GET /users/1..3.json</li>'
      , '<li>DELETE /users/4</li>'
      , '</ul>'
    ].join('\n'));
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express started on port 3000');
}

/////////////////////


var verbose: any;

app.map = function (a, route) {
    route = route || '';
    for (var key in a) {
        switch (typeof a[key]) {
            // { '/path': { ... }}
            case 'object':
                app.map(a[key], route + key);
                break;
            // get: function(){ ... }
            case 'function':
                if (verbose) console.log('%s %s', key, route);
                app[key](route, a[key]);
                break;
        }
    }
};

var users2 = {
    list: function (req, res) {
        res.send('user list');
    },

    get: function (req, res) {
        res.send('user ' + req.params.uid);
    },

    del: function (req, res) {
        res.send('delete users');
    }
};

var pets2 = {
    list: function (req, res) {
        res.send('user ' + req.params.uid + '\'s pets');
    },

    del: function (req, res) {
        res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
    }
};

app.map({
    '/users': {
        get: users2.list,
        del: users2.del,
        '/:uid': {
            get: users.get ,
            '/pets': {
                get: pets2.list,
                '/:pid': {
                    del: pets2.del
                }
            }
        }
    }
});

app.listen(3000);

///////////////////////////

// Example requests:
//     curl http://localhost:3000/user/0
//     curl http://localhost:3000/user/0/edit
//     curl http://localhost:3000/user/1
//     curl http://localhost:3000/user/1/edit (unauthorized since this is not you)
//     curl -X DELETE http://localhost:3000/user/0 (unauthorized since you are not an admin)

function loadUser(req, res, next) {
    // You would fetch your user from the db
    var user = users[req.params.id];
    if (user) {
        req.user = user;
        next();
    } else {
        next(new Error('Failed to load user ' + req.params.id));
    }
}

function andRestrictToSelf(req, res, next) {
    // If our authenticated user is the user we are viewing
    // then everything is fine :)
    if (req.authenticatedUser.id == req.user.id) {
        next();
    } else {
        // You may want to implement specific exceptions
        // such as UnauthorizedError or similar so that you
        // can handle these can be special-cased in an error handler
        // (view ./examples/pages for this)
        next(new Error('Unauthorized'));
    }
}

function andRestrictTo(role) {
    return function (req, res, next) {
        if (req.authenticatedUser.role == role) {
            next();
        } else {
            next(new Error('Unauthorized'));
        }
    }
}

// Middleware for faux authentication
// you would of course implement something real,
// but this illustrates how an authenticated user
// may interact with middleware

app.use(function (req, res, next) {
    req.authenticatedUser = users[0];
    next();
});

app.get('/', function (req, res) {
    res.redirect('/user/0');
});

app.get('/user/:id', loadUser, function (req, res) {
    res.send('Viewing user ' + req.user.name);
});

app.get('/user/:id/edit', loadUser, andRestrictToSelf, function (req, res) {
    res.send('Editing user ' + req.user.name);
});

app.del('/user/:id', loadUser, andRestrictTo('admin'), function (req, res) {
    res.send('Deleted user ' + req.user.name);
});

app.listen(3000);
console.log('Express app started on port 3000');

/////////////////////////

app.set('view engine', 'jade');
app.set('views', __dirname);

// populate search

db.sadd('ferret', 'tobi');
db.sadd('ferret', 'loki');
db.sadd('ferret', 'jane');
db.sadd('cat', 'manny');
db.sadd('cat', 'luna');

/**
 * GET the search page.
 */

app.get('/', function (req, res) {
    res.render('search');
});

/**
 * GET search for :query.
 */

app.get('/search/:query?', function (req, res) {
    var query = req.params.query;
    db.smembers(query, function (err, vals) {
        if (err) return res.send(500);
        res.send(vals);
    });
});

/**
 * GET client javascript. Here we use sendfile()
 * because serving __dirname with the static() middleware
 * would also mean serving our server "index.js" and the "search.jade"
 * template.
 */

app.get('/client.js', function (req, res) {
    res.sendfile(__dirname + '/client.js');
});

app.listen(3000);
console.log('app listening on port 3000');

///////////////////

app.use(express.logger('dev'));

// Required by session() middleware
// pass the secret for signed cookies
// (required by session())
app.use(express.cookieParser('keyboard cat'));

// Populates req.session
app.use(express.session());

app.get('/', function (req, res) {
    var body = '';
    if (req.session.views) {
        ++req.session.views;
    } else {
        req.session.views = 1;
        body += '<p>First time visiting? view this page in several browsers :)</p>';
    }
    res.send(body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>');
});

app.listen(3000);
console.log('Express app started on port 3000');

////////////////////////

// log requests
app.use(express.logger('dev'));

// express on its own has no notion
// of a "file". The express.static()
// middleware checks for a file matching
// the `req.path` within the directory
// that you pass it. In this case "GET /js/app.js"
// will look for "./public/js/app.js".

app.use(express.static(__dirname + '/public'));

// if you wanted to "prefix" you may use
// the mounting feature of Connect, for example
// "GET /static/js/app.js" instead of "GET /js/app.js".
// The mount-path "/static" is simply removed before
// passing control to the express.static() middleware,
// thus it serves the file correctly by ignoring "/static"
app.use('/static', express.static(__dirname + '/public'));

// if for some reason you want to serve files from
// several directories, you can use express.static()
// multiple times! Here we're passing "./public/css",
// this will allow "GET /style.css" instead of "GET /css/style.css":
app.use(express.static(__dirname + '/public/css'));

// this examples does not have any routes, however
// you may `app.use(app.router)` before or after these
// static() middleware. If placed before them your routes
// will be matched BEFORE file serving takes place. If placed
// after as shown here then file serving is performed BEFORE
// any routes are hit:
app.use(app.router);

app.listen(3000);
console.log('listening on port 3000');
console.log('try:');
console.log('  GET /hello.txt');
console.log('  GET /js/app.js');
console.log('  GET /css/style.css');

//////////////////

/*
edit /etc/vhosts:

127.0.0.1       foo.example.com
127.0.0.1       bar.example.com
127.0.0.1       example.com
*/

// Main app

var main = express();

main.use(express.logger('dev'));

main.get('/', function (req, res) {
    res.send('Hello from main app!')
});

main.get('/:sub', function (req, res) {
    res.send('requsted ' + req.params.sub);
});

// Redirect app

var redirect = express();

redirect.all('*', function (req, res) {
    console.log(req.subdomains);
    res.redirect('http://example.com:3000/' + req.subdomains[0]);
});

app.use(express.vhost('*.example.com', redirect))
app.use(express.vhost('example.com', main));

app.listen(3000);
console.log('Express app started on port 3000');

////////////////////

// create an error with .status. we
// can then use the property in our
// custom error handler (Connect repects this prop as well)

function merror(status, msg) {
    var err = <any>new Error(msg);
    err.status = status;
    return err;
}

// if we wanted to supply more than JSON, we could
// use something similar to the content-negotiation
// example.

// here we validate the API key,
// by mounting this middleware to /api
// meaning only paths prefixed with "/api"
// will cause this middleware to be invoked

app.use('/api', function (req, res, next) {
    var key = req.query['api-key'];

    // key isnt present
    if (!key) return next(merror(400, 'api key required'));

    // key is invalid
    if (!~apiKeys.indexOf(key)) return next(merror(401, 'invalid api key'));

    // all good, store req.key for route access
    req.key = key;
    next();
});

// position our routes above the error handling middleware,
// and below our API middleware, since we want the API validation
// to take place BEFORE our routes
app.use(app.router);

// middleware with an arity of 4 are considered
// error handling middleware. When you next(err)
// it will be passed through the defined middleware
// in order, but ONLY those with an arity of 4, ignoring
// regular middleware.
app.use(function (err, req, res, next) {
    // whatever you want here, feel free to populate
    // properties on `err` to treat it differently in here.
    res.send(err.status || 500, { error: err.message });
});

// our custom JSON 404 middleware. Since it's placed last
// it will be the last middleware called, if all others
// invoke next() and do not respond.
app.use(function (req, res) {
    res.send(404, { error: "Lame, can't find that" });
});

// map of valid api keys, typically mapped to
// account info with some sort of database like redis.
// api keys do _not_ serve as authentication, merely to
// track API usage or help prevent malicious behavior etc.

var apiKeys = ['foo', 'bar', 'baz'];

// these two objects will serve as our faux database

var repos = [
    { name: 'express', url: 'http://github.com/visionmedia/express' }
  , { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
  , { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
];

var userRepos = {
    tobi: [repos[0], repos[1]]
  , loki: [repos[1]]
  , jane: [repos[2]]
};

// we now can assume the api key is valid,
// and simply expose the data

app.get('/api/users', function (req, res, next) {
    res.send(users);
});

app.get('/api/repos', function (req, res, next) {
    res.send(repos);
});

app.get('/api/user/:name/repos', function (req, res, next) {
    var name = req.params.name
      , user = userRepos[name];

    if (user) res.send(user);
    else next();
});

if (!module.parent) {
    app.listen(3000);
    console.log('Express server listening on port 3000');
}

////// 

function test_general() {

    app.use(function (err, req, res, next) {
        console.error(err.stack);
        res.send(500, 'Something broke!');
    });
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(function (err, req, res, next) { });
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);

    app.get('/', function (req, res) {
        res.send('hello world');
    });

    app.listen(3000);

    app.set('title', 'My Site');
    app.get('title');

    app.enable('trust proxy');
    app.get('trust proxy');

    app.disable('trust proxy');
    app.get('trust proxy');

    app.enabled('trust proxy');

    app.configure(() => {
        app.set('title', 'My Application');
    });

    app.configure('development', () => {
        app.set('db uri', 'localhost/dev');
    });

    app.configure('stage', 'production', function () { });

    app.configure('1', '2', '3', function () { });

    app.use(function (req, res, next) {
        res.send('Hello World');
    });

    app.engine('jade', require('jade').__express);

    var User;
    app.param('user', (req, res, next, id) => {
        User.find(id, (err, user) =>{
            if (err) {
                next(err);
            } else if (user) {
                req.user = user;
                next();
            } else {
                next(new Error('failed to load user'));
            }
        });
    });

    app.get(/^\/commits\/(\d+)(?:\.\.(\d+))?$/, (req, res) => {
        var from = req.params[0];
        var to = req.params[1] || 'HEAD';
        res.send('commit range ' + from + '..' + to);
    });

    app.locals.title = 'My App';
    app.locals.strftime = require('strftime');

    var requireAuthentication;
    var loadUser = function () { };
    app.all('*', requireAuthentication, loadUser);
    app.all('*', loadUser);
    app.all('*', loadUser, loadUser, loadUser);

    app.locals.title = 'My App';
    app.locals.strftime = require('strftime');
    app.locals({
        title: 'My App',
        phone: '1-250-858-9990',
        email: 'me@myapp.com'
    });
    app.render('email', function (err, html) { });

    app.render('email', { name: 'Tobi' }, function (err, html) { });
}

function test_request() {
    var req: ExpressServerRequest;
    req.params.name;
    req.params[0];
    req.query.q;
    req.body.user.name;
    app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/my/files' }));
    req.param('name');
    req.route;
    req.cookies.name;
    req.signedCookies;
    req.get('Content-Type');
    req.accepts('html');
    req.accepts(['html', 'json']);
    req.is('html');
    req.ip;
    req.path;
    req.host;
    req.fresh;
    req.stale;
    req.xhr;
    req.protocol;
    req.subdomains;
    req.originalUrl;
    req.acceptedLanguages;
    req.acceptedCharsets;
    var charset;
    req.acceptsCharset(charset);
    var lang;
    req.acceptsLanguage(lang);
    req.session = null;
}

function test_response() {
    var res: ExpressServerResponse;
    res.status(404).sendfile('path/to/404.png');
    res.set('Content-Type', 'text/plain');
    res.set({
        'Content-Type': 'text/plain',
        'Content-Length': '123',
        'ETag': '12345'
    });
    res.get('Content-Type');
    res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true });
    res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
    res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true });
    res.cookie('cart', { items: [1, 2, 3] });
    res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 });;
    res.cookie('name', 'tobi', { signed: true });
    res.cookie('name', 'tobi', { path: '/admin' });
    res.clearCookie('name', { path: '/admin' });
    res.redirect('/foo/bar');
    res.redirect('http://example.com');
    res.redirect(301, 'http://example.com');
    res.charset = 'value';
    res.send('some html');
    res.send(new Buffer('whoop'));
    res.send({ some: 'json' });
    res.send('some html');
    res.send(404, 'Sorry, we cannot find that!');
    res.send(500, { error: 'something blew up' });
    res.send(200);
    res.set('Content-Type', 'text/html');
    res.send(new Buffer('some html'));
    res.send('some html');
    res.send({ user: 'tobi' });
    res.send([1, 2, 3]);
    res.json(null);
    res.json({ user: 'tobi' });
    res.json(500, { error: 'message' });
    res.jsonp(null);
    res.jsonp({ user: 'tobi' });
    res.jsonp(500, { error: 'message' });
    res.jsonp({ user: 'tobi' });
    res.type('application/json');

    res.format({
        'text/plain': function () {
            res.send('hey');
        },
        'text/html': function () {
            res.send('hey');
        },
        'application/json': function () {
            res.send({ message: 'hey' });
        }
    });

    res.attachment();
    res.attachment('path/to/logo.png');
    app.get('/user/:uid/photos/:file', function (req, res) {
        var uid = req.params.uid
            , file = req.params.file;

        req.user.mayViewFilesFrom(uid, function (yes) {
            if (yes) {
                res.sendfile('/uploads/' + uid + '/' + file);
            } else {
                res.send(403, 'Sorry! you cant see that.');
            }
        });
    });

    res.download('/report-12345.pdf');
    res.download('/report-12345.pdf', 'report.pdf');
    res.download('/report-12345.pdf', 'report.pdf', function (err) {
        if (err) { } else { }
    });

    res.links({
        next: 'http://api.example.com/users?page=2',
        last: 'http://api.example.com/users?page=5'
    });

    app.use(function (req, res, next) {
        res.locals.user = req.user;
        res.locals.authenticated = !req.user.anonymous;
        next();
    });
    res.render('index', function (err, html) { });
    res.render('user', { name: 'Tobi' }, function (err, html) { });

}

function test_middleware() {
    app.use(express.basicAuth('username', 'password'));
    app.use(express.basicAuth(function (user, pass) {
        return 'tj' == user && 'wahoo' == pass;
    }));
    app.use(express.bodyParser());
    app.use(express.json());
    app.use(express.urlencoded());
    app.use(express.multipart());
    app.use(express.logger());
    app.use(express.compress());
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.cookieParser('some secret'));
    app.use(express.cookieSession());
    app.use(express.directory('public'));
    app.use(express.static('public'));
}
