var path = require('canonical-path');
var fs = require("fs");
var FRAGMENT_DIR = "./public/docs/_fragments";

/**
 * @dgService exampleInlineTagDef
 * @description
 * Process inline example tags (of the form {@example relativePath region -title='some title' -stylePattern='{some style pattern}' }),
 * replacing them with a jade makeExample mixin call.
 * @kind function
 * @param  {Object} path   The relative path to example
 * @param  {Function} docs error message
 * @return {String}  The jade makeExample mixin call
 *
 * @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc
 */
module.exports = function exampleInlineTagDef(getLinkInfo, createDocMessage, log) {
  return {
    name: 'example',
    description: 'Process inline example tags (of the form {@example some/uri Some Title}), replacing them with HTML anchors',
    handler: function(doc, tagName, tagDescription) {

      var tagArgs = parseArgs(tagDescription);
      var unnamedArgs = tagArgs._;
      var relativePath = unnamedArgs[0];
      var region = unnamedArgs.length > 1 && unnamedArgs[1];
      var title = tagArgs.title;
      // TODO: not yet implemented here
      var stylePattern = tagArgs.stylePattern;

      var dir = path.join("_api", path.dirname(relativePath));
      var extn = path.extname(relativePath);
      var baseNameNoExtn = path.basename(relativePath, extn);
      var fileName = region ? baseNameNoExtn + "-" + region + extn : baseNameNoExtn + extn;
      var fullFileName = path.join(FRAGMENT_DIR, dir, fileName);
      if ( !fs.existsSync(fileName)) {
        log.warn(createDocMessage('Invalid example (unable to locate fragment file: ' + quote(fullFileName), doc));
      }

      var comma = ', '
      var res = [ "+makeExample(", quote(dir), comma, quote(fileName), comma, title ? quote(title) : 'null', ")" ].join('');
      return res;
    }

  };
};

function quote(str) {
  if (str == null || str.length === 0) return str;
  str = str.replace("'","'\'");
  return "'" + str + "'";
}


// processes an arg string in 'almost' the same fashion that the command processor does
// and returns an args object in yargs format.
function parseArgs(str) {
  // regex from npm string-argv
  //[^\s'"] Match if not a space ' or "

  //+|['] or Match '
  //([^']*) Match anything that is not '
  //['] Close match if '

  //+|["] or Match "
  //([^"]*) Match anything that is not "
  //["] Close match if "
  var rx = /[^\s'"]+|[']([^']*?)[']|["]([^"]*?)["]/gi;
  var value = str;
  var unnammedArgs = [];
  var args = { _: unnammedArgs };
  var match, key;
  do {
    //Each call to exec returns the next regex match as an array
    match = rx.exec(value);
    if (match !== null) {
      //Index 1 in the array is the captured group if it exists
      //Index 0 is the matched text, which we use if no captured group exists
      var arg = match[2] ? match[2] : (match[1]?match[1]:match[0]);
      if (key) {
        args[key] = arg;
        key = null;
      } else {
        if (arg.substr(arg.length-1) === '=') {
          key = arg.substr(0, arg.length-1);
          // remove leading '-' if it exists.
          if (key.substr(0,1)=='-') {
            key = key.substr(1);
          }
        } else {
          unnammedArgs.push(arg)
          key = null;
        }
      }
    }
  } while (match !== null);
  return args;
}