/*
 * grunt-faker
 * https://github.com/chrisocast/grunt-faker
 *
 * Copyright (c) 2013 Chris Cast
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

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

  //Loop through entire json object
  function processJson(obj) {
    for (var i in obj) {
      if (typeof(obj[i]) === "object") {
        processJson(obj[i]); // found an obj or array keep digging
      } else if (obj[i] !== null){
        obj[i] = getFunctionNameAndArgs(obj[i]);// not an obj or array, check contents
      }
    }
    return obj;
  }

  // Get func name, extract args, and exec on their values
  function getFunctionNameAndArgs(value) {
    var pattern = /\{\{([^()]+?)(\((.+)\))?\}\}/g,
    match, func, args;
    var argArray = [];


    while (match = pattern.exec(value)) {
      func = match[1];
      args = match[3];
    }

    // Value is not a {{grunt-faker}} tag
    if (func === undefined){
      return value;
    }

    if (args !== undefined ){
      if (args.indexOf("[") !== -1){
        // is an array as string
        args = JSON.parse(args);
        argArray.push(args);
      } else {

        // one or more string/number params
        args = args.replace(/, /gi, ",");
        args = args.replace(/'/gi, "", "gi");
        argArray = args.split(',');
      }
    }


    return executeFunctionByName(func,argArray);
  }

  // Execute function as string
  function executeFunctionByName(functionName, args) {
    var namespaces = functionName.split(".");
    var nsLength = namespaces.length;
    var context = Faker;
    var parentContext = Faker;

    if (namespaces[0].toLowerCase() === 'definitions'){
      grunt.log.warn('The definitions module from Faker.js is not avail in this task.');
      return;
    }

    for(var i = 0; i < nsLength; i++) {
      context = context[namespaces[i]];
    }

    for(var j = 0; j < nsLength - 1; j++) {
      parentContext = parentContext[namespaces[j]];
    }

    return context.apply(parentContext, args);
  }

  grunt.registerMultiTask('faker', 'Generate fake JSON with faker.', function() {
    
    var options = this.options();

    // Check that options were provided 
    if(!options.hasOwnProperty("out")){
      grunt.log.warn('"out" option not specified.');
      return false;
    }
    if(!options.hasOwnProperty("jsonFormat")){
      grunt.log.warn('"jsonFormat" option not specified.');
      return false;
    }

    // Check for json format file
    var jsonFormatPath = options.jsonFormat;
    if (!grunt.file.exists(jsonFormatPath)) {
      grunt.log.warn('Format file "' + jsonFormatPath + '" not found.');
      return false;
    }

    // Create dir if needed
    var outputFilePath = options.out;
    var destDir = path.dirname(outputFilePath);
    if (!grunt.file.exists(destDir)) {
      grunt.file.mkdir(destDir);
    }

    // Get json and parse with faker
    var json = grunt.file.readJSON(jsonFormatPath);
    var outputJson = processJson(json);

    // Write file with faker json data
    grunt.file.write(outputFilePath, JSON.stringify(outputJson));

    // Print a success message
    grunt.log.writeln('File "' + outputFilePath + '" created.');
  });

};

@@ -2168,16 +2168,64 @@
 tions();
+%0A    var outs = grunt.util.toArray(options.out);
 %0A%0A    //
@@ -2374,24 +2374,163 @@
 alse;%0A    %7D%0A
+    if(Array.isArray(options.jsonFormat))%7B%0A      grunt.log.warn('%22jsonFormat%22 option has to be a single file.');%0A      return false;%0A    %7D%0A
     if(!opti
@@ -2884,70 +2884,80 @@
     
-// Create dir if needed%0A    var outputFilePath = options.out;%0A
+outs.forEach(function(outputFilePath) %7B%0A      // Create dir if needed%0A  
     
@@ -3000,24 +3000,26 @@
 ePath);%0A    
+  
 if (!grunt.f
@@ -3043,24 +3043,26 @@
 r)) %7B%0A      
+ 
+ 
 grunt.file.m
@@ -3076,16 +3076,18 @@
 stDir);%0A
+  
     %7D%0A%0A 
@@ -3089,16 +3089,18 @@
  %7D%0A%0A    
+  
 // Get j
@@ -3124,16 +3124,18 @@
 h faker%0A
+  
     var 
@@ -3178,24 +3178,26 @@
 tPath);%0A    
+  
 var outputJs
@@ -3217,24 +3217,26 @@
 son(json);%0A%0A
+  
     // Write
@@ -3262,24 +3262,26 @@
 on data%0A    
+  
 grunt.file.w
@@ -3335,16 +3335,18 @@
 );%0A%0A    
+  
 // Print
@@ -3368,25 +3368,31 @@
 age%0A    
+  
 grunt.
-log
+verbose
 .writeln
@@ -3439,14 +3439,17 @@
 ');%0A
+  
   %7D);%0A
-%0A%7D;%0A
+  %7D);

support writing output to multiple files, with different JSON data