// Copyright (C) 2013 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.client.change;

import com.google.gerrit.client.AvatarImage;
import com.google.gerrit.client.FormatUtil;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.info.ChangeInfo.MessageInfo;
import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

class Message extends Composite {
  interface Binder extends UiBinder<HTMLPanel, Message> {}
  private static final Binder uiBinder = GWT.create(Binder.class);

  static interface Style extends CssResource {
    String closed();
  }

  @UiField Style style;
  @UiField HTMLPanel header;
  @UiField Element name;
  @UiField Element summary;
  @UiField Element date;
  @UiField Button reply;
  @UiField Element message;
  @UiField FlowPanel comments;

  private final History history;
  private final MessageInfo info;
  private List<CommentInfo> commentList;
  private boolean autoOpen;

  @UiField(provided = true)
  AvatarImage avatar;

  Message(History parent, MessageInfo info) {
    if (info.author() != null) {
      avatar = new AvatarImage(info.author());
      avatar.setSize("", "");
    } else {
      avatar = new AvatarImage();
    }

    initWidget(uiBinder.createAndBindUi(this));
    header.addDomHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        setOpen(!isOpen());
      }
    }, ClickEvent.getType());

    this.history = parent;
    this.info = info;

    setName(false);
    date.setInnerText(FormatUtil.shortFormatDayTime(info.date()));
    if (info.message() != null) {
      String msg = info.message().trim();
      summary.setInnerText(msg);
      message.setInnerSafeHtml(history.getCommentLinkProcessor()
        .apply(new SafeHtmlBuilder().append(msg).wikify()));
    } else {
      reply.getElement().getStyle().setVisibility(Visibility.HIDDEN);
    }
  }

  @UiHandler("reply")
  void onReply(ClickEvent e) {
    e.stopPropagation();

    if (Gerrit.isSignedIn()) {
      history.replyTo(info);
    } else {
      Gerrit.doSignIn(com.google.gwt.user.client.History.getToken());
    }
  }

  MessageInfo getMessageInfo() {
    return info;
  }

  private boolean isOpen() {
    return UIObject.isVisible(message);
  }

  void setOpen(boolean open) {
    if (open && info._revisionNumber() > 0 && !commentList.isEmpty()) {
      renderComments(commentList);
      commentList = Collections.emptyList();
    }
    setName(open);

    UIObject.setVisible(summary, !open);
    UIObject.setVisible(message, open);
    comments.setVisible(open && comments.getWidgetCount() > 0);
    if (open) {
      removeStyleName(style.closed());
    } else {
      addStyleName(style.closed());
    }
  }

  private void setName(boolean open) {
    name.setInnerText(open
        ? authorName(info)
        : com.google.gerrit.common.FormatUtil.elide(authorName(info), 20));
  }

  void autoOpen() {
    if (commentList == null) {
      autoOpen = true;
    } else if (!commentList.isEmpty()) {
      setOpen(true);
    }
  }

  void addComments(List<CommentInfo> list) {
    if (isOpen()) {
      renderComments(list);
      comments.setVisible(comments.getWidgetCount() > 0);
      commentList = Collections.emptyList();
    } else {
      commentList = list;
      if (autoOpen && !commentList.isEmpty()) {
        setOpen(true);
      }
    }
  }

  private void renderComments(List<CommentInfo> list) {
    CommentLinkProcessor clp = history.getCommentLinkProcessor();
    PatchSet.Id ps = new PatchSet.Id(
        history.getChangeId(),
        info._revisionNumber());
    TreeMap<String, List<CommentInfo>> m = byPath(list);
    List<CommentInfo> l = m.remove(Patch.COMMIT_MSG);
    if (l != null) {
      comments.add(new FileComments(clp, ps, Util.C.commitMessage(), l));
    }
    for (Map.Entry<String, List<CommentInfo>> e : m.entrySet()) {
      comments.add(new FileComments(clp, ps, e.getKey(), e.getValue()));
    }
  }

  private static TreeMap<String, List<CommentInfo>>
  byPath(List<CommentInfo> list) {
    TreeMap<String, List<CommentInfo>> m = new TreeMap<>();
    for (CommentInfo c : list) {
      List<CommentInfo> l = m.get(c.path());
      if (l == null) {
        l = new ArrayList<>();
        m.put(c.path(), l);
      }
      l.add(c);
    }
    return m;
  }

  static String authorName(MessageInfo info) {
    if (info.author() != null) {
      if (info.author().name() != null) {
        return info.author().name();
      }
      return Gerrit.info().user().anonymousCowardName();
    }
    return Util.C.messageNoAuthor();
  }
}
