// Copyright 2017-2020 The Verible Authors.
//
// 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 "common/strings/diff.h"

#include <iostream>
#include <vector>

#include "absl/strings/str_split.h"
#include "common/strings/split.h"
#include "common/util/iterator_range.h"
#include "external_libs/editscript.h"

namespace verible {

using diff::Edit;
using diff::Edits;
using diff::Operation;

static char EditOperationToLineMarker(Operation op) {
  switch (op) {
    case Operation::DELETE:
      return '-';
    case Operation::EQUALS:
      return ' ';
    case Operation::INSERT:
      return '+';
    default:
      return '?';
  }
}

LineDiffs::LineDiffs(absl::string_view before, absl::string_view after)
    : before_text(before),
      after_text(after),
      before_lines(SplitLinesKeepLineTerminator(before_text)),
      after_lines(SplitLinesKeepLineTerminator(after_text)),
      edits(diff::GetTokenDiffs(before_lines.begin(), before_lines.end(),
                                after_lines.begin(), after_lines.end())) {}

template <typename Iter>
static std::ostream& PrintLineRange(std::ostream& stream, char op, Iter start,
                                    Iter end) {
  for (const auto& line : make_range(start, end)) {
    stream << op << line;
  }
  return stream;
}

std::ostream& LineDiffs::PrintEdit(std::ostream& stream,
                                   const Edit& edit) const {
  const char op = EditOperationToLineMarker(edit.operation);
  if (edit.operation == Operation::INSERT) {
    PrintLineRange(stream, op, after_lines.begin() + edit.start,
                   after_lines.begin() + edit.end);
    if (after_lines[edit.end - 1].back() != '\n') stream << "\n";
  } else {
    PrintLineRange(stream, op, before_lines.begin() + edit.start,
                   before_lines.begin() + edit.end);
    if (before_lines[edit.end - 1].back() != '\n') stream << "\n";
  }
  stream << std::flush;
  return stream;
}

std::ostream& operator<<(std::ostream& stream, const LineDiffs& diffs) {
  for (const auto& edit : diffs.edits) {
    diffs.PrintEdit(stream, edit);
  }
  return stream;
}

LineNumberSet DiffEditsToAddedLineNumbers(const Edits& edits) {
  LineNumberSet added_lines;
  for (const auto& edit : edits) {
    if (edit.operation == Operation::INSERT) {
      // Add 1 to convert from 0-indexed to 1-indexed.
      added_lines.Add(
          {static_cast<int>(edit.start) + 1, static_cast<int>(edit.end) + 1});
    }
  }
  return added_lines;
}

std::vector<diff::Edits> DiffEditsToPatchHunks(const diff::Edits& edits,
                                               int common_context) {
  const int split_threshold = common_context * 2;
  std::vector<diff::Edits> hunks(1);  // start with 1 empty destination vector
  for (const diff::Edit& edit : edits) {
    auto& current_hunk = hunks.back();
    if (edit.operation == Operation::EQUALS) {
      const int edit_size = edit.end - edit.start;
      if (current_hunk.empty()) {
        // For "end-pieces" (in this case, the head), threshold should be
        // common_context, not split_threshold.
        if (edit_size > common_context) {
          // Add the tail end of this edit.
          current_hunk.push_back(
              diff::Edit{edit.operation, edit.end - common_context, edit.end});
        } else {
          // Add the whole edit.
          current_hunk.push_back(edit);
        }
      } else {  // !current_hunk.empty()
        // We don't know what follows this edit, so this may still be oversized.
        // A final pass will trim excess sizing of EQUALS edits in tail
        // position.
        if (edit_size > split_threshold) {
          // Close off the current hunk.
          current_hunk.push_back(diff::Edit{edit.operation, edit.start,
                                            edit.start + common_context});
          // Start the next hunk.
          hunks.push_back(diff::Edits{
              diff::Edit{edit.operation, edit.end - common_context, edit.end}});
        } else {
          // Add the whole edit.
          current_hunk.push_back(edit);
        }
      }
    } else {  // operation is INSERT or DELETE
      current_hunk.push_back(edit);
    }
  }

  // The last hunk may have been started before knowing it was the last one.
  // Remove if it is a no-op.
  const auto& last_hunk = hunks.back();  // hunks is always non-empty
  if (last_hunk.size() == 1 &&
      last_hunk.front().operation == Operation::EQUALS) {
    // This last hunk's only element is an Operation::EQUALS (no-change),
    // so remove it.
    hunks.pop_back();
  }

  // Trim excess EQUALS tail edits in each hunk.
  for (auto& hunk : hunks) {
    auto& tail = hunk.back();
    if (tail.operation == Operation::EQUALS) {
      if (tail.end - tail.start > common_context) {
        tail.end = tail.start + common_context;
      }
    }
  }
  return hunks;
}

void LineDiffsToUnifiedDiff(std::ostream& stream, const LineDiffs& linediffs,
                            unsigned common_context, absl::string_view file_a,
                            absl::string_view file_b) {
  const std::vector<diff::Edits> chunks =
      DiffEditsToPatchHunks(linediffs.edits, common_context);

  if (chunks.size() == 0) {
    return;
  }

  if (!file_a.empty()) {
    if (file_b.empty()) {
      stream << "--- a/" << file_a << std::endl;
      stream << "+++ b/" << file_a << std::endl;
    } else {
      stream << "--- " << file_a << std::endl;
      stream << "+++ " << file_b << std::endl;
    }
  }

  int added_lines_count = 0;
  for (const auto& chunk : chunks) {
    int chunk_before_lines_count = 0;
    int chunk_added_lines_count = 0;

    for (size_t i = 0; i < chunk.size(); ++i) {
      auto& edit = chunk[i];

      if (edit.operation == Operation::INSERT) {
        chunk_added_lines_count += edit.end - edit.start;
      } else if (edit.operation == Operation::DELETE) {
        chunk_before_lines_count += edit.end - edit.start;
        chunk_added_lines_count -= edit.end - edit.start;
      } else {
        chunk_before_lines_count += edit.end - edit.start;
      }
    }
    const int chunk_after_lines_count =
        chunk_before_lines_count + chunk_added_lines_count;

    // Chunk header
    stream << "@@ -" << (chunk.front().start + 1);
    if (chunk_before_lines_count > 1) stream << "," << chunk_before_lines_count;
    stream << " +" << (chunk.front().start + added_lines_count + 1);
    if (chunk_after_lines_count > 1) stream << "," << chunk_after_lines_count;
    stream << " @@" << std::endl;

    added_lines_count += chunk_added_lines_count;

    for (const auto& edit : chunk) {
      linediffs.PrintEdit(stream, edit);

      // Last line from either original or new text, and final '\n' is missing?
      if ((edit.operation != Operation::INSERT &&
           size_t(edit.end) == linediffs.before_lines.size() &&
           linediffs.before_text.back() != '\n') ||
          (edit.operation == Operation::INSERT &&
           size_t(edit.end) == linediffs.after_lines.size() &&
           linediffs.after_text.back() != '\n')) {
        stream << "\\ No newline at end of file" << std::endl;
      }
    }
  }
}

}  // namespace verible
