/*
 * Copyright 2010 Google Inc.
 *
 * 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.gwt.view.client;

import com.google.gwt.junit.client.GWTTestCase;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

/**
 * Test cases for {@link AbstractDataProvider}.
 */
public class AbstractDataProviderTest extends GWTTestCase {

  /**
   * A mock {@link AbstractDataProvider} used for testing.
   *
   * @param <T> the data type
   */
  static class MockDataProvider<T> extends AbstractDataProvider<T> {

    private HasData<T> lastChanged;
    
    public MockDataProvider(ProvidesKey<T> keyProvider) {
      super(keyProvider);
    }

    public void assertLastRangeChanged(HasData<T> expected) {
      assertEquals(expected, lastChanged);
    }

    public void clearLastRangeChanged() {
      lastChanged = null;
    }

    @Override
    protected void onRangeChanged(HasData<T> display) {
      lastChanged = display;
    }
  }

  @Override
  public String getModuleName() {
    return "com.google.gwt.view.View";
  }

  public void testAddRemoveDataDisplay() {
    MockDataProvider<String> provider = new MockDataProvider<String>(null);

    // Test with no displays.
    provider.updateRowCount(10, true);
    provider.assertLastRangeChanged(null);

    // Add the first display.
    MockHasData<String> display0 = new MockHasData<String>();
    provider.addDataDisplay(display0);
    provider.assertLastRangeChanged(display0);

    // Add a second display.
    MockHasData<String> display1 = new MockHasData<String>();
    provider.addDataDisplay(display1);
    provider.assertLastRangeChanged(display1);

    // Try to remove an invalid display.
    MockHasData<String> invalidDisplay = new MockHasData<String>();
    try {
      provider.removeDataDisplay(invalidDisplay);
      fail("Expected IllegalStateException");
    } catch (IllegalStateException e) {
      // Expected.
    }

    // Remove a valid display.
    provider.removeDataDisplay(display1);

    // Make sure the remaining display triggers the delegate.
    provider.assertLastRangeChanged(display1);
    display0.setVisibleRange(100, 20);
    display1.setVisibleRange(100, 20); // Shouldn't affect the provider.
    provider.assertLastRangeChanged(display0);
  }

  public void testGetRanges() {
    AbstractDataProvider<String> provider = createDataProvider();

    // No ranges.
    {
      Range[] ranges = provider.getRanges();
      assertEquals(0, ranges.length);
    }

    // One range.
    {
      MockHasData<String> display0 = new MockHasData<String>();
      display0.setVisibleRange(0, 10);
      provider.addDataDisplay(display0);
      Range[] ranges = provider.getRanges();
      assertEquals(1, ranges.length);
      assertEquals(new Range(0, 10), ranges[0]);
    }

    // Multiple ranges.
    {
      MockHasData<String> display1 = new MockHasData<String>();
      display1.setVisibleRange(3, 10);
      provider.addDataDisplay(display1);
      MockHasData<String> display2 = new MockHasData<String>();
      display2.setVisibleRange(30, 35);
      provider.addDataDisplay(display2);
      Set<Range> ranges = new HashSet<Range>();
      for (Range range : provider.getRanges()) {
        ranges.add(range);
      }
      assertEquals(3, ranges.size());
      assertTrue(ranges.contains(new Range(0, 10)));
      assertTrue(ranges.contains(new Range(3, 10)));
      assertTrue(ranges.contains(new Range(30, 35)));
    }
  }

  public void testGetDataDisplays() {
    AbstractDataProvider<String> provider = createDataProvider();
    MockHasData<String> display0 = new MockHasData<String>();
    MockHasData<String> display1 = new MockHasData<String>();
    assertEquals(0, provider.getDataDisplays().size());

    // Add two displays.
    provider.addDataDisplay(display0);
    provider.addDataDisplay(display1);
    Set<HasData<String>> displays = provider.getDataDisplays();
    assertEquals(2, displays.size());
    assertTrue(displays.contains(display0));
    assertTrue(displays.contains(display1));

    // Remove one display.
    provider.removeDataDisplay(display0);
    displays = provider.getDataDisplays();
    assertEquals(1, displays.size());
    assertTrue(displays.contains(display1));
  }

  public void testKeyProvider() {
    // By default, use the object as a key.
    AbstractDataProvider<String> provider = createDataProvider(null);
    assertNull(provider.getKeyProvider());
    assertEquals("test", provider.getKey("test"));
    assertEquals(null, provider.getKey(null));
    
    // Set a key provider
    ProvidesKey<String> keyProvider = new ProvidesKey<String>() {
      @Override
      public Object getKey(String item) {
        return item == null ? item : item.toUpperCase(Locale.ROOT);
      }
    };
    provider = createDataProvider(keyProvider);
    assertEquals(keyProvider, provider.getKeyProvider());
    assertEquals("TEST", provider.getKey("test"));
    assertEquals(null, provider.getKey(null));
  }

