<%
// for(var i = 0; i < entries.length; i++) {
//   if(isClass(entries[i].tags)) {
// 
//   }
// }

var addLine = function(char, length) {
  var chars = [];  
  for(var i = 0; i < length; i++) chars[i] = char;
  return chars.join('');
}

// Contains the current class name
var className = null;

for(var i = 0; i < entries.length; i++) {
  if(isClass(entries[i].tags)) {
    var _name = entries[i].ctx.string.trim();
        
    %><%= format("%s\n%s\n%s\n", addLine("=", _name.length), _name, addLine("=", _name.length)) %><%
    className = entries[i].ctx.string.replace("()", "");
    
    %><%= format("\n------------------\nConstructor\n------------------\n") %><%

    // Get full description and clean it
    var fullDescription = entries[i].description.summary;
    fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
      .replace(/\<\/code\>\<\/pre\>/g, "")
      .replace(/\<h2\>|\<\/h2\>/g, "**")
      .replace(/\<p\>/g, "\n\n")
      .replace(/\<\/p\>/g, "")
      .replace(/&lt;/g, "<")
      .replace(/\<strong\>|\<\/strong\>/g, "**")
      .replace(/\<em\>|\<\/em\>/g, "*")
      .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n");
    %><%- format("%s\n\n", fullDescription) %><%    
    %><%= format("\n  .. js:class:: %s\n\n", entries[i].ctx.string) %><%

    for(var ti = 0; ti < entries[i].tags.length; ti++) { 
      // Get the current tag
      var tag = entries[i].tags[ti];    
      
      // If we have a parameter render it
      if(tag.type == 'param') {
        // Unpack the tag
        var type = tag.types[0].toLowerCase();
        var name = tag.name;
        var description = tag.description;
        // Render the parameter
        %><%= format("   :param %s %s: %s\n", type, name, description) %><%
      } else if(tag.type == 'return') {
        // Unpack the tag
        var type = tag.types[0].toLowerCase();
        var description = tag.description;
        // Render the parameter
        %><%= format("   :returns: %s %s\n", type, description) %><%        
      }
    }
    
    // Get full description and clean it
    var fullDescription = entries[i].description.body;
    fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
      .replace(/\<\/code\>\<\/pre\>/g, "")
      .replace(/\<h2\>|\<\/h2\>/g, "**")
      .replace(/\<p\>/g, "\n\n")
      .replace(/\<\/p\>/g, "")
      .replace(/\<strong\>|\<\/strong\>/g, "**")
      .replace(/\<em\>|\<\/em\>/g, "*")
      .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n")
      .replace(/&lt;/g, "<")
    %><%- format("%s\n\n", fullDescription) %><%    
  }
}

for(var i = 0; i < entries.length; i++) {
  if(isClassConstant(entries[i])) {
    %><%= format("\n------------------\nConstants\n------------------\n") %><%
%>
.. csv-table:: 
   :header: "Constant Name", "Value", "Description"
   :widths: 15, 10, 30

<%
    break;
  }
}

for(var i = 0; i < entries.length; i++) {
  if(isClassConstant(entries[i])) {
    // Extract values
    var attributeName = format("%s = %s;", entries[i].ctx.string, entries[i].ctx.value);
    var getterSetters = [];
    var type = "";
  
    // Get full description and clean it
    var fullDescription = entries[i].description.full;
    fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
      .replace(/\<\/code\>\<\/pre\>/g, "")
      .replace(/\<h2\>|\<\/h2\>/g, "**")
      .replace(/\<p\>/g, "\n\n")
      .replace(/\<\/p\>/g, "")
      .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n");

   // Write out the class definition row
   %><%- format("   \"%s\", \"%s\", \"%s\"\n", entries[i].ctx.string.trim(), entries[i].ctx.value.trim(), fullDescription.trim()) %><%
  }
}

for(var i = 0; i < entries.length; i++) {
  if(isProperty(entries[i])) {
    %><%= format("\n------------------\nProperties\n------------------\n") %><%
    break;
  }
}

