#include "dep.h"

#include <memory>

#include "log.h"
#include "rule.h"
#include "var.h"

static vector<DepNode*>* g_dep_node_pool;

DepNode::DepNode(StringPiece o, bool p)
    : output(o),
      has_rule(false),
      is_order_only(false),
      is_phony(p),
      target_specific_vars(NULL) {
  g_dep_node_pool->push_back(this);
}

class DepBuilder {
 public:
  DepBuilder(const vector<Rule*>& rules,
             const Vars& vars,
             const unordered_map<StringPiece, Vars*>& rule_vars)
      : vars_(vars),
        rule_vars_(rule_vars),
        first_rule_(NULL) {
    PopulateRules(rules);
  }

  void Build(vector<StringPiece> targets,
             vector<DepNode*>* nodes) {
    if (targets.empty()) {
      if (!first_rule_) {
        ERROR("*** No targets.");
      }
      CHECK(!first_rule_->outputs.empty());
      targets.push_back(first_rule_->outputs[0]);
    }

    // TODO: LogStats?

    for (StringPiece target : targets) {
      unique_ptr<Vars> tsvs(new Vars);
      DepNode* n = BuildPlan(target, "", tsvs.get());
      nodes->push_back(n);
    }
  }

 private:
  void PopulateRules(const vector<Rule*>& rules) {
    for (Rule* rule : rules) {
      if (rule->outputs.empty()) {
        PopulateImplicitRule(rule);
      } else {
        PopulateExplicitRule(rule);
      }
    }
  }

  void PopulateExplicitRule(Rule* rule) {
    for (StringPiece output : rule->outputs) {
      // isSuffixRule := db.populateSuffixRule(rule, output)


      /*
          if oldRule, present := db.rules[output]; present {
     r := mergeRules(oldRule, rule, output, isSuffixRule)
                                                         db.rules[output] = r
                                                         } else {
        db.rules[output] = rule
            if db.firstRule == nil && !strings.HasPrefix(output, ".") {
                db.firstRule = rule
              }
      }
      */

      auto p = rules_.insert(make_pair(output, rule));
      if (p.second) {
        if (!first_rule_ && output.get(0) != '.') {
          first_rule_ = rule;
        }
      } else {
        // TODO: merge
        CHECK(false);
      }
    }
  }

  void PopulateImplicitRule(Rule*) {
    CHECK(false);
  }

  Rule* LookupRule(StringPiece o) {
    auto found = rules_.find(o);
    if (found != rules_.end())
      return found->second;
    return NULL;
  }

  Vars* LookupRuleVars(StringPiece o) {
    auto found = rule_vars_.find(o);
    if (found != rule_vars_.end())
      return found->second;
    return NULL;
  }

  bool PickRule(StringPiece output, Rule** r, Vars** v) {
    Rule* rule = LookupRule(output);
    Vars* vars = LookupRuleVars(output);
    *r = rule;
    *v = vars;
    if (rule) {
      if (!rule->cmds.empty()) {
        return true;
      }
    }
    return rule;
  }

  DepNode* BuildPlan(StringPiece output, StringPiece needed_by, Vars* tsvs) {
    LOG("BuildPlan: %s for %s",
        output.as_string().c_str(),
        needed_by.as_string().c_str());

    auto found = done_.find(output);
    if (found != done_.end()) {
      return found->second;
    }

    DepNode* n = new DepNode(output, phony_[output]);
    done_[output] = n;

    Rule* rule;
    Vars* vars;
    if (!PickRule(output, &rule, &vars)) {
      return n;
    }

    // TODO: Handle TSVs

    for (StringPiece input : rule->inputs) {
      if (rule->output_patterns.size() > 0) {
        if (rule->output_patterns.size() > 1) {
          ERROR("TODO: multiple output pattern is not supported yet");
        }
        ERROR("TODO");
      }

      n->actual_inputs.push_back(input);
      DepNode* c = BuildPlan(input, output, tsvs);
      n->deps.push_back(c);
    }

    // TODO: order only
    n->has_rule = true;
    n->cmds = rule->cmds;

    return n;
  }

  unordered_map<StringPiece, Rule*> rules_;
  const Vars& vars_;
  const unordered_map<StringPiece, Vars*>& rule_vars_;

  vector<Rule*> implicit_rules_;   // pattern=%. no prefix,suffix.
  //vector<Rule*> iprefix_rules_;   // pattern=prefix%..  may have suffix
  //vector<Rule*> isuffix_rules_;   // pattern=%suffix  no prefix

  unordered_map<StringPiece, vector<Rule*>> suffix_rules_;
  Rule* first_rule_;
  unordered_map<StringPiece, DepNode*> done_;
  unordered_map<StringPiece, bool> phony_;
};

void MakeDep(const vector<Rule*>& rules,
             const Vars& vars,
             const unordered_map<StringPiece, Vars*>& rule_vars,
             const vector<StringPiece>& targets,
             vector<DepNode*>* nodes) {
  DepBuilder db(rules, vars, rule_vars);
  db.Build(targets, nodes);
}

void InitDepNodePool() {
  g_dep_node_pool = new vector<DepNode*>;
}

void QuitDepNodePool() {
  for (DepNode* n : *g_dep_node_pool)
    delete n;
  delete g_dep_node_pool;
}
