package com.vaadin.components.grid;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.query.client.GQuery;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.RootPanel;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.WidgetUtil;

public class ViolatedGrid extends com.vaadin.client.widgets.Grid<Object> {

    public ViolatedGrid() {
        super();
        // This is needed for detecting the correct native scrollbar size in
        // (OS X) Chrome [https://github.com/vaadin/components/issues/30]
        if (BrowserInfo.get().isChrome()) {
            setWidgetUtilNativeScrollbarSize(getWidgetUtilNativeScrollbarSize());
        }

        if (WidgetUtil.getNativeScrollbarSize() == 0) {
            // "invisible" scrollbars
            if (BrowserInfo.get().isSafari()) {
                // This hack is needed to fix scrollbars for OS X Safari
                // [https://github.com/vaadin/components/issues/28]
                //
                // Dynamic scrollbars refuse to work on the stacking root
                // directly so
                // the wrapper is needed for creating an additional stacking
                // context.
                GQuery scrollers = GQuery
                        .$(".v-grid-scroller", this)
                        .css("position", "relative")
                        .wrap("<div style='position: absolute; z-index: 10' />");
                scrollers.filter(".v-grid-scroller-vertical").parent()
                        .css("right", "0");
                scrollers.filter(".v-grid-scroller-horizontal").parent()
                        .css("bottom", "0");
            } else if (BrowserInfo.get().isChrome()) {
                // Fix for [https://github.com/vaadin/components/issues/29]
                GQuery.$(".v-grid-scroller", this).attr("invisible", "");
            }
        }
    }

    public native boolean refreshHeader()
    /*-{
        this.@com.vaadin.client.widgets.Grid::refreshHeader()();
    }-*/;

    public native boolean refreshFooter()
    /*-{
      this.@com.vaadin.client.widgets.Grid::refreshFooter()();
    }-*/;

    public void refreshStaticSection(StaticSection.StaticCell cell) {
        if (cell instanceof HeaderCell) {
            refreshHeader();
        } else {
            refreshFooter();
        }
    }

    /**
     * The method is overridden for now to avoid IE related bugs and performance
     * issues.
     */
    @Override
    public void setHeightByRows(double bodyRows)
            throws IllegalArgumentException {
        // Header height
        double headerRowHeight = getEscalator().getHeader()
                .getDefaultRowHeight();
        int headerRows = isHeaderVisible() ? getHeaderRowCount() : 0;
        double headerHeight = headerRowHeight * headerRows;

        // Body height
        double bodyRowHeight = getEscalator().getBody().getDefaultRowHeight();
        double bodyHeight = bodyRowHeight * bodyRows;

        // Footer height
        double footerRowHeight = getEscalator().getFooter()
                .getDefaultRowHeight();
        int footerRows = isFooterVisible() ? getFooterRowCount() : 0;
        double footerHeight = footerRowHeight * footerRows;

        setHeight(headerHeight + bodyHeight + footerHeight + "px");
    }

    private static native void setWidgetUtilNativeScrollbarSize(int size)
    /*-{
      @com.vaadin.client.WidgetUtil::detectedScrollbarSize = size;
    }-*/;

    private static int getWidgetUtilNativeScrollbarSize() {
        // Using an iFrame to calculate the native scrollbar size
        IFrameElement iFrame = IFrameElement.as(DOM.createIFrame());
        iFrame.getStyle().setProperty("position", "absolute");
        iFrame.getStyle().setProperty("marginLeft", "-5000px");
        RootPanel.getBodyElement().appendChild(iFrame);
        Document contentDocument = iFrame.getContentDocument();

        Element scroller = contentDocument.createElement("div");
        scroller.getStyle().setProperty("width", "50px");
        scroller.getStyle().setProperty("height", "50px");
        scroller.getStyle().setProperty("overflow", "scroll");
        contentDocument.getBody().appendChild(scroller);

        int detectedScrollbarSize = scroller.getOffsetWidth()
                - scroller.getPropertyInt("clientWidth");
        RootPanel.getBodyElement().removeChild(iFrame);

        return detectedScrollbarSize;
    }

    @Override
    public void onBrowserEvent(Event event) {
        // clicking on the select all checkbox moves focus away from the grid
        // causing the :focus transition effect to be reapplied. Forcing focus on the grid
        // will mitigate the issue. Grid should always keep the focus anyways when interacting with it.
        getElement().focus();

        super.onBrowserEvent(event);
    }
}

@@ -107,32 +107,78 @@
 client.Element;%0A
+import com.google.gwt.dom.client.EventTarget;%0A
 import com.googl
@@ -4682,24 +4682,25 @@
 nt event) %7B%0A
+%0A
         // c
@@ -4895,144 +4895,534 @@
 sue.
- Grid should always keep the focus anyways when interacting with it.%0A        getElement().focus();%0A%0A        super.onBrowserEvent(event);
+%0A        focusGridIfSelectAllClicked(event);%0A%0A        super.onBrowserEvent(event);%0A    %7D%0A%0A    private void focusGridIfSelectAllClicked(Event event) %7B%0A        EventTarget target = event.getEventTarget();%0A        if(Element.is(target)) %7B%0A            Element targetElement = Element.as(target);%0A%0A            // Currently targeting all gwt-checkboxes, might need refinement in the future.%0A            if(targetElement.getParentElement().hasClassName(%22gwt-CheckBox%22)) %7B%0A                getElement().focus();%0A            %7D%0A        %7D
 %0A   

Stop stealing focus on input elements inside Grid.