for(var i = 0; i < entries.length; i++) {
  if(isProperty(entries[i])) {

    // If we have a class property
    if(entries[i].tags[0].type == 'class') {
%>
.. csv-table:: 
   :header: "Property"
   :widths: 30

<%

      // Write out all of the properties
      for(var j = 0; j < entries[i].tags.length; j++) {
        if(entries[i].tags[j].type == 'property') {
          %><%- format("   \"%s\"\n", entries[i].tags[j].string) %><%
        }
      }

      // Skip to next entry
      continue;
    }


    // Extract values
    var attributeName = "";
    var getterSetters = [];
    var type = "";
  
    // Loop over all tags
    for(var ti = 0; ti < entries[i].tags.length; ti++) {
      if(entries[i].tags[ti].type == 'field') attributeName = entries[i].tags[ti].string;
      if(entries[i].tags[ti].type == 'getter') getterSetters.push("Getter");
      if(entries[i].tags[ti].type == 'setter') getterSetters.push("Setter");
      if(entries[i].tags[ti].type == 'type') type = entries[i].tags[ti].types[0].toLowerCase();
    }
    
    // Get full description and clean it
    var fullDescription = entries[i].description.full;
    fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
      .replace(/\<\/code\>\<\/pre\>/g, "")
      .replace(/\<h2\>|\<\/h2\>/g, "**")
      .replace(/\<p\>/g, "\n\n")
      .replace(/\<\/p\>/g, "")
      .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n");
      
    // Write out the text
    %><%- format("%s\n\n", fullDescription) %><%
    %><%= format(".. js:attribute:: %s %s [%s]\n\n", attributeName, type, getterSetters.join("|")) %><%    

    // If we have examples render them
    if(examples != null && examples[attributeName]) {
      %><%= format("\n**Examples**\n\n") %><%      
      var examplesArray = examples[attributeName];
      // Iterate over all the examples
      for(var ei = 0; ei < examplesArray.length; ei++) {
        // Fetch an example
        var example = examplesArray[ei];
        var code = example.code;        
        code = code.replace(", ssl:useSSL", "")
          .replace("native_parser: native_parser", "native_parser: false")
          .replace(/test\.ok/g, "assert.ok")
          .replace(/test\.equal/g, "assert.equal")
          .replace(/test\.deepEqual/g, "assert.deepEqual")
          .replace(/\n[ |\t]*test\.done\(\)\;/, "");
      
        // Split and adjust code
        var codeLines = code.split(/\n/);
        for(var ci = 0; ci < codeLines.length; ci++) {
          codeLines[ci] = "     " + codeLines[ci];
        }
      
        var fullDescription = example.description.full;
        fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
          .replace(/\<\/code\>\<\/pre\>/g, "")
          .replace(/\<h2\>|\<\/h2\>/g, "**")
          .replace(/\<p\>/g, "\n\n")
          .replace(/\<\/p\>/g, "")
          .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n");
          
        // Split up and move
        var fullDescriptionLines = fullDescription.split(/\n/);
        for(var ci = 0; ci < fullDescriptionLines.length; ci++) {
          fullDescriptionLines[ci] = "  " + fullDescriptionLines[ci];
        }
        
        // Starting template Lines
        var startingTemplateLines = [
            "     var Db = require('mongodb').Db,",
            "         MongoClient = require('mongodb').MongoClient,",
            "         Server = require('mongodb').Server,",
            "         ReplSetServers = require('mongodb').ReplSetServers,",
            "         ObjectID = require('mongodb').ObjectID,",
            "         Binary = require('mongodb').Binary,",
            "         GridStore = require('mongodb').GridStore,",
            "         Grid = require('mongodb').Grid,",
            "         Code = require('mongodb').Code,",
            "         BSON = require('mongodb').pure().BSON,",
            "         assert = require('assert');\n\n"
          ];
                
        // Let's render it
        %><%- format("%s\n\n", fullDescriptionLines.join("\n")) %><%
        %><%- format("  .. code-block:: javascript\n\n%s%s\n\n", startingTemplateLines.join("\n"), codeLines.join("\n")) %><%
      }
    }
  }
}

