// 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.common.data;

import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Comment;
import com.google.gerrit.reviewdb.client.PatchSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CommentDetail {
  protected List<Comment> a;
  protected List<Comment> b;

  private transient PatchSet.Id idA;
  private transient PatchSet.Id idB;
  private transient Map<Integer, List<Comment>> forA;
  private transient Map<Integer, List<Comment>> forB;

  public CommentDetail(PatchSet.Id idA, PatchSet.Id idB) {
    this.a = new ArrayList<>();
    this.b = new ArrayList<>();
    this.idA = idA;
    this.idB = idB;
  }

  protected CommentDetail() {}

  public void include(Change.Id changeId, Comment p) {
    PatchSet.Id psId = new PatchSet.Id(changeId, p.key.patchSetId);
    if (p.side == 0) {
      if (idA == null && idB.equals(psId)) {
        a.add(p);
      }
    } else if (p.side == 1) {
      if (idA != null && idA.equals(psId)) {
        a.add(p);
      } else if (idB.equals(psId)) {
        b.add(p);
      }
    }
  }

  public List<Comment> getCommentsA() {
    return a;
  }

  public List<Comment> getCommentsB() {
    return b;
  }

  public boolean isEmpty() {
    return a.isEmpty() && b.isEmpty();
  }

  public List<Comment> getForA(int lineNbr) {
    if (forA == null) {
      forA = index(a);
    }
    return get(forA, lineNbr);
  }

  public List<Comment> getForB(int lineNbr) {
    if (forB == null) {
      forB = index(b);
    }
    return get(forB, lineNbr);
  }

  private static List<Comment> get(Map<Integer, List<Comment>> m, int i) {
    List<Comment> r = m.get(i);
    return r != null ? orderComments(r) : Collections.emptyList();
  }

  /**
   * Order the comments based on their parent_uuid parent. It is possible to do this by iterating
   * over the list only once but it's probably overkill since the number of comments on a given line
   * will be small most of the time.
   *
   * @param comments The list of comments for a given line.
   * @return The comments sorted as they should appear in the UI
   */
  private static List<Comment> orderComments(List<Comment> comments) {
    // Map of comments keyed by their parent. The values are lists of comments since it is
    // possible for several comments to have the same parent (this can happen if two reviewers
    // click Reply on the same comment at the same time). Such comments will be displayed under
    // their correct parent in chronological order.
    Map<String, List<Comment>> parentMap = new HashMap<>();

    // It's possible to have more than one root comment if two reviewers create a comment on the
    // same line at the same time
    List<Comment> rootComments = new ArrayList<>();

    // Store all the comments in parentMap, keyed by their parent
    for (Comment c : comments) {
      String parentUuid = c.parentUuid;
      List<Comment> l = parentMap.get(parentUuid);
      if (l == null) {
        l = new ArrayList<>();
        parentMap.put(parentUuid, l);
      }
      l.add(c);
      if (parentUuid == null) {
        rootComments.add(c);
      }
    }

    // Add the comments in the list, starting with the head and then going through all the
    // comments that have it as a parent, and so on
    List<Comment> result = new ArrayList<>();
    addChildren(parentMap, rootComments, result);

    return result;
  }

  /** Add the comments to {@code outResult}, depth first */
  private static void addChildren(
      Map<String, List<Comment>> parentMap, List<Comment> children, List<Comment> outResult) {
    if (children != null) {
      for (Comment c : children) {
        outResult.add(c);
        addChildren(parentMap, parentMap.get(c.key.uuid), outResult);
      }
    }
  }

  private Map<Integer, List<Comment>> index(List<Comment> in) {
    HashMap<Integer, List<Comment>> r = new HashMap<>();
    for (Comment p : in) {
      List<Comment> l = r.get(p.lineNbr);
      if (l == null) {
        l = new ArrayList<>();
        r.put(p.lineNbr, l);
      }
      l.add(p);
    }
    return r;
  }
}
