// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "clean.h"

#include <assert.h>
#include <stdio.h>

#include "disk_interface.h"
#include "graph.h"
#include "state.h"
#include "util.h"

Cleaner::Cleaner(State* state,
                 const BuildConfig& config,
                 DiskInterface* disk_interface)
  : state_(state),
    config_(config),
    removed_(),
    cleaned_(),
    cleaned_files_count_(0),
    disk_interface_(disk_interface),
    status_(0) {
}

int Cleaner::RemoveFile(const string& path) {
  return disk_interface_->RemoveFile(path);
}

bool Cleaner::FileExists(const string& path) {
  string err;
  TimeStamp mtime = disk_interface_->Stat(path, &err);
  if (mtime == -1)
    Error("%s", err.c_str());
  return mtime > 0;  // Treat Stat() errors as "file does not exist".
}

void Cleaner::Report(const string& path) {
  ++cleaned_files_count_;
  if (IsVerbose())
    printf("Remove %s\n", path.c_str());
}

void Cleaner::Remove(const string& path) {
  if (!IsAlreadyRemoved(path)) {
    removed_.insert(path);
    if (config_.dry_run) {
      if (FileExists(path))
        Report(path);
    } else {
      int ret = RemoveFile(path);
      if (ret == 0)
        Report(path);
      else if (ret == -1)
        status_ = 1;
    }
  }
}

bool Cleaner::IsAlreadyRemoved(const string& path) {
  set<string>::iterator i = removed_.find(path);
  return (i != removed_.end());
}

void Cleaner::RemoveEdgeFiles(Edge* edge) {
  string depfile = edge->GetUnescapedDepfile();
  if (!depfile.empty())
    Remove(depfile);

  string rspfile = edge->GetUnescapedRspfile();
  if (!rspfile.empty())
    Remove(rspfile);
}

void Cleaner::PrintHeader() {
  if (config_.verbosity == BuildConfig::QUIET)
    return;
  printf("Cleaning...");
  if (IsVerbose())
    printf("\n");
  else
    printf(" ");
  fflush(stdout);
}

void Cleaner::PrintFooter() {
  if (config_.verbosity == BuildConfig::QUIET)
    return;
  printf("%d files.\n", cleaned_files_count_);
}

int Cleaner::CleanAll(bool generator) {
  Reset();
  PrintHeader();
  for (vector<Edge*>::iterator e = state_->edges_.begin();
       e != state_->edges_.end(); ++e) {
    // Do not try to remove phony targets
    if ((*e)->is_phony())
      continue;
    // Do not remove generator's files unless generator specified.
    if (!generator && (*e)->GetBindingBool("generator"))
      continue;
    for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
         out_node != (*e)->outputs_.end(); ++out_node) {
      Remove((*out_node)->path());
    }

    RemoveEdgeFiles(*e);
  }
  PrintFooter();
  return status_;
}

void Cleaner::DoCleanTarget(Node* target) {
  if (Edge* e = target->in_edge()) {
    // Do not try to remove phony targets
    if (!e->is_phony()) {
      Remove(target->path());
      RemoveEdgeFiles(e);
    }
    for (vector<Node*>::iterator n = e->inputs_.begin(); n != e->inputs_.end();
         ++n) {
      Node* next = *n;
      // call DoCleanTarget recursively if this node has not been visited
      if (cleaned_.count(next) == 0) {
        DoCleanTarget(next);
      }
    }
  }

  // mark this target to be cleaned already
  cleaned_.insert(target);
}

int Cleaner::CleanTarget(Node* target) {
  assert(target);

  Reset();
  PrintHeader();
  DoCleanTarget(target);
  PrintFooter();
  return status_;
}

int Cleaner::CleanTarget(const char* target) {
  assert(target);

  Reset();
  Node* node = state_->LookupNode(target);
  if (node) {
    CleanTarget(node);
  } else {
    Error("unknown target '%s'", target);
    status_ = 1;
  }
  return status_;
}

int Cleaner::CleanTargets(int target_count, char* targets[]) {
  Reset();
  PrintHeader();
  for (int i = 0; i < target_count; ++i) {
    string target_name = targets[i];
    uint64_t slash_bits;
    string err;
    if (!CanonicalizePath(&target_name, &slash_bits, &err)) {
      Error("failed to canonicalize '%s': %s", target_name.c_str(), err.c_str());
      status_ = 1;
    } else {
      Node* target = state_->LookupNode(target_name);
      if (target) {
        if (IsVerbose())
          printf("Target %s\n", target_name.c_str());
        DoCleanTarget(target);
      } else {
        Error("unknown target '%s'", target_name.c_str());
        status_ = 1;
      }
    }
  }
  PrintFooter();
  return status_;
}

void Cleaner::DoCleanRule(const Rule* rule) {
  assert(rule);

  for (vector<Edge*>::iterator e = state_->edges_.begin();
       e != state_->edges_.end(); ++e) {
    if ((*e)->rule().name() == rule->name()) {
      for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
           out_node != (*e)->outputs_.end(); ++out_node) {
        Remove((*out_node)->path());
        RemoveEdgeFiles(*e);
      }
    }
  }
}

int Cleaner::CleanRule(const Rule* rule) {
  assert(rule);

  Reset();
  PrintHeader();
  DoCleanRule(rule);
  PrintFooter();
  return status_;
}

int Cleaner::CleanRule(const char* rule) {
  assert(rule);

  Reset();
  const Rule* r = state_->bindings_.LookupRule(rule);
  if (r) {
    CleanRule(r);
  } else {
    Error("unknown rule '%s'", rule);
    status_ = 1;
  }
  return status_;
}

int Cleaner::CleanRules(int rule_count, char* rules[]) {
  assert(rules);

  Reset();
  PrintHeader();
  for (int i = 0; i < rule_count; ++i) {
    const char* rule_name = rules[i];
    const Rule* rule = state_->bindings_.LookupRule(rule_name);
    if (rule) {
      if (IsVerbose())
        printf("Rule %s\n", rule_name);
      DoCleanRule(rule);
    } else {
      Error("unknown rule '%s'", rule_name);
      status_ = 1;
    }
  }
  PrintFooter();
  return status_;
}

void Cleaner::Reset() {
  status_ = 0;
  cleaned_files_count_ = 0;
  removed_.clear();
  cleaned_.clear();
}
