#!/usr/bin/env node
//# vi: ft=javascript

var fs = require('fs');
var path = require('path');

var _ = require('lodash');
var async = require('async');
var express = require('express');
var handlebars = require('handlebars');

var app = express();
var staticHandler = express['static'].bind(express);

app.use((function log() {
  var text = '{{date}} {{req.method}} {{req.url}}';
  var logTemplate = handlebars.compile(text);

  return function (req, res, next) {
    console.log(logTemplate({date: new Date().toISOString(), req: req}));
    next();
  };
}()));

function renderError(res, err) {
  console.error(err);
  res.writeHead(500, {'Content-Type': 'text/plain'});
  res.write(err);
}

function pathToFile() {
  return path.normalize(
    path.join.apply(null, [__dirname, '..'].concat(_.toArray(arguments)))
  );
}

app.get('/', function index(req, res) {
  var indexFile = pathToFile('assets', 'index.html');

  function compileServe(err, text) {
    if (err) {
      renderError(res, err);
      return;
    }
    var tmpl = handlebars.compile(text);
    res.send(tmpl());
  }

  fs.readFile(indexFile, {encoding: 'utf8'}, compileServe);
});

function serveIfExists(path) {
  return function _serveIfExists(cb) {
    fs.exists(path, function (exists) {
      if (!exists) {
        cb(null, null);
        return;
      }
      fs.readFile(path, {encoding: 'utf8'}, cb);
    });
  };
}

app.get('/slides', function showHandler(req, res) {
  fs.readdir(pathToFile('data', 'slide'), function (err, files) {
    files.sort();
    var jsonFiles = _.filter(files, function (file) {
      return /^\d+.json$/.test(file);
    });

    var getJsonFiles = _.map(jsonFiles, function (file) {
      return function (cb) {
        var serve = serveIfExists(pathToFile('data', 'slide', file));
        serve(function (err, content) {
          if (err) {
            cb(err, null);
            return;
          }
          try {
            var json = JSON.parse(content);
          } catch (err) {
            cb(err, null);
            return;
          }
          cb(null, json);
        });
      };
    });

    async.parallel(getJsonFiles, function (err, slideContent) {
      if (err) {
        renderError(res, err);
        return;
      }
      res.send(slideContent);
    });
  });
});

app.get(/slide\/(\d+)/, function showHandler(req, res, next) {
  var slideId = req.params[0];
  var slidePath = pathToFile('data', 'slide', slideId + '.json');

  fs.exists(slidePath, function (exists) {
    if (!exists) {
      next();
      return;
    }

    fs.readFile(slidePath, {encoding: 'utf8'}, function (err, content) {
      if (err) {
        renderError(res, err);
        return;
      }

      try {
        var slide = JSON.parse(content);
      } catch (err) {
        renderError(res, err);
        return;
      }

      async.parallel({
        copy: serveIfExists(pathToFile('data', 'copy', slide.copy + '.md')),
        code: serveIfExists(pathToFile('data', 'code', slide.code + '.js'))
      }, function (err, slideContent) {
        if (err) {
          renderError(res, err);
          return;
        }
        slideContent.id = parseInt(slideId, 10);
        slideContent.title = slide.title || '';
        res.send(slideContent);
      });
    });

  });
});

app.use('/data', staticHandler('data'));
app.use('/vendor', staticHandler('vendor'));
app.use('/static', staticHandler('static'));

app.listen(8000);