for(var i = 0; i < entries.length; i++) {    
  // If it's a function parse it
  if(isFunction(entries[i])) {
    var paramsStrings = [];
    var paramNames = [];
    
    for(var ti = 0; ti < entries[i].tags.length; ti++) { 
      // Get the current tag
      var tag = entries[i].tags[ti];    
      
      // If we have a parameter render it
      if(tag.type == 'param') {
        // Unpack the tag
        var type = tag.types[0].toLowerCase();
        var name = tag.name;
        var description = tag.description;
        // Add to list of params
        paramNames.push(name);
        // Render the parameter
        paramsStrings.push(format("   :param %s %s: %s\n", type, name, description));
      } else if(tag.type == 'return') {
        // Unpack the tag
        var type = tag.types[0].toLowerCase();
        var description = tag.description;
        // Render the parameter
        paramsStrings.push(format("   :returns: %s %s\n\n", type, description));
      }
    }
        
    // Reformat any optional parameters from ,[] to [,]
    var paramsString = paramNames.join(", ").replace(/\, \[/, "[, ");
    
    // Write out the methods
    var fullDescription = entries[i].description.full;
    
    fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
      .replace(/\<\/code\>\<\/pre\>/g, "")
      .replace(/\<h2\>|\<\/h2\>/g, "**")
      .replace(/\<p\>/g, "\n\n")
      .replace(/\<\/p\>/g, "")
      .replace(/\<strong\>|\<\/strong\>/g, "**")
      .replace(/\<em\>|\<\/em\>/g, "*")
      .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n");
    
    // The name of examples
    var examplesName = entries[i].ctx.name;
        
    // Write header depending on if it's class or instance level
    if(entries[i].ctx.receiver != null && entries[i].ctx.receiver != "this") {   
      // Change examples Name to include class name
      var examplesName = format("%s.%s", className, entries[i].ctx.name);      
      var _length = format("%s.%s", className, entries[i].ctx.name).length;      
      %><%= format("\n%s\n%s.%s\n%s\n", addLine("-", _length), className, entries[i].ctx.name, addLine("-", _length)) %><%
      %><%- format("%s\n\n", fullDescription) %><%
      %><%= format(".. js:function:: %s.%s(%s)\n\n", className, entries[i].ctx.name, paramsString) %><%      
    } else {      
      var _length = entries[i].ctx.name.length;      
      %><%= format("\n%s\n%s\n%s\n", addLine("-", _length), entries[i].ctx.name, addLine("-", _length)) %><%
      %><%- format("%s\n\n", fullDescription) %><%
      %><%= format(".. js:function:: %s(%s)\n\n", entries[i].ctx.name, paramsString) %><%
    }
        
    %><%= Array.isArray(paramsStrings) ? paramsStrings.join("") : paramsStrings %><%

    // If we have examples render them
    if(examples != null && examples[examplesName]) {
      %><%= format("\n**Examples**\n\n") %><%      
      var examplesArray = examples[examplesName];
      
      // Iterate over all the examples
      for(var ei = 0; ei < examplesArray.length; ei++) {
        
        // Fetch an example
        var example = examplesArray[ei];
        
        var code = example.code;        
        code = code.replace(", ssl:useSSL", "")
          .replace("native_parser: native_parser", "native_parser: false")
          .replace(/test\.ok/g, "assert.ok")
          .replace(/test\.equal/g, "assert.equal")
          .replace(/test\.deepEqual/g, "assert.deepEqual")
          .replace(/\n[ |\t]*test\.done\(\)\;/, "");

        // Split and adjust code
        var codeLines = code.split(/\n/);
        for(var ci = 0; ci < codeLines.length; ci++) {
          codeLines[ci] = "     " + codeLines[ci];
        }

        var fullDescription = example.description.full;
        fullDescription = fullDescription.replace(/\<pre\>\<code\>/g, ".. code-block:: javascript\n\n   ")
          .replace(/\<\/code\>\<\/pre\>/g, "")
          .replace(/\<h2\>|\<\/h2\>/g, "**")
          .replace(/\<p\>/g, "\n\n")
          .replace(/\<\/p\>/g, "")
          .replace(/\<br[ ]*\>|\<\/br[ ]*\>|\<br[ ]*\/\>/g, "\n");
          
        // Split up and move
        var fullDescriptionLines = fullDescription.split(/\n/);
        for(var ci = 0; ci < fullDescriptionLines.length; ci++) {
          fullDescriptionLines[ci] = "  " + fullDescriptionLines[ci];
        }
        
        // Starting template Lines
        var startingTemplateLines = [
            "     var Db = require('mongodb').Db,",
            "         MongoClient = require('mongodb').MongoClient,",
            "         Server = require('mongodb').Server,",
            "         ReplSetServers = require('mongodb').ReplSetServers,",
            "         ObjectID = require('mongodb').ObjectID,",
            "         Binary = require('mongodb').Binary,",
            "         GridStore = require('mongodb').GridStore,",
            "         Grid = require('mongodb').Grid,",
            "         Code = require('mongodb').Code,",
            "         BSON = require('mongodb').pure().BSON,",
            "         assert = require('assert');\n\n"
          ];
                
        // Let's render it
        %><%- format("%s\n\n", fullDescriptionLines.join("\n")) %><%
        %><%- format("  .. code-block:: javascript\n\n%s%s\n\n", startingTemplateLines.join("\n"), codeLines.join("\n")) %><%
      }
    } 
  }
}
%>