package org.gcube.portlets.admin.authportletmanager.client.pagelayout;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.AbstractCellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.Header;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;

/**
 * ResizableHeader for DataGrid
 * 
 * @author "Alessandro Pieve " <a
 *         href="mailto:alessandro.pieve@isti.cnr.it">alessandro.pieve@isti.cnr.it</a>
 * 
 */


public class ResizableHeader<T> extends Header<String> {

  private Column<T, ?> column = null;
  private AbstractCellTable<T> cellTable;
  private String title = "";
  private static final int width = 20;

  public ResizableHeader(String title, AbstractCellTable<T> cellTable, Column<T, ?> column) {
    super(new HeaderCell());
    this.title = title;
    this.cellTable = cellTable;
    this.column = column;
  }

  @Override
  public String getValue() {
    return title;
  }

  @Override
  public void onBrowserEvent(Context context, Element target, NativeEvent event) {
    String eventType = event.getType();
    if (eventType.equals("mousemove")) {
      new ColumnResizeHelper<T>(cellTable, column, target);
    } else {
      return;
    }
  }

  private void setCursor(Element element, Cursor cursor) {
    element.getStyle().setCursor(cursor);
  }

  class ColumnResizeHelper<E> implements NativePreviewHandler {

    private HandlerRegistration handler;
    private AbstractCellTable<E> table;
    private Column<E, ?> col;
    private Element el;
    private boolean mousedown;
    private Element measuringElement;

    public ColumnResizeHelper(AbstractCellTable<E> table, Column<E, ?> col, Element el) {
      this.el = el;
      this.table = table;
      this.col = col;
      handler = Event.addNativePreviewHandler(this);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onPreviewNativeEvent(NativePreviewEvent event) {
      NativeEvent nativeEvent = event.getNativeEvent();
      nativeEvent.preventDefault();
      nativeEvent.stopPropagation();

      String eventType = nativeEvent.getType();
      int clientX = nativeEvent.getClientX();
      if (eventType.equals("mousemove") && mousedown) {
        int absoluteLeft = el.getAbsoluteLeft();
        int newWidth = clientX - absoluteLeft;
        newWidth = newWidth < width ? width : newWidth;
        table.setColumnWidth(col, newWidth + "px");
        return;
      }

      if (eventType.equals("mousemove") || eventType.equals("mousedown")) {
        Element eventTargetEl = nativeEvent.getEventTarget().cast();
        int absoluteLeft = eventTargetEl.getAbsoluteLeft();
        int offsetWidth = eventTargetEl.getOffsetWidth();
        if (clientX > absoluteLeft + offsetWidth - width) {
          if (eventType.equals("mousedown")) {
            mousedown = true;
          } else {
            setCursor(el, Cursor.COL_RESIZE);
          }
        } else {
          removeHandler();
          return;
        }
      } else if (eventType.equals("mouseup")) {
        mousedown = false;
      } else if (eventType.equals("mouseout") && !mousedown) {
        removeHandler();
        return;
      }

      if (eventType.equals("dblclick")) {
        // Get column
        nativeEvent.preventDefault();
        nativeEvent.stopPropagation();
        double max = 0;
        startMeasuring();
        for (E t : table.getVisibleItems()) {
          Object value = col.getValue(t);
          SafeHtmlBuilder sb = new SafeHtmlBuilder();
          Cell<Object> cell = (Cell<Object>) col.getCell();
          cell.render(null, value, sb);
          max = Math.max(measureText(sb.toSafeHtml().asString()), max);
        }
        finishMeasuring();
        table.setColumnWidth(col, (max + width) + "px");
        removeHandler();
      }
    }

    private void removeHandler() {
      handler.removeHandler();
      setCursor(el, Cursor.DEFAULT);
    }
    
    private void startMeasuring() {
      Document document = Document.get();
      measuringElement = document.createElement("div");
      measuringElement.getStyle().setPosition(Position.ABSOLUTE);
      measuringElement.getStyle().setLeft(-1000, Unit.PX);
      measuringElement.getStyle().setTop(-1000, Unit.PX);
      document.getBody().appendChild(measuringElement);
    }

    private double measureText(String text) {
      measuringElement.setInnerHTML(text);
      return measuringElement.getOffsetWidth();
    }
    
    private void finishMeasuring() {
      Document.get().getBody().removeChild(measuringElement);
    }
  }

  static class HeaderCell extends AbstractCell<String> {
    public HeaderCell() {
      super("click", "mousedown", "mousemove", "dblclick");
    }

    @Override
    public void render(Context context, String value, SafeHtmlBuilder sb) {
      sb.append(SafeHtmlUtils.fromString(value));
    }
  }
};