/* eslint no-console:1 */

'use strict';

var fs = require('fs');
var Q = require('q');

// Matches strings generated by Date.toJSON()
// which is called to serialize date to JSON.
var jsonDateParser = function (key, value) {
  var reISO = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/;
  if (typeof value === 'string') {
    if (reISO.exec(value)) {
      return new Date(value);
    }
  }
  return value;
};

var makeNicerJsonParsingError = function (path, err) {
  var nicerError = new Error('JSON parsing failed while reading '
  + path + ' [' + err + ']');
  nicerError.originalError = err;
  return nicerError;
};

// ---------------------------------------------------------
// SYNC
// ---------------------------------------------------------

var readSync = function (path, returnAs) {
  var retAs = returnAs || 'utf8';
  var data;

  var encoding = 'utf8';
  if (retAs === 'buffer') {
    encoding = null;
  } else if (retAs === 'buf') {
    console.warn("[fs-jetpack] DEPRECATION WARNING: Please use 'buffer' " +
      "instead of 'buf' in read() method.");
    encoding = null;
  }

  try {
    data = fs.readFileSync(path, { encoding: encoding });
  } catch (err) {
    if (err.code === 'ENOENT') {
      // If file doesn't exist return undefined instead of throwing.
      return undefined;
    }
    // Otherwise rethrow the error
    throw err;
  }

  try {
    if (retAs === 'json') {
      data = JSON.parse(data);
    } else if (retAs === 'jsonWithDates') {
      data = JSON.parse(data, jsonDateParser);
    }
  } catch (err) {
    throw makeNicerJsonParsingError(path, err);
  }

  return data;
};

// ---------------------------------------------------------
// ASYNC
// ---------------------------------------------------------

var promisedReadFile = Q.denodeify(fs.readFile);

var readAsync = function (path, returnAs) {
  var deferred = Q.defer();

  var retAs = returnAs || 'utf8';
  var encoding = 'utf8';
  if (retAs === 'buffer') {
    encoding = null;
  } else if (retAs === 'buf') {
    console.warn("[fs-jetpack] DEPRECATION WARNING: Please use 'buffer' " +
      "instead of 'buf' in read() method.");
    encoding = null;
  }

  promisedReadFile(path, { encoding: encoding })
  .then(function (data) {
    // Make final parsing of the data before returning.
    try {
      if (retAs === 'json') {
        deferred.resolve(JSON.parse(data));
      } else if (retAs === 'jsonWithDates') {
        deferred.resolve(JSON.parse(data, jsonDateParser));
      } else {
        deferred.resolve(data);
      }
    } catch (err) {
      deferred.reject(makeNicerJsonParsingError(path, err));
    }
  })
  .catch(function (err) {
    if (err.code === 'ENOENT') {
      // If file doesn't exist return undefined instead of throwing.
      deferred.resolve(undefined);
    } else {
      // Otherwise throw
      deferred.reject(err);
    }
  });

  return deferred.promise;
};

// ---------------------------------------------------------
// API
// ---------------------------------------------------------

exports.sync = readSync;
exports.async = readAsync;