  public void testUpdateDataSize() {
    AbstractDataProvider<String> provider = createDataProvider();

    // Test with no displays.
    provider.updateRowCount(10, true);

    // Add the first display.
    MockHasData<String> display0 = new MockHasData<String>();
    provider.addDataDisplay(display0);
    provider.updateRowCount(20, true);
    assertEquals(20, display0.getRowCount());
    assertTrue(display0.isRowCountExact());

    // Add another display.
    MockHasData<String> display1 = new MockHasData<String>();
    provider.addDataDisplay(display1);
    provider.updateRowCount(30, false);
    assertEquals(30, display0.getRowCount());
    assertFalse(display0.isRowCountExact());
    assertEquals(30, display1.getRowCount());
    assertFalse(display1.isRowCountExact());
  }

  public void testUpdateRowData() {
    AbstractDataProvider<String> provider = createDataProvider();
    MockHasData<String> display = new MockHasData<String>();
    display.setVisibleRange(10, 5);
    provider.addDataDisplay(display);

    // Data equal to range.
    {
      List<String> values = createData(10, 5);
      provider.updateRowData(10, values);
      assertEquals(values, display.getLastRowData());
      assertEquals(new Range(10, 5), display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Data contained within range.
    {
      List<String> values = createData(12, 2);
      provider.updateRowData(12, values);
      assertEquals(values, display.getLastRowData());
      assertEquals(new Range(12, 2), display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Empty data list starting at page start.
    {
      List<String> values = createData(10, 0);
      provider.updateRowData(10, values);
      assertEquals(values, display.getLastRowData());
      assertEquals(new Range(10, 0), display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Data before range.
    {
      List<String> values = createData(5, 5);
      provider.updateRowData(5, values);
      assertNull(display.getLastRowData());
      assertNull(display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Data after range.
    {
      List<String> values = createData(15, 5);
      provider.updateRowData(15, values);
      assertNull(display.getLastRowData());
      assertNull(display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Data overlaps entire range.
    {
      List<String> values = createData(5, 15);
      provider.updateRowData(5, values);
      assertEquals(values.subList(5, 10), display.getLastRowData());
      assertEquals(new Range(10, 5), display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Data overlaps start of range.
    {
      List<String> values = createData(5, 7);
      provider.updateRowData(5, values);
      assertEquals(values.subList(5, 7), display.getLastRowData());
      assertEquals(new Range(10, 2), display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }

    // Data overlaps end of range.
    {
      List<String> values = createData(13, 5);
      provider.updateRowData(13, values);
      assertEquals(values.subList(0, 2), display.getLastRowData());
      assertEquals(new Range(13, 2), display.getLastRowDataRange());
      display.clearLastRowDataAndRange();
    }
  }

  public void testUpdateRowDataMultipleDisplays() {
    AbstractDataProvider<String> provider = createDataProvider();
    MockHasData<String> display0 = new MockHasData<String>();
    display0.setVisibleRange(10, 5);
    provider.addDataDisplay(display0);
    MockHasData<String> display1 = new MockHasData<String>();
    display1.setVisibleRange(0, 5);
    provider.addDataDisplay(display1);
    MockHasData<String> display2 = new MockHasData<String>();
    display2.setVisibleRange(12, 10);
    provider.addDataDisplay(display2);

    List<String> values = createData(10, 5);
    provider.updateRowData(10, values);
    assertEquals(values, display0.getLastRowData());
    assertEquals(new Range(10, 5), display0.getLastRowDataRange());
    assertNull(display1.getLastRowData());
    assertNull(display1.getLastRowDataRange());
    assertEquals(values.subList(2, 5), display2.getLastRowData());
    assertEquals(new Range(12, 3), display2.getLastRowDataRange());
  }

  /**
   * Create an {@link AbstractDataProvider} for testing.
   *
   * @return the data provider
   */
  protected AbstractDataProvider<String> createDataProvider() {
    return new MockDataProvider<String>(null);
  }

  /**
   * Create an {@link AbstractDataProvider} for testing.
   *
   * @return the data provider
   */
  protected AbstractDataProvider<String> createDataProvider(ProvidesKey<String> keyProvider) {
    return new MockDataProvider<String>(keyProvider);
  }

  /**
   * Create a list of data for testing.
   *
   * @param start the start index
   * @param length the length
   * @return a list of data
   */
  protected List<String> createData(int start, int length) {
    List<String> toRet = new ArrayList<String>();
    for (int i = 0; i < length; i++) {
      toRet.add("test " + (i + start));
    }
    return toRet;
  }
}
