// Copyright (C) 2009 The Android Open Source Project
//
// 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.

package com.google.gerrit.server.patch;

import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.flogger.FluentLogger;
import com.google.gerrit.git.ObjectIds;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.text.SimpleDateFormat;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.util.RawParseUtils;
import org.mozilla.universalchardet.UniversalDetector;

public class Text extends RawText {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  private static final int bigFileThreshold = PackConfig.DEFAULT_BIG_FILE_THRESHOLD;

  public static final byte[] NO_BYTES = {};
  public static final Text EMPTY = new Text(NO_BYTES);

  public static Text forCommit(ObjectReader reader, AnyObjectId commitId) throws IOException {
    try (RevWalk rw = new RevWalk(reader)) {
      RevCommit c;
      if (commitId instanceof RevCommit) {
        c = (RevCommit) commitId;
      } else {
        c = rw.parseCommit(commitId);
      }

      StringBuilder b = new StringBuilder();
      switch (c.getParentCount()) {
        case 0:
          break;
        case 1:
          {
            RevCommit p = c.getParent(0);
            rw.parseBody(p);
            b.append("Parent:     ");
            b.append(abbreviateName(p, reader));
            b.append(" (");
            b.append(p.getShortMessage());
            b.append(")\n");
            break;
          }
        default:
          for (int i = 0; i < c.getParentCount(); i++) {
            RevCommit p = c.getParent(i);
            rw.parseBody(p);
            b.append(i == 0 ? "Merge Of:   " : "            ");
            b.append(abbreviateName(p, reader));
            b.append(" (");
            b.append(p.getShortMessage());
            b.append(")\n");
          }
      }
      appendPersonIdent(b, "Author", c.getAuthorIdent());
      appendPersonIdent(b, "Commit", c.getCommitterIdent());
      b.append("\n");
      b.append(c.getFullMessage());
      return new Text(b.toString().getBytes(UTF_8));
    }
  }

  public static Text forMergeList(
      ComparisonType comparisonType, ObjectReader reader, AnyObjectId commitId) throws IOException {
    try (RevWalk rw = new RevWalk(reader)) {
      RevCommit c = rw.parseCommit(commitId);
      StringBuilder b = new StringBuilder();
      switch (c.getParentCount()) {
        case 0:
          break;
        case 1:
          {
            break;
          }
        default:
          int uniterestingParent =
              comparisonType.isAgainstParent() ? comparisonType.getParentNum() : 1;

          b.append("Merge List:\n\n");
          for (RevCommit commit : MergeListBuilder.build(rw, c, uniterestingParent)) {
            b.append("* ");
            b.append(abbreviateName(commit, reader));
            b.append(" ");
            b.append(commit.getShortMessage());
            b.append("\n");
          }
      }
      return new Text(b.toString().getBytes(UTF_8));
    }
  }

  private static String abbreviateName(RevCommit p, ObjectReader reader) throws IOException {
    return ObjectIds.abbreviateName(p, 8, reader);
  }

  private static void appendPersonIdent(StringBuilder b, String field, PersonIdent person) {
    if (person != null) {
      b.append(field).append(":    ");
      if (person.getName() != null) {
        b.append(" ");
        b.append(person.getName());
      }
      if (person.getEmailAddress() != null) {
        b.append(" <");
        b.append(person.getEmailAddress());
        b.append(">");
      }
      b.append("\n");

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZ");
      sdf.setTimeZone(person.getTimeZone());
      b.append(field).append("Date: ");
      b.append(sdf.format(person.getWhen()));
      b.append("\n");
    }
  }

  public static byte[] asByteArray(ObjectLoader ldr)
      throws MissingObjectException, LargeObjectException, IOException {
    return ldr.getCachedBytes(bigFileThreshold);
  }

  private static Charset charset(byte[] content, String encoding) {
    if (encoding == null) {
      UniversalDetector d = new UniversalDetector(null);
      d.handleData(content, 0, content.length);
      d.dataEnd();
      encoding = d.getDetectedCharset();
    }
    if (encoding == null) {
      return ISO_8859_1;
    }
    try {
      return Charset.forName(encoding);

    } catch (IllegalCharsetNameException err) {
      logger.atSevere().log("Invalid detected charset name '%s': %s", encoding, err);
      return ISO_8859_1;

    } catch (UnsupportedCharsetException err) {
      logger.atSevere().log("Detected charset '%s' not supported: %s", encoding, err);
      return ISO_8859_1;
    }
  }

  private Charset charset;

  public Text(byte[] r) {
    super(r);
  }

  public Text(ObjectLoader ldr) throws MissingObjectException, LargeObjectException, IOException {
    this(asByteArray(ldr));
  }

  public byte[] getContent() {
    return content;
  }

  @Override
  protected String decode(int s, int e) {
    if (charset == null) {
      charset = charset(content, null);
    }
    return RawParseUtils.decode(charset, content, s, e);
  }
}
