
/*!
 * makeit-browserable
 * @license MIT
 */

/*
 * Module dependencies
 */

var path = require('bike.path')
  , fs = require('bike.fs')
  , mkdirp = require('bike.fs/mkdirp')
  , through2 = require('through2')
  , mdeps = require('module-deps')
  , browserPack = require('browser-pack')
  , JSONStream = require('JSONStream')
  , pipeline = require('stream-combiner')
  , depSorter = require('deps-sort')
  , crypto = require('crypto')
  , copy = require('shallow-copy')
  ;

function hash(what) {
  return crypto.createHash('md5').update(what).digest('base64').slice(0, 6);
}

/**
 * Module exports
 */

module.exports = function (options, params, callback) {

  var pack = this
    , source
    , ast
    , min
    , src = path.join(pack.conf.__cwd, pack.conf.__dirname, options.src)
    , dest = path.join(pack.conf.__cwd, pack.conf.__dirname, options.dest)
    ;

  var b = new Browserable({
    src: src,
    dest: dest
  }, callback);

  b.pipe(fs.createWriteStream(path.join(path.dirname(dest), 'aaaa.js')));
};



  var list = {}
    , list_count = 0
    ;


function Browserable (opts, callback) {
  if (!opts) opts = {};

  var output = through2();


  var d = (opts.deps || this.deps.bind(this))(opts);
  var p = this.pack(opts);

  d.pipe(p);

  p.pipe(output);

  output.on('end', function () {
    process.nextTick(function () {
      // output.emit('close');
      callback();
    });
  });

  return output;
}


Browserable.prototype.pack = function (opts) {
  if (!opts) opts = {};

  var self = this;
  var hashes = {}, depList = {}, depHash = {};


    var input = through2.obj(function (row_, encoding, callback) {
        var row = copy(row_);
// console.log(row);
// console.log('=================================');
// console.log('=================================');
// console.log('=================================');
// console.log('=================================');
        // if (opts.debug) {
        //     row.sourceRoot = 'file://localhost';
        //     row.sourceFile = row.id.replace(/\\/g, '/');
        // }

        // var dup = hashes[row.hash];
        // if (dup && sameDeps(depList[dup._id], row.deps)) {
        //     row.source = 'module.exports=require('
        //         + JSON.stringify(dup.id)
        //         + ')'
        //     ;
        //     row.nomap = true;
        // }
        // else if (dup) {
        //     row.source = 'arguments[4]['
        //         + JSON.stringify(dup.id)
        //         + '][0].apply(exports,arguments)'
        //     ;
        // }
        // else hashes[row.hash] = { _id: row.id, id: getId(row) };

        // if (/^#!/.test(row.source)) row.source = '//' + row.source;
        // var err = checkSyntax(row.source, row.id);
        // if (err) return callback(err);

        // var newId = getId(row);
        // self.emit('id', newId, row.id);
        // row.id = getId(row);

        // if (row.entry) mainModule = mainModule || row.id;

        // var deps = {};
        // Object.keys(row.deps || {}).forEach(function (key) {
        //     var file = row.deps[key];
        //     var index = row.indexDeps && row.indexDeps[key];
        //     if (self._exposeAll) {
        //         index = self._hash(file);
        //     }
        //     deps[key] = getId({ id: file, index: index });
        // });
        // row.deps = deps;

        this.push(row);
        callback();
    });


  var packer = browserPack({
    raw: true,
    // prelude: fs.readFileSync(path.join(__dirname, 'prelude.js'), 'utf-8'),
    prelude: '(PRELUDE)',
    // preludePath: path.join(__dirname, 'prelude.js'),
    sourceMapPrefix: '//#',
    basedir: path.dirname(opts.src)
  });

  var output = through2(write, end);
  var sort = depSorter({ index: true });
  // var sort = depSorter({ index: true });
  // var emitRows = through2.obj(function (row, enc, next) {
  //     self.emit('row', row);
  //     this.push(row);
  //     next();
  // });

  return pipeline(through2.obj(hasher), sort, input, packer, output);

  function write (buf, encoding, callback) {
      // if (first) writePrelude.call(this);
      // first = false;
      this.push(buf);
      callback();
  }

  function end (callback) {
      // if (first) writePrelude.call(this);
      // if (opts.standalone) {
      //     this.push(
      //         '\n(' + JSON.stringify(mainModule) + ')'
      //         + umd.postlude(opts.standalone)
      //     );
      // }
      // if (opts.debug) this.push('\n');
      callback();
  }

  function hasher (row, encoding, callback) {
      row.hash = hash(row.source);
      depList[row.id] = row.deps;
      depHash[row.id] = row.hash;
      this.push(row);
      callback();
  }


  function sameDeps (a, b, limit) {
      var keys = Object.keys(a);
      if (keys.length !== Object.keys(b).length) return false;

      for (var i = 0; i < keys.length; i++) {
          var k = keys[i], ka = a[k], kb = b[k];
          var ha = depHash[ka];
          var hb = depHash[kb];
          var da = depList[ka];
          var db = depList[kb];

          if (ka === kb) continue;
          if (ha !== hb || (!limit && !sameDeps(da, db, 1))) {
              return false;
          }
      }
      return true;
  }

}


Browserable.prototype.deps = function (opts) {
  if (!opts) opts = {};

  var self = this;
  // var packer = self._browserPack(opts);
  var d = mdeps(opts.src, {
    // transform: '' // []
    // , transformKey: []
    basedir: path.dirname(opts.src)
    ,packageFilter: function (pkg, dir) {
      return pkg;
    }
  });

  return d.pipe(through2.obj(write));


//   g.pipe(through2.obj(write, end));

  function write (row, encoding, callback) {

    // row.source = 'module.exports = {};';

    if (/^\ufeff/.test(row.source)) {
            row.source = row.source.replace(/^\ufeff/, '');
        }

    row.deps = Object.keys(row.deps).reduce(function (acc, key) {
      console.log(acc);
      // if (!self._exclude[key] && !self._external[key]
      // && !self._external[row.id] && row.deps[key] !== excludeModulePath) {
        acc[key] = row.deps[key];
      // }
      return acc;
    }, {});

// skip adding this file if it is external
        if ('bike' == row.id) {
            return callback();
        }


    if (/\.json$/.test(row.id)) {
        row = copy(row);
        row.source = 'module.exports=' + row.source;
    }

    row.id = list[row.id] = list[row.id] || ++list_count;
    var index = row.indexDeps && row.indexDeps[key];
// console.log('eee', index);

        var deps = {};
        Object.keys(row.deps || {}).forEach(function (key) {
            var file = row.deps[key];
            // deps[key] = getId({ id: file, index: index });
            deps[key] = list[file] = list[file] || ++list_count;
        });
        row.deps = deps;



    this.push(row);
        callback();
  };
}