var fs = require("fs");
var yaml = require("js-yaml");
var _ = require("underscore");
var path = require("path");
var marked = require("marked");

marked.setOptions({
  gfm: true,
  tables: true,
  breaks: true,
  highlight: function (code) {
    return require('highlight.js').highlightAuto(code).value;
  }
})

/** 
 * Defaults object
 * 
 */
var defaults = {
  optionsCheck: true,
  optionsDelimiter: "---",
  optionsParse: function (string) {
    return yaml.safeLoad(string);
  },
  contentParse: function (string) {
    return marked(string);
  },
  templatesDir: path.join(process.cwd(), "src", "layouts"),
  templateCompile: function (string) {
    return _.template(string);
  },
  templateData: {}
};



/**
 * Constructor for the Pagemaki class
 * 
 * @param {[type]} config [description]
 */
var Pagemaki = function (config) {
  this.templates = {};
  this.config = _.extend({}, defaults, config);
  this.config.optionsRegex = new RegExp("^" + this.config.optionsDelimiter + "([\\S\\s]+)" + this.config.optionsDelimiter + "([\\S\\s]+)");
};



/**
 * Find and return the template string to be compiled
 *
 * Note: this can be overridden by passing a 'getTemplateString'
 * function to the Pagemaki constructor, esp for testing
 * 
 * @param  {[type]} name [description]
 * @return {[type]}      [description]
 */
Pagemaki.prototype.getTemplateString = function (name) {
  return fs.readFileSync(path.join(this.config.templatesDir, name + ".html")).toString();
}



/**
 * Get a cached template by name, or from disk and then cache for later
 * 
 * @param  {[type]} name [description]
 * @return {[type]}      [description]
 */
Pagemaki.prototype.getTemplate = function (name) {

  var getTemplateString = (this.config.getTemplateString || this.getTemplateString).bind(this);

  if (!this.templates[name]) {
    this.templates[name] = this.config.templateCompile(getTemplateString(name).trim());
  }

  return this.templates[name];

};



/**
 * Parse out the string and look for options, content
 * 
 * @param  {[type]}   string   [description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
Pagemaki.prototype.parse = function (string, callback) {

  var data = {};
  var matches = this.config.optionsCheck && this.config.optionsRegex.exec(string);

  if (matches) {
    data.options = this.config.optionsParse(matches[1]);
    data.content = this.config.contentParse(matches[2].trim());
  } else {
    data.options = false;
    data.content = this.config.contentParse(string.trim());
  }

  callback(null, data);

};



/**
 * Use the rendering function to create static string
 * 
 * @param  {[type]}   err      [description]
 * @param  {[type]}   parsed   [description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
Pagemaki.prototype.render = function (err, parsed, callback) {

  if (err) {
    callback(err);
    return;
  }

  var layout = (parsed.options && parsed.options.layout) || "default";
  var render = this.getTemplate(layout);

  this.config.templateData.page = parsed;

  callback(null, render(this.config.templateData).trim());

};



/**
 * Putting it all together using the parsed options, content,
 * and templates to compile static HTML
 * 
 * @param  {[type]}   string   [description]
 * @param  {Function} callback [description]
 * @return {[type]}            [description]
 */
Pagemaki.prototype.make = function (string, callback) {

  var self = this;

  this.parse(string, function (err, parsed) {

    self.render(err, parsed, callback);

  });

};





module.exports = Pagemaki;

@@ -1934,33 +1934,32 @@
 es%5Bname%5D;%0A%0A%7D;%0A%0A%0A
-%0A
 /**%0A * Parse out
@@ -2020,40 +2020,84 @@
 m  %7B
-%5Btype%5D%7D   string   %5Bdescription%5D
+Object%7D   input    File object with string 'contents' and optional extension
 %0A * 
@@ -2224,35 +2224,159 @@
 nction (
-string, callback) %7B
+input, callback) %7B%0A%0A  if (typeof input.contents !== %22string%22) %7B%0A    callback(new Error(%22input.contents is a required string%22));%0A    return;%0A  %7D
 %0A%0A  var 
@@ -2460,22 +2460,30 @@
 ex.exec(
-string
+input.contents
 );%0A%0A  if
@@ -2609,24 +2609,41 @@
 es%5B2%5D.trim()
+, input.extension
 );%0A  %7D else 
@@ -2718,21 +2718,46 @@
 rse(
-string.trim()
+input.contents.trim(), input.extension
 );%0A 
@@ -2786,25 +2786,24 @@
 ata);%0A%0A%7D;%0A%0A%0A
-%0A
 /**%0A * Use t
@@ -3145,24 +3145,90 @@
 eturn;%0A  %7D%0A%0A
+  if (!parsed.content) %7B%0A    callback(null, %22%22);%0A    return;%0A  %7D%0A%0A
   var layout
@@ -3432,25 +3432,24 @@
 m());%0A%0A%7D;%0A%0A%0A
-%0A
 /**%0A * Putti
@@ -3562,24 +3562,23 @@
 m  %7B
-%5Btype%5D%7D   string
+Object%7D   input
    %5B
@@ -3720,22 +3720,21 @@
 nction (
-string
+input
 , callba
@@ -3773,22 +3773,21 @@
 s.parse(
-string
+input
 , functi
@@ -3859,19 +3859,16 @@
 ;%0A%0A%7D;%0A%0A%0A
-%0A%0A%0A
 module.e

Change input from string to object