// Copyright (C) 2008 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.Gerrit;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtml;

import java.util.Comparator;
import java.util.Iterator;

public abstract class FancyFlexTable<RowItem> extends Composite {
  private static final FancyFlexTableImpl impl =
      GWT.create(FancyFlexTableImpl.class);

  protected static final int C_ARROW = 0;

  protected final MyFlexTable table;

  protected FancyFlexTable() {
    table = createFlexTable();
    table.addStyleName(Gerrit.RESOURCES.css().changeTable());
    table.setWidth("100%");
    initWidget(table);

    table.setText(0, C_ARROW, "");
    table.getCellFormatter().addStyleName(0, C_ARROW, Gerrit.RESOURCES.css().iconHeader());
  }

  protected MyFlexTable createFlexTable() {
    return new MyFlexTable();
  }

  protected RowItem getRowItem(final int row) {
    return FancyFlexTable.<RowItem> getRowItem(table.getCellFormatter()
        .getElement(row, 0));
  }

  protected void setRowItem(final int row, final RowItem item) {
    setRowItem(table.getCellFormatter().getElement(row, 0), item);
  }

  /**
   * Finds an item in the table.
   *
   * @param comparator comparator by which the items in the table are sorted
   * @param item the item that should be found
   * @return if the item is found the number of the row that contains the item;
   *         if the item is not found <code>-1</code>
   */
  protected int findRowItem(Comparator<RowItem> comparator, RowItem item) {
    int row = lookupRowItem(comparator, item);
    if (row < table.getRowCount()
        && comparator.compare(item, getRowItem(row)) == 0) {
      return row;
    }
    return -1;
  }

  /**
   * Finds the number of the row where a new item should be inserted into the
   * table.
   *
   * @param comparator comparator by which the items in the table are sorted
   * @param item the new item that should be inserted
   * @return if the item is not yet contained in the table, the number of the
   *         row where the new item should be inserted; if the item is already
   *         contained in the table <code>-1</code>
   */
  protected int getInsertRow(Comparator<RowItem> comparator, RowItem item) {
    int row = lookupRowItem(comparator, item);
    if (row >= table.getRowCount()
        || comparator.compare(item, getRowItem(row)) != 0) {
      return row;
    }
    return -1;
  }

  /**
   * Makes a binary search for the given row item over the table.
   *
   * @param comparator comparator by which the items in the table are sorted
   * @param item the item that should be looked up
   * @return if the item is found the number of the row that contains the item;
   *         if the item is not found the number of the row where the item
   *         should be inserted according to the given comparator.
   */
  private int lookupRowItem(Comparator<RowItem> comparator, RowItem item) {
    int left = 1;
    int right = table.getRowCount() - 1;
    while (left <= right) {
      int middle = (left + right) >>> 1; // (left+right)/2
      RowItem i = getRowItem(middle);
      int cmp = comparator.compare(i, item);

      if (cmp < 0) {
        left = middle + 1;
      } else if (cmp > 0) {
        right = middle - 1;
      } else {
        // item is already contained in the table
        return middle;
      }
    }
    return left;
  }

  protected void resetHtml(final SafeHtml body) {
    for (final Iterator<Widget> i = table.iterator(); i.hasNext();) {
      i.next();
      i.remove();
    }
    impl.resetHtml(table, body);
  }

  protected void scrollIntoView(final int topRow, final int endRow) {
    final CellFormatter fmt = table.getCellFormatter();
    final Element top = DOM.getParent(fmt.getElement(topRow, C_ARROW));
    final Element end = DOM.getParent(fmt.getElement(endRow, C_ARROW));

    final int rTop = top.getAbsoluteTop();
    final int rEnd = end.getAbsoluteTop() + end.getOffsetHeight();
    final int rHeight = rEnd - rTop;

    final int sTop = Document.get().getScrollTop();
    final int sHeight = Document.get().getClientHeight();
    final int sEnd = sTop + sHeight;

    final int nTop;
    if (sHeight <= rHeight) {
      // The region is larger than the visible area, make the top
      // exactly the top of the region, its the most visible area.
      //
      nTop = rTop;
    } else if (sTop <= rTop && rTop <= sEnd) {
      // At least part of the region is already visible.
      //
      if (rEnd <= sEnd) {
        // ... actually its all visible. Don't scroll.
        //
        return;
      }

      // Move only enough to make the end visible.
      //
      nTop = sTop + (rHeight - (sEnd - rTop));
    } else {
      // None of the region is visible. Make it visible.
      //
      nTop = rTop;
    }
    Document.get().setScrollTop(nTop);
  }

  protected void applyDataRowStyle(final int newRow) {
    table.getCellFormatter().addStyleName(newRow, C_ARROW, Gerrit.RESOURCES.css().iconCell());
    table.getCellFormatter().addStyleName(newRow, C_ARROW, Gerrit.RESOURCES.css().leftMostCell());
  }

  /**
   * Get the td element that contains another element.
   *
   * @param target the child element whose parent td is required.
   * @return the td containing element {@code target}; null if {@code target} is
   *         not a member of this table.
   */
  protected Element getParentCell(final Element target) {
    final Element body = FancyFlexTableImpl.getBodyElement(table);
    for (Element td = target; td != null && td != body; td = DOM.getParent(td)) {
      // If it's a TD, it might be the one we're looking for.
      if ("td".equalsIgnoreCase(td.getTagName())) {
        // Make sure it's directly a part of this table.
        Element tr = DOM.getParent(td);
        if (DOM.getParent(tr) == body) {
          return td;
        }
      }
    }
    return null;
  }

  /** @return the row of the child element; -1 if the child is not in the table. */
  protected int rowOf(final Element target) {
    final Element td = getParentCell(target);
    if (td == null) {
      return -1;
    }
    final Element tr = DOM.getParent(td);
    final Element body = DOM.getParent(tr);
    return DOM.getChildIndex(body, tr);
  }

  /** @return the cell of the child element; -1 if the child is not in the table. */
  protected int columnOf(final Element target) {
    final Element td = getParentCell(target);
    if (td == null) {
      return -1;
    }
    final Element tr = DOM.getParent(td);
    return DOM.getChildIndex(tr, td);
  }

  protected static class MyFlexTable extends FlexTable {
  }

  private static final native <ItemType> void setRowItem(Element td, ItemType c)
  /*-{ td['__gerritRowItem'] = c; }-*/;

  private static final native <ItemType> ItemType getRowItem(Element td)
  /*-{ return td['__gerritRowItem']; }-*/;
}
