var EPMSource = require("./epm");
var NPMSource = require("./npm");
var GlobalNPMSource = require("./globalnpm");
var FSSource = require("./fs");
var whilst = require("async/whilst");
var contract = require("@truffle/contract");
var expect = require("@truffle/expect");
var provision = require("@truffle/provisioner");

function Resolver(options) {
  expect.options(options, ["working_directory", "contracts_build_directory"]);

  this.options = options;

  this.sources = [
    new EPMSource(options.working_directory, options.contracts_build_directory),
    new NPMSource(options.working_directory),
    new GlobalNPMSource(),
    new FSSource(options.working_directory, options.contracts_build_directory)
  ];
}

// This function might be doing too much. If so, too bad (for now).
Resolver.prototype.require = function(import_path, search_path) {
  let abstraction;
  this.sources.forEach(source => {
    const result = source.require(import_path, search_path);
    if (result) {
      abstraction = contract(result, this.options);
      provision(abstraction, this.options);
    }
  });
  if (abstraction) return abstraction;
  throw new Error(
    "Could not find artifacts for " + import_path + " from any sources"
  );
};

Resolver.prototype.resolve = function(import_path, imported_from, callback) {
  var self = this;

  if (typeof imported_from === "function") {
    callback = imported_from;
    imported_from = null;
  }

  var resolved_body = null;
  var resolved_path = null;
  var current_index = -1;
  var current_source;

  whilst(
    function() {
      return !resolved_body && current_index < self.sources.length - 1;
    },
    function(next) {
      current_index += 1;
      current_source = self.sources[current_index];

      current_source.resolve(import_path, imported_from, function(
        err,
        body,
        file_path
      ) {
        if (!err && body) {
          resolved_body = body;
          resolved_path = file_path;
        }
        next(err);
      });
    },
    function(err) {
      if (err) return callback(err);

      if (!resolved_body) {
        var message = "Could not find " + import_path + " from any sources";

        if (imported_from) {
          message += "; imported from " + imported_from;
        }

        return callback(new Error(message));
      }

      callback(null, resolved_body, resolved_path, current_source);
    }
  );
};

module.exports = Resolver;

var EPMSource = require("./epm");
var NPMSource = require("./npm");
var GlobalNPMSource = require("./globalnpm");
var FSSource = require("./fs");
var whilst = require("async/whilst");
var contract = require("@truffle/contract");
var expect = require("@truffle/expect");
var provision = require("@truffle/provisioner");

function Resolver(options) {
  expect.options(options, ["working_directory", "contracts_build_directory"]);

  this.options = options;

  this.sources = [
    new EPMSource(options.working_directory, options.contracts_build_directory),
    new NPMSource(options.working_directory),
    new GlobalNPMSource(),
    new FSSource(options.working_directory, options.contracts_build_directory)
  ];
}

// This function might be doing too much. If so, too bad (for now).
Resolver.prototype.require = function(import_path, search_path) {
  let abstraction;
  this.sources.forEach(source => {
    const result = source.require(import_path, search_path);
    if (result) {
      abstraction = contract(
        result,
        this.options.networks[this.options.network].type
      );
      provision(abstraction, this.options);
    }
  });
  if (abstraction) return abstraction;
  throw new Error(
    "Could not find artifacts for " + import_path + " from any sources"
  );
};

Resolver.prototype.resolve = function(import_path, imported_from, callback) {
  var self = this;

  if (typeof imported_from === "function") {
    callback = imported_from;
    imported_from = null;
  }

  var resolved_body = null;
  var resolved_path = null;
  var current_index = -1;
  var current_source;

  whilst(
    function() {
      return !resolved_body && current_index < self.sources.length - 1;
    },
    function(next) {
      current_index += 1;
      current_source = self.sources[current_index];

      current_source.resolve(import_path, imported_from, function(
        err,
        body,
        file_path
      ) {
        if (!err && body) {
          resolved_body = body;
          resolved_path = file_path;
        }
        next(err);
      });
    },
    function(err) {
      if (err) return callback(err);

      if (!resolved_body) {
        var message = "Could not find " + import_path + " from any sources";

        if (imported_from) {
          message += "; imported from " + imported_from;
        }

        return callback(new Error(message));
      }

      callback(null, resolved_body, resolved_path, current_source);
    }
  );
};

module.exports = Resolver;

simplify contract() param input (resolver/index)