package org.jboss.as.console.client.widgets.tables;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionModel;
import com.google.gwt.view.client.SingleSelectionModel;

import java.util.ArrayList;
import java.util.List;

/**
 * <b>Caveat</b>: You need to set the data provider list before creating the filter instance.
 *
 * @author Heiko Braun
 * @date 7/31/12
 */
public class DataProviderFilter<T> {

    private ListDataProvider<T> delegate;
    private ArrayList<T> origValues = new ArrayList<T>();
    private Predicate predicate;
    private TextBox filter;

    public interface Predicate<T> {
        boolean apply(String prefix, T candiate);
    }

    /**
     *  initialized the filter by calling {@link #snapshot()}
     * @param delegate
     * @param predicate
     */
    public DataProviderFilter(ListDataProvider<T> delegate, Predicate<T> predicate) {
        this.delegate = delegate;
        this.predicate = predicate;
        this.filter = new TextBox();

        snapshot();
    }

    private void clearSelection() {
        for(HasData<T> table : delegate.getDataDisplays())
        {
            SelectionModel<? super T> selectionModel = table.getSelectionModel();
            if(selectionModel instanceof SingleSelectionModel)
            {
                SingleSelectionModel<T> sm = (SingleSelectionModel<T>)selectionModel;
                T selectedObject = sm.getSelectedObject();
                if(selectedObject!=null)
                    ((SingleSelectionModel<T>) selectionModel).setSelected(selectedObject, false);
            }
        }
    }

    /**
     * if {@link #snapshot()} is set, a new backup if the data provider list will be made. <br/>
     * you need to do it when the data provider gets new records.
     *
     * @param snapshot  create a snapshot
     */
    public void reset(boolean snapshot) {
        if(snapshot)
            snapshot();

        // flush
        clearFilter();

        // clear input
        filter.setText("");
    }

    /**
     * creates a backup of the orig data provider values
     * that a re used to clear the provider when the filter is cleared.
     */
    public void snapshot() {
        // backup original
        this.origValues.clear();
        this.origValues.addAll(delegate.getList());
    }

    public Widget asWidget() {


        filter.setMaxLength(30);
        filter.setVisibleLength(20);
        filter.getElement().setAttribute("style", "width:120px;");

        filter.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent keyUpEvent) {

                Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {

                    @Override
                    public void execute() {
                        String prefix = filter.getText();

                        if (prefix != null && !prefix.equals("")) {
                            // filter by prefix
                            filterByPrefix(prefix);
                        } else {
                            clearFilter();
                        }
                    }

                });
            }
        });
        HorizontalPanel panel = new HorizontalPanel();
        Label label = new Label("Filter: ");
        panel.add(label);
        panel.add(filter);

        label.getElement().setAttribute("style", "padding-top:8px;margin-right:8px");
        return panel;
    }

    public void filterByPrefix(String prefix) {

        clearSelection();

        final List<T> next  = new ArrayList<T>();
        for(T item : origValues)
        {
            if(predicate.apply(prefix, item))
                next.add(item);
        }


        delegate.getList().clear(); // cannot call setList() as that breaks the sort handler
        delegate.getList().addAll(next);
        delegate.flush();

    }

    public void clearFilter() {

        delegate.getList().clear(); // cannot call setList() as that breaks the sort handler
        delegate.getList().addAll(origValues);
        delegate.flush();

    }
}

@@ -475,24 +475,65 @@
 taProvider;%0A
+import com.google.gwt.view.client.Range;%0A
 import com.g
@@ -566,24 +566,24 @@
 ctionModel;%0A
-
 import com.g
@@ -1022,16 +1022,52 @@
  filter;
+%0A    private Range origVisibleRange;
 %0A%0A    pu
@@ -2780,16 +2780,107 @@
 ist());%0A
+        origVisibleRange = delegate.getDataDisplays().iterator().next().getVisibleRange();%0A
     %7D%0A%0A 
@@ -4081,16 +4081,104 @@
 ction();
+%0A        delegate.getDataDisplays().iterator().next().setVisibleRange(origVisibleRange);
 %0A%0A      
@@ -4487,16 +4487,214 @@
 l(next);
+%0A%0A        if(next.size()%3CorigVisibleRange.getLength()) %7B%0A            for (HasData table : delegate.getDataDisplays()) %7B%0A                table.setVisibleRange(0, next.size());%0A            %7D%0A        %7D
 %0A       
@@ -4838,32 +4838,32 @@
 he sort handler%0A
-
         delegate
@@ -4893,16 +4893,106 @@
 alues);%0A
+%0A        delegate.getDataDisplays().iterator().next().setVisibleRange(origVisibleRange);%0A%0A
         

Fix HAL-395 / BZ1088379: Deployment filter only works in the first page