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

var walkdir = require('walkdir');
var mkdirp = require('mkdirp');

var Filesystem = require('./filesystem');
var disk = require('./disk');

module.exports.createPackage = function(src, dest, cb) {
  var filesystem = new Filesystem(src);
  var files = [];
  var walking = walkdir(filesystem.src);
  walking.on('directory', function(p, stat) {
    filesystem.insertDirectory(p);
  });
  walking.on('file', function(p, stat) {
    files.push(p);
    filesystem.insertFile(p, stat);
  });
  walking.on('link', function(p, stat) {
    filesystem.insertLink(p, stat);
  });
  walking.on('end', function() {
    disk.writeFilesystem(dest, filesystem, files, function() {
      if ('function' === typeof cb)
        cb(null);
    });
  });
};

module.exports.listPackage = function(archive) {
  return disk.readFilesystem(archive).listFiles()
}

module.exports.extractFile = function(archive, filename) {
  var filesystem = disk.readFilesystem(archive);
  return disk.readFile(filesystem, filesystem.getFile(filename));
}

module.exports.extractAll = function(archive, dest) {
  var filesystem = disk.readFilesystem(archive);
  var filenames = filesystem.listFiles();
  var i, content, file, filename, destFilename, linkTo;
  // under windows just extract links as regular files
  var followLinks = 'win32' === os.platform();
  
  mkdirp.sync(dest); // create destination directory

  for (i in filenames) {
    filename = filenames[i].substr(1); // get rid of leading slash
    destFilename = path.join(dest, filename);
    file = filesystem.getFile(filename, followLinks);
    if (file.files) {
      // it's a directory, create it and continue with the next entry
      mkdirp.sync(destFilename);
    }
    else if (file.link) {
      // it's a symlink, create a symlink
      var linkSrcPath = path.dirname(path.join(dest, file.link));
      var linkDestPath = path.dirname(destFilename);
      var relativePath = path.relative(linkDestPath, linkSrcPath);

      // try to delete output file, because we can't overwrite a link
      try {
        fs.unlinkSync(destFilename);
      }
      catch (err) {
      }

      linkTo = path.join(relativePath, path.basename(file.link));
      fs.symlinkSync(linkTo, destFilename);
    }
    else {
      // it's a file, extract it
      content = disk.readFile(filesystem, file);
      fs.writeFileSync(destFilename, content);
    }
  }
  return true;
}

@@ -214,65 +214,735 @@
 );%0A%0A
-module.exports.createPackage = function(src, dest, cb) %7B%0A
+var crawlFilesystem = function(dir, cb) %7B%0A  var paths = %5B%5D;%0A  var metadata = %7B%7D;%0A%0A  var emitter = walkdir(dir);%0A  emitter.on('directory', function(p, stat) %7B%0A    paths.push(p);%0A    metadata%5Bp%5D = %7Btype: 'directory', stat: stat%7D;%0A  %7D);%0A  emitter.on('file', function(p, stat) %7B%0A    paths.push(p);%0A    metadata%5Bp%5D = %7Btype: 'file', stat: stat%7D;%0A  %7D);%0A  emitter.on('link', function(p, stat) %7B%0A    paths.push(p);%0A    metadata%5Bp%5D = %7Btype: 'link', stat: stat%7D;%0A  %7D);%0A  emitter.on('end', function() %7B%0A    paths.sort();%0A    cb(false, paths, metadata);%0A  %7D);%0A  emitter.on('error', function(err) %7B%0A    cb(err);%0A  %7D);%0A%7D;%0A%0Amodule.exports.createPackage = function(src, dest, cb) %7B%0A  crawlFilesystem(src, function(err, filenames, metadata) %7B%0A  
   va
@@ -977,16 +977,18 @@
 m(src);%0A
+  
   var fi
@@ -1001,95 +1001,168 @@
 %5B%5D;%0A
+  
   var 
-walking = walkdir(filesystem.src)
+i, filename, file;%0A    for(i in filenames) %7B%0A      filename = filenames%5Bi%5D
 ;%0A  
+ 
-walking.on('directory', function(p, stat) %7B%0A
+   file = metadata%5Bfilename%5D;%0A      if ('directory' === file.type) %7B%0A    
     
@@ -1192,78 +1192,100 @@
 ory(
-p);%0A
+filename);%0A    
   %7D
-);
 %0A  
-walking.on('file', function(p, stat) %7B%0A    files.push(p);%0A
+    else if ('file' === file.type) %7B%0A        files.push(filename);%0A    
     
@@ -1310,139 +1310,222 @@
 ile(
-p, 
+filename, file.
 stat);%0A
+    
   %7D
-);
 %0A  
-walking.on('link', function(p, stat) %7B%0A    filesystem.insertLink(p, stat);%0A
+    else if ('link' === file.type) %7B%0A        filesystem.insertLink(filename, file.stat);%0A      %7D%0A  
   %7D
-);
 %0A  
-walking.on('end', function() %7B
+  // create output dir if necessary%0A    mkdirp.sync(path.dirname(dest));%0A    
 %0A   
@@ -1756,16 +1756,17 @@
 iles()%0A%7D
+;
 %0A%0Amodule
@@ -1934,16 +1934,17 @@
 ame));%0A%7D
+;
 %0A%0Amodule
@@ -3313,9 +3313,10 @@
  true;%0A%7D
+;
 %0A

put walkdir results in list and sort