// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

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

function _summarize(method, hashes) {
  var keys = Object.keys(hashes);
  keys.sort();

  var obj = {};
  obj.files = hashes;
  var hash = crypto.createHash(method);
  for (var i = 0; i < keys.length; i++) {
    if (typeof(hashes[keys[i]]) === 'string') {
      hash.update(hashes[keys[i]]);
    } else if (typeof(hashes[keys[i]]) === 'object') {
      hash.update(hashes[keys[i]].hash);
    } else {
      console.error('Unknown type found in hash: ' + typeof(hashes[keys[i]]));
    }
  }

  obj.hash = hash.digest('hex');
  return obj;
}

function digest(root, method, callback) {
  if (!root || typeof(root) !== 'string') {
    throw new TypeError('root is required (string)');
  }
  if (method) {
    if (typeof(method) === 'string') {
      // NO-OP
    } else if (typeof(method) === 'function') {
      callback = method;
      method = 'md5';
    } else {
      throw new TypeError('hash must be a string');
    }
  } else {
    throw new TypeError('callback is required (function)');
  }
  if (!callback) {
    throw new TypeError('callback is required (function)');
  }

  var hashes = {};

  fs.readdir(root, function(err, files) {
    if (err) return callback(err);

    if (files.length === 0) {
      return callback(undefined, {hash: '', files: {}});
    }

    var hashed = 0;
    files.forEach(function(f) {
      var path = root + '/' + f;
      fs.stat(path, function(err, stats) {
        if (err) return callback(err);

        if (stats.isDirectory()) {
          return digest(path, method, function(err, hash) {
            if (err) return hash;

            hashes[f] = hash;
            if (++hashed >= files.length) {
              return callback(undefined, _summarize(method, hashes));
            }
          });
        } else if (stats.isFile()) {
          fs.readFile(path, 'utf8', function(err, data) {
            if (err) return callback(err);

            var hash = crypto.createHash(method);
            hash.update(data);
            hashes[f] = hash.digest('hex');

            if (++hashed >= files.length) {
              return callback(undefined, _summarize(method, hashes));
            }
          });
        } else {
          console.error('Skipping hash of %s', f);
          if (++hashed > files.length) {
            return callback(undefined, _summarize(method, hashes));
          }
        }
      });
    });
  });
}

module.exports = {
  digest: digest
};

@@ -692,16 +692,24 @@
  method,
+ ignore,
  callbac
@@ -1450,24 +1450,61 @@
 nction(f) %7B%0A
+      if(ignore.indexOf(f) %3E= 0) %7B%0A  
       var pa
@@ -1524,16 +1524,18 @@
 /' + f;%0A
+  
       fs
@@ -1569,32 +1569,34 @@
 tats) %7B%0A        
+ 
+ 
 if (err) return 
@@ -1615,24 +1615,26 @@
 );%0A%0A        
+  
 if (stats.is
@@ -1654,24 +1654,26 @@
 %7B%0A          
+ 
+ 
 return diges
@@ -1706,24 +1706,26 @@
 rr, hash) %7B%0A
+  
             
@@ -1751,32 +1751,34 @@
 h;%0A%0A            
+  
 hashes%5Bf%5D = hash
@@ -1779,16 +1779,18 @@
 = hash;%0A
+  
         
@@ -1817,32 +1817,34 @@
 files.length) %7B%0A
+  
               re
@@ -1901,34 +1901,38 @@
 ));%0A            
-%7D%0A
+  %7D%0A  
           %7D);%0A  
@@ -1921,32 +1921,34 @@
             %7D);%0A
+  
         %7D else i
@@ -1978,16 +1978,18 @@
         
+ 
+ 
 fs.readF
@@ -2024,24 +2024,26 @@
 rr, data) %7B%0A
+  
             
@@ -2082,24 +2082,26 @@
             
+  
 var hash = c
@@ -2134,24 +2134,26 @@
             
+ 
+ 
 hash.update(
@@ -2159,16 +2159,18 @@
 (data);%0A
+  
         
@@ -2210,32 +2210,34 @@
 );%0A%0A            
+ 
+ 
 if (++hashed %3E= 
@@ -2244,32 +2244,34 @@
 files.length) %7B%0A
+  
               re
@@ -2328,34 +2328,38 @@
 ));%0A            
-%7D%0A
+  %7D%0A  
           %7D);%0A  
@@ -2348,32 +2348,34 @@
             %7D);%0A
+  
         %7D else %7B
@@ -2381,24 +2381,26 @@
 %7B%0A          
+  
 console.erro
@@ -2428,16 +2428,18 @@
 s', f);%0A
+  
         
@@ -2475,32 +2475,34 @@
 ) %7B%0A            
+  
 return callback(
@@ -2543,34 +2543,38 @@
 es));%0A          
+ 
+ 
 %7D%0A
+  
         %7D%0A      
@@ -2569,28 +2569,44 @@
     %7D%0A      
+  
 %7D);%0A
+      %7D      %0A
     %7D);%0A  %7D)

add ignore