#!/usr/bin/env node

var fs = require('fs'),
    path = require('path'),
    commander = require('commander'),
    async = require('async'),
    glob = require('glob'),
    mkdirp = require('mkdirp'),
    typogr = require('./typogr');


function isDirectory(pathString) {
  try {
    // Query the entry
    return fs.statSync(pathString).isDirectory();
  }
  catch (error) {
    // if file doesn't exist, statSync throws an error instead of just returning false
    return false;
  }
}

// path.dirname and path.basename don't always work right, so we have to create our own functions
function dirname(pathString) {
  return pathString.substring(0, pathString.lastIndexOf('/') + 1);
}

function basename(pathString) {
  return pathString.substring(pathString.lastIndexOf('/') + 1);
}

function readRenderWrite(input, output, force) {
  input = path.normalize(input);
  output = path.normalize(output);

  if(isDirectory(input))
    input = input + '/**';  // add glob to get all files under directory

  var inputDirectory = dirname(input),
      inputGlob = basename(input),
      after,
      outputString;

  // process input
  glob(inputGlob, { cwd: inputDirectory }, function (error, files) {
    async.eachSeries(files, function (file, eachCallback) {
      // only process files; other types such as directories or links are ignored
      fs.stat(inputDirectory + '/' + file, function (error, stats) {
        if(stats.isFile()) {
          // read file
          fs.readFile(inputDirectory + '/' + file, 'utf8', function (error, before) {
            // process the html
            after = typogr.typogrify(before);
            // write file
            if(output === '/dev/stdout') // writeFile doesn't like /dev/stdout even though readFile works with /dev/stdin
              console.log(after);
            else {
              if(files.length > 1) {
                // multiple input files means we are dealing with a directory or a glob,
                // so make sure directory exists
                mkdirp.sync(output + '/' + dirname(file));
                outputString = path.normalize(output + '/' + file);
              }
              else // one input file means we are only writing one file
                outputString = output;
              if(force) {
                fs.writeFile(outputString, after, function (error) {
                  eachCallback(error);
                });
              }
              else {
                confirmOverwrite(outputString, function (ok) {
                  if(ok)
                    fs.writeFile(outputString, after, function (error) {
                      eachCallback(error);
                    });
                });
              }
            }
          });
        }
        else
          eachCallback(null);
      });
    }, function (error) {
      if(error) throw error;
    });
  });
}

function confirmOverwrite(fileName, callback) {
  fs.stat(fileName, function(error, stats) {
    if(stats) {
      if(stats.isFile()) {
        commander.confirm('Confirm: overwrite file (' + fileName + ')? ', function(ok) {
          // work around bug in commander.js 
          // see (https://github.com/visionmedia/commander.js/issues/109)
          // also see (https://github.com/visionmedia/commander.js/pull/133)
          process.stdin.pause();

          if(ok)
            callback(true);
          else {
            console.log("  Cancelling action, file wasn't modified.");
            callback(false);
          }
        });
      }
      else {
        // fileName is not of type 'file' (close our eyes and assume it's a directory)
        callback(true);
      }
    }
    else {
      // fileName doesn't exist
      callback(true);
    }
  });
}


function main() {
  // specify cli options
  commander
    .version('0.6.8')
    .usage('[options] [input] [output]')
    .option('-i, --inplace', 'Use single path as both input and output')
    .option('-f, --force', 'Do not prompt to verify file overwrites');

  // specify example help text
  commander.on('--help', function() {
    console.log('  reads input from stdin, individual files, directories, or globs');
    console.log('  writes ouput to stdout, individual files, or directories');
    console.log('');
    console.log('  Examples:');
    console.log('');
    console.log('    $ typogr inputFile.html outputFile.html');
    console.log('    $ typogr < inputFile.html > outputFile.html');
    console.log('    $ typogr -i singleFile.html');
    console.log('    $ typogr inputDirectory outputDirectory');
    console.log('    $ typogr inputDirectory/*.html outputDirectory');
    console.log('');
  });

  // parse arguments and generate object mappings in the *commander* object
  commander.parse(process.argv);

  switch (commander.args.length) {
    case 0:
      // get input from stdin and send output to stdout
      readRenderWrite('/dev/stdin', '/dev/stdout');
      break;
    case 1:
      if (commander.inplace) {
        // modify the file in place
        readRenderWrite(commander.args[0], commander.args[0], commander.force);
      }
      else {
        // get input from file specified and send output to stdout
        readRenderWrite(commander.args[0], '/dev/stdout');
      }
      break;
    case 2:
      // get input from first parameter and send output to second parameter
      readRenderWrite(commander.args[0], commander.args[1], commander.force);
      break;
  }

}


module.exports.main = main;