// 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.client.ui;

import com.google.gerrit.client.FormatUtil;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.common.data.AccountInfo;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;

import java.util.Date;

public class CommentPanel extends Composite implements HasDoubleClickHandlers {
  private static final int SUMMARY_LENGTH = 75;
  private final FlexTable header;
  private final InlineLabel messageSummary;
  private final FlowPanel content;
  private final DoubleClickHTML messageText;
  private FlowPanel buttons;
  private boolean recent;

  public CommentPanel(final AccountInfo author, final Date when, String message) {
    this();

    setMessageText(message);
    setAuthorNameText(FormatUtil.name(author));
    setDateText(FormatUtil.shortFormat(when));

    final CellFormatter fmt = header.getCellFormatter();
    fmt.getElement(0, 0).setTitle(FormatUtil.nameEmail(author));
    fmt.getElement(0, 2).setTitle(FormatUtil.mediumFormat(when));
  }

  protected CommentPanel() {
    final FlowPanel body = new FlowPanel();
    initWidget(body);
    setStyleName(Gerrit.RESOURCES.css().commentPanel());

    messageSummary = new InlineLabel();
    messageSummary.setStyleName(Gerrit.RESOURCES.css().commentPanelSummary());

    header = new FlexTable();
    header.setStyleName(Gerrit.RESOURCES.css().commentPanelHeader());
    header.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        setOpen(!isOpen());
      }
    });
    header.setText(0, 0, "");
    header.setWidget(0, 1, messageSummary);
    header.setText(0, 2, "");
    final CellFormatter fmt = header.getCellFormatter();
    fmt.setStyleName(0, 0, Gerrit.RESOURCES.css().commentPanelAuthorCell());
    fmt.setStyleName(0, 1, Gerrit.RESOURCES.css().commentPanelSummaryCell());
    fmt.setStyleName(0, 2, Gerrit.RESOURCES.css().commentPanelDateCell());
    fmt.setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_RIGHT);
    body.add(header);

    content = new FlowPanel();
    content.setStyleName(Gerrit.RESOURCES.css().commentPanelContent());
    content.setVisible(false);
    body.add(content);

    messageText = new DoubleClickHTML();
    messageText.setStyleName(Gerrit.RESOURCES.css().commentPanelMessage());
    content.add(messageText);
  }

  @Override
  public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
    return messageText.addDoubleClickHandler(handler);
  }

  protected void setMessageText(String message) {
    if (message == null) {
      message = "";
    } else {
      message = message.trim();
    }

    messageSummary.setText(summarize(message));
    SafeHtml buf = new SafeHtmlBuilder().append(message).wikify();
    buf = CommentLinkProcessor.apply(buf);
    SafeHtml.set(messageText, buf);
  }

  public void setAuthorNameText(final String nameText) {
    header.setText(0, 0, nameText);
  }

  protected void setDateText(final String dateText) {
    header.setText(0, 2, dateText);
  }

  protected void setMessageTextVisible(final boolean show) {
    messageText.setVisible(show);
  }

  protected void addContent(final Widget w) {
    if (buttons != null) {
      content.insert(w, content.getWidgetIndex(buttons));
    } else {
      content.add(w);
    }
  }

  protected Panel getButtonPanel() {
    if (buttons == null) {
      buttons = new FlowPanel();
      buttons.setStyleName(Gerrit.RESOURCES.css().commentPanelButtons());
      content.add(buttons);
    }
    return buttons;
  }

  private static String summarize(final String message) {
    if (message.length() < SUMMARY_LENGTH) {
      return message;
    }

    int p = 0;
    final StringBuilder r = new StringBuilder();
    while (r.length() < SUMMARY_LENGTH) {
      final int e = message.indexOf(' ', p);
      if (e < 0) {
        break;
      }

      final String word = message.substring(p, e).trim();
      if (SUMMARY_LENGTH <= r.length() + word.length() + 1) {
        break;
      }
      if (r.length() > 0) {
        r.append(' ');
      }
      r.append(word);
      p = e + 1;
    }
    r.append(" \u2026");
    return r.toString();
  }

  public boolean isOpen() {
    return content.isVisible();
  }

  public void setOpen(final boolean open) {
    messageSummary.setVisible(!open);
    content.setVisible(open);
  }

  public boolean isRecent() {
    return recent;
  }

  public void setRecent(final boolean r) {
    recent = r;
  }

  private static class DoubleClickHTML extends HTML implements
      HasDoubleClickHandlers {
    public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
      return addDomHandler(handler, DoubleClickEvent.getType());
    }
  }
}
