'use strict';

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

var detector = require('./detector');

var handlers = {};
var types = require('./types');

// load all available handlers
types.forEach(function (type) {
  handlers[type] = require('./types/' + type);
});

// Maximum buffer size, with a default of 512 kilobytes.
// TO-DO: make this adaptive based on the initial signature of the image
var MaxBufferSize = 512*1024;

/**
 * Return size information based on a buffer
 *
 * @param {Buffer} buffer
 * @param {String} filepath
 * @returns {Object}
 */
function lookup (buffer, filepath) {
  // detect the file type.. don't rely on the extension
  var type = detector(buffer, filepath);

  // find an appropriate handler for this file type
  if (type in handlers) {
    var size = handlers[type].calculate(buffer, filepath);
    if (size !== false) {
      size.type = type;
      return size;
    }
  }

  // throw up, if we don't understand the file
  throw new TypeError('unsupported file type: ' + type + ' (file: ' + filepath + ')');
}

/**
 * Reads a file into a buffer.
 *
 * The callback will be called after the process has completed. The
 * callback's first argument will be an error (or null). The second argument
 * will be the Buffer, if the operation was successful.
 *
 * @param {String} filepath
 * @param {Function} callback
 */
function asyncFileToBuffer (filepath, callback) {
  // open the file in read only mode
  fs.open(filepath, 'r', function (err, descriptor) {
    if (err) { return callback(err); }
    var size = fs.fstatSync(descriptor).size;
    if (size <= 0){return callback(new Error("File size is not greater than 0 —— " + filepath)); }
    var bufferSize = Math.min(size, MaxBufferSize);
    var buffer = new Buffer(bufferSize);
    // read first buffer block from the file, asynchronously
    fs.read(descriptor, buffer, 0, bufferSize, 0, function (err) {
      if (err) { return callback(err); }
      // close the file, we are done
      fs.close(descriptor, function (err) {
        callback(err, buffer);
      });
    });
  });
}

/**
 * Synchronously reads a file into a buffer, blocking the nodejs process.
 *
 * @param {String} filepath
 * @returns {Buffer}
 */
function syncFileToBuffer (filepath) {
  // read from the file, synchronously
  var descriptor = fs.openSync(filepath, 'r');
  var size = fs.fstatSync(descriptor).size;
  var bufferSize = Math.min(size, MaxBufferSize);
  var buffer = new Buffer(bufferSize);
  fs.readSync(descriptor, buffer, 0, bufferSize, 0);
  fs.closeSync(descriptor);
  return buffer;
}

/**
 * @param {Buffer|string} input - buffer or relative/absolute path of the image file
 * @param {Function} callback - optional function for async detection
 */
module.exports = function (input, callback) {

  // Handle buffer input
  if (Buffer.isBuffer(input)) {
    return lookup(input);
  }

  // input should be a string at this point
  if (typeof input !== 'string') {
    throw new TypeError('invalid invocation');
  }

  // resolve the file path
  var filepath = path.resolve(input);

  if (typeof callback === 'function') {
    asyncFileToBuffer(filepath, function (err, buffer) {
      if (err) { return callback(err); }

      // return the dimensions
      var dimensions;
      try {
        dimensions = lookup(buffer, filepath);
      } catch (e) {
        err = e;
      }
      callback(err, dimensions);
    });
  } else {
    var buffer = syncFileToBuffer(filepath);
    return lookup(buffer, filepath);
  }
};

module.exports.types = types;

@@ -1535,27 +1535,16 @@
 ); %7D%0A   
- var size =
  fs.fsta
@@ -1536,36 +1536,32 @@
 ; %7D%0A    fs.fstat
-Sync
 (descriptor).siz
@@ -1547,33 +1547,121 @@
 fstat(descriptor
-)
+, function (err, stats) %7B%0A      if (err) %7B return callback(err); %7D%0A      var size = stats
 .size;%0A    if (s
@@ -1651,24 +1651,26 @@
 s.size;%0A    
+  
 if (size %3C= 
@@ -1671,17 +1671,27 @@
 ze %3C= 0)
-%7B
+ %7B%0A        
 return c
@@ -1759,23 +1759,31 @@
 epath));
+%0A     
  %7D%0A    
+ 
+ 
 var buff
@@ -1822,24 +1822,26 @@
 rSize);%0A    
+  
 var buffer =
@@ -1861,24 +1861,26 @@
 ufferSize);%0A
+  
     // read 
@@ -1932,16 +1932,18 @@
 sly%0A    
+  
 fs.read(
@@ -1993,24 +1993,26 @@
 ion (err) %7B%0A
+  
       if (er
@@ -2046,16 +2046,18 @@
 %7D%0A      
+  
 // close
@@ -2079,16 +2079,18 @@
 re done%0A
+  
       fs
@@ -2129,24 +2129,26 @@
 ) %7B%0A        
+ 
+ 
 callback(err
@@ -2158,16 +2158,28 @@
 uffer);%0A
+        %7D);%0A
       %7D)

use `fs.fstat` in the async code path (#101)