/*
 * 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.core.shared.impl.StringCase;
import com.google.gwt.junit.client.GWTTestCase;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
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 : StringCase.toUpper(item);
      }
    };
    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;
  }
}
