package com.vaadin.tests.components.table;

import java.util.HashSet;
import java.util.Set;

import com.vaadin.annotations.AutoGenerated;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.Align;
import com.vaadin.ui.Table.ColumnGenerator;
import com.vaadin.ui.VerticalLayout;

public class LargeSelectionCausesNPE extends TestBase {

    @AutoGenerated
    private Table table;

    private static final String ID = "id";
    private static final String NAME = "name";
    private static final String CODE = "code";

    @Override
    protected void setup() {
        addComponent(new SelectionExample());
    }

    @Override
    protected String getDescription() {
        return "Attempting to update table contents while selection reaches beyond cache limits causes a NPE.<br>"
                + " Select a large amount of rows, e.g. from name2 to name262, return to the top of the table,"
                + " then try to update the first item twice.<br>"
                + " Test is broken if the original values don't reappear on the second click of the button.";
    }

    @Override
    protected Integer getTicketNumber() {
        return 8519;
    }

    public class SelectionExample extends VerticalLayout {

        Table table = new Table();
        Button button = new Button("Update the first item");
        Label nameLabel = new Label();

        HashSet<Object> markedRows = new HashSet<Object>();
        Label selected = new Label();

        public SelectionExample() {
            addComponent(table);
            addComponent(button);
            setMargin(new MarginInfo(true, false, false, false));

            // Label to indicate current selection
            selected.setValue("No selection");
            addComponent(selected);

            // set a style name, so we can style rows and cells
            table.setStyleName("iso3166");

            // size
            table.setWidth("100%");
            table.setPageLength(5);

            // selectable
            table.setSelectable(true);
            table.setMultiSelect(true);
            table.setImmediate(true);

            // connect data source
            table.setContainerDataSource(getContainer());

            table.addGeneratedColumn(CODE, columnGenerator);

            // turn on column reordering and collapsing
            table.setColumnReorderingAllowed(true);
            table.setColumnCollapsingAllowed(true);

            // set column headers
            table.setVisibleColumns(new String[] { CODE, NAME, ID });
            table.setColumnHeaders(new String[] { "DummyCode", "DummyName",
                    "DummyId" });

            // Column alignment
            table.setColumnAlignment(ID, Align.CENTER);

            // Column width
            table.setColumnWidth(CODE, 70);
            table.setColumnExpandRatio(NAME, 1);
            table.setColumnWidth(ID, 70);

            // listen for valueChange, a.k.a 'select' and update the label
            table.addValueChangeListener(valueChangeListener);

            button.setId(getTicketNumber() + "-button");
            button.addClickListener(clickListener);
        }

        Table.ValueChangeListener valueChangeListener = new Table.ValueChangeListener() {
            @Override
            public void valueChange(ValueChangeEvent event) {
                // in multiselect mode, a Set of itemIds is returned,
                // in singleselect mode the itemId is returned directly
                Set<?> value = (Set<?>) event.getProperty().getValue();
                if (null == value || value.size() == 0) {
                    selected.setValue("No selection");
                } else {
                    selected.setValue("Selected: " + table.getValue());
                }
            }
        };

        Button.ClickListener clickListener = new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                Property nameProperty = table.getContainerProperty(0, NAME);
                if (("0").equals(nameLabel.getValue())) {
                    nameProperty.setValue(NAME + "0-version2");
                    nameLabel.setValue("0-version2");
                } else {
                    nameProperty.setValue(NAME + 0);
                    nameLabel.setValue("0");
                }
            }
        };

        public IndexedContainer getContainer() {
            IndexedContainer container = new IndexedContainer();
            container.addContainerProperty(NAME, String.class, null);
            container.addContainerProperty(ID, Integer.class, null);
            for (int i = 0; i < 264; i++) {
                String name = NAME + i;
                int id = i;
                Item item = container.addItem(id);
                item.getItemProperty(NAME).setValue(name);
                item.getItemProperty(ID).setValue(id);
            }
            container.sort(new Object[] { ID }, new boolean[] { true });
            return container;
        }

        ColumnGenerator columnGenerator = new ColumnGenerator() {

            @Override
            public Object generateCell(Table source, Object itemId,
                    Object columnId) {
                Label label = new Label();
                label.setSizeUndefined();
                label.setValue(itemId.toString());
                label.setId(getTicketNumber() + "-" + itemId);
                if (0 == (Integer) itemId) {
                    nameLabel = label;
                }
                return label;
            }

        };
    }

}
