// Copyright (C) 2011 The Android Open Source Project
//
// 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.gwtorm.jdbc;


import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

import com.google.gwtorm.client.Key;
import com.google.gwtorm.schema.sql.SqlDialect;
import com.google.gwtorm.server.Access;
import com.google.gwtorm.server.ListResultSet;
import com.google.gwtorm.server.OrmConcurrencyException;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.mockito.stubbing.OngoingStubbing;

import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@RunWith(Parameterized.class)
public abstract class AbstractTestJdbcAccess {

  private static final String INSERT = "insert";
  private static final String UPDATE = "update";
  private static final String DELETE = "delete";

  private final JdbcAccess<Data, Data.DataKey> classUnderTest;

  private final Iterable<Data> noData;
  private final Iterable<Data> oneRow;
  private final Iterable<Data> twoRows;
  private final Connection conn;
  protected final SqlDialect dialect;

  protected Integer totalUpdateCount = null;

  protected SQLException sqlException = null;

  static abstract class IterableProvider<T> {
    abstract Iterable<T> createIterable(T... ts);
  }

  private static final IterableProvider<Data> LIST_PROVIDER =
      new IterableProvider<Data>() {

        @Override
        Iterable<Data> createIterable(Data... data) {
          return Arrays.asList(data);
        }
      };

  private static final IterableProvider<Data> LIST_RESULT_SET_PROVIDER =
      new IterableProvider<Data>() {

        @Override
        Iterable<Data> createIterable(Data... data) {
          List<Data> list = Arrays.asList(data);
          return new ListResultSet<Data>(list);
        }
      };

  private static final IterableProvider<Data> UNMODIFIABLE_LIST_PROVIDER =
      new IterableProvider<Data>() {

        @Override
        Iterable<Data> createIterable(Data... data) {
          List<Data> list = Arrays.asList(data);
          return Collections.unmodifiableList(list);
        }
      };

  @Parameters
  public static Collection<Object[]> data() {
    return Arrays.asList(new Object[][] { {LIST_PROVIDER},
        {UNMODIFIABLE_LIST_PROVIDER}, {LIST_RESULT_SET_PROVIDER},});
  }

  public AbstractTestJdbcAccess(IterableProvider<Data> dataProvider)
      throws SQLException {
    noData = dataProvider.createIterable();
    oneRow = dataProvider.createIterable(new Data(1));
    twoRows = dataProvider.createIterable(new Data(1), new Data(2));
    conn = mock(Connection.class);
    dialect = createDialect();
    classUnderTest = createJdbcAccess(dialect, conn);
  }

  protected abstract SqlDialect createDialect() throws SQLException;

  private PreparedStatement stubStatementWithUpdateCounts(String command,
      final int... updateCounts) throws SQLException {
    PreparedStatement ps = mock(PreparedStatement.class);

    // batching
    doNothing().when(ps).addBatch();
    when(ps.executeBatch()).thenReturn(updateCounts);

    int total = 0;

    // non-batching
    if (updateCounts != null && updateCounts.length > 0) {
      OngoingStubbing<Integer> stubber = when(ps.executeUpdate());
      for (int updateCount : updateCounts) {
        stubber = stubber.thenReturn(updateCount);
        total += updateCount;
      }
    }

    totalUpdateCount = Integer.valueOf(total);

    when(conn.prepareStatement(command)).thenReturn(ps);
    return ps;
  }

  private PreparedStatement stubStatementThrowExceptionOnExecute(
      String command, SQLException exception) throws SQLException {
    PreparedStatement ps = mock(PreparedStatement.class);
    doNothing().when(ps).addBatch();
    when(ps.executeBatch()).thenThrow(exception);
    when(ps.executeUpdate()).thenThrow(exception);
    when(conn.prepareStatement(command)).thenReturn(ps);
    return ps;
  }

  private static JdbcAccess<Data, Data.DataKey> createJdbcAccess(
      final SqlDialect dialect, Connection conn) {
    JdbcSchema schema = setupSchema(dialect, conn);

    JdbcAccess<Data, Data.DataKey> classUnderTest = new DataJdbcAccess(schema);
    return classUnderTest;
  }

  private static JdbcSchema setupSchema(final SqlDialect dialect,
      final Connection conn) {
    @SuppressWarnings("rawtypes")
    Database db = mock(Database.class);
    try {
      when(db.getDialect()).thenReturn(dialect);

      when(db.newConnection()).thenReturn(conn);

      JdbcSchema schema = new Schema(db);
      return schema;
    } catch (OrmException e) {
      throw new RuntimeException(e);
    }
  }

  protected static void assertUsedBatchingOnly(PreparedStatement ps, int... ids)
      throws SQLException {
    verify(ps, times(ids.length)).addBatch();
    verify(ps).executeBatch();
    verify(ps, never()).executeUpdate();
    assertExpectedIdsUsed(ps, ids);
  }

  protected static void assertUsedNonBatchingOnly(PreparedStatement ps,
      int... ids) throws SQLException {
    verify(ps, never()).addBatch();
    verify(ps, never()).executeBatch();
    verify(ps, times(ids.length)).executeUpdate();
    assertExpectedIdsUsed(ps, ids);
  }

  protected static void assertNotUsed(PreparedStatement insert) {
    verifyZeroInteractions(insert);
  }

  protected abstract void assertCorrectUpdating(PreparedStatement ps,
      int... ids) throws SQLException;

  protected abstract void assertCorrectAttempting(PreparedStatement ps,
      int... ids) throws SQLException;

  private static void assertExpectedIdsUsed(PreparedStatement ps, int... ids)
      throws SQLException {
    for (int id : ids) {
      verify(ps).setInt(1, id);
    }
  }

  @Test
  public void testInsertNothing() throws OrmException {
    classUnderTest.insert(noData);
  }

  @Test
  public void testInsertOne() throws SQLException, OrmException {
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1);

    classUnderTest.insert(oneRow);

    assertCorrectUpdating(insert, 1);
  }

  @Test
  public void testInsertOneException() throws OrmException, SQLException {
    sqlException = new BatchUpdateException();
    PreparedStatement insert =
        stubStatementThrowExceptionOnExecute(INSERT, sqlException);
    try {
      classUnderTest.insert(oneRow);
      fail("missingException");
    } catch (OrmException e) {
      // expected
      assertSame(e.getCause(), sqlException);
    }

    assertCorrectUpdating(insert, 1);
  }

  @Test
  public void testUpdateNothing() throws OrmException {
    classUnderTest.update(noData);
  }

  @Test
  public void testUpdateOne() throws SQLException, OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 1);

    classUnderTest.update(oneRow);

    assertCorrectUpdating(update, 1);
  }

  @Test
  public void testUpdateOneException() throws SQLException {
    sqlException = new BatchUpdateException();
    PreparedStatement update =
        stubStatementThrowExceptionOnExecute(UPDATE, sqlException);
    try {
      classUnderTest.update(oneRow);
      fail("missingException");
    } catch (OrmException e) {
      // expected
      assertSame(e.getCause(), sqlException);
    }

    assertCorrectUpdating(update, 1);
  }

  @Test
  public void testUpdateTwoConcurrentlyModifiedException() throws SQLException,
      OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 0, 0);
    try {
      classUnderTest.update(twoRows);
      fail("missing OrmConcurrencyException");
    } catch (OrmConcurrencyException e) {
      // expected
    }
    assertCorrectUpdating(update, 1, 2);
  }

  @Test
  public void testUpsertNothing() throws OrmException, SQLException {
    classUnderTest.upsert(noData);
  }

  @Test
  public void upsertOneExisting() throws OrmException, SQLException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 1);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT);

    classUnderTest.upsert(oneRow);

    assertCorrectAttempting(update, 1);
    assertNotUsed(insert);
  }

  @Test
  public void upsertOneException() throws OrmException, SQLException {
    SQLException exception = new BatchUpdateException();
    PreparedStatement update =
        stubStatementThrowExceptionOnExecute(UPDATE, exception);
    try {
      classUnderTest.upsert(oneRow);
      fail("missingException");
    } catch (OrmException e) {
      // expected
      assertSame(e.getCause(), exception);
    }

    assertCorrectAttempting(update, 1);
  }

  @Test
  public void upsertOneNotExisting() throws OrmException, SQLException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1);

    classUnderTest.upsert(oneRow);

    assertCorrectAttempting(update, 1);
    assertCorrectUpdating(insert, 1);
  }

  @Test
  public void testUpsertTwoNotExistingZeroLengthArray() throws SQLException,
      OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1, 1);

    classUnderTest.upsert(twoRows);

    assertCorrectAttempting(update, 1, 2);
    assertCorrectUpdating(insert, 1, 2);
  }

  @Test
  public void upsertTwoNotExistingNoInfo() throws SQLException, OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 0, 0);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1, 1);

    classUnderTest.upsert(twoRows);

    assertCorrectAttempting(update, 1, 2);
    assertCorrectUpdating(insert, 1, 2);
  }

  @Test
  public void upsertTwoBothExisting() throws SQLException, OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 1, 1);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT);

    classUnderTest.upsert(twoRows);

    assertCorrectAttempting(update, 1, 2);
    assertNotUsed(insert);
  }

  @Test
  public void upsertTwoFirstExistsingNoInfo() throws SQLException, OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 1, 0);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1);

    classUnderTest.upsert(twoRows);

    assertCorrectAttempting(update, 1, 2);
    assertCorrectUpdating(insert, 2);
  }

  @Test
  public void testUpsertTwoUpdateCountsAreNull() throws SQLException,
      OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, null);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1, 1);

    classUnderTest.upsert(twoRows);

    assertCorrectAttempting(update, 1, 2);
    assertCorrectUpdating(insert, 1, 2);
  }

  @Test
  public void upsertTwoSecondExisting() throws SQLException, OrmException {
    PreparedStatement update = stubStatementWithUpdateCounts(UPDATE, 0, 1);
    PreparedStatement insert = stubStatementWithUpdateCounts(INSERT, 1);

    classUnderTest.upsert(twoRows);

    assertCorrectAttempting(update, 1, 2);
    assertCorrectUpdating(insert, 1);
  }

  @Test
  public void deleteOneExisting() throws SQLException, OrmException {
    PreparedStatement delete = stubStatementWithUpdateCounts(DELETE, 1);

    classUnderTest.delete(oneRow);

    assertCorrectUpdating(delete, 1);
  }

  @Test
  public void deleteTwoNotExisting() throws SQLException, OrmException {
    PreparedStatement delete = stubStatementWithUpdateCounts(DELETE, 0, 1);
    try {
      classUnderTest.delete(twoRows);
      fail("missing OrmConcurrencyException");
    } catch (OrmConcurrencyException e) {
      // expected
    }

    assertCorrectUpdating(delete, 1, 2);
  }

  private static class Schema extends JdbcSchema {

    protected Schema(Database<?> d) throws OrmException {
      super(d);
    }

    @Override
    public Access<?, ?>[] allRelations() {
      throw new UnsupportedOperationException();
    }

  }

  static class Data {

    private final int id;

    Data(int anId) {
      id = anId;
    }

    private static class DataKey implements Key<Key<?>> {

      @Override
      public com.google.gwtorm.client.Key<?> getParentKey() {
        throw new UnsupportedOperationException();
      }

      @Override
      public void fromString(String in) {
        throw new UnsupportedOperationException();
      }

    }

  }

  private static class DataJdbcAccess extends JdbcAccess<Data, Data.DataKey> {

    protected DataJdbcAccess(JdbcSchema s) {
      super(s);
    }

    public String getRelationName() {
      return "Data";
    }

    @Override
    public Data.DataKey primaryKey(Data entity) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Data get(Data.DataKey key) throws OrmException {
      throw new UnsupportedOperationException();
    }

    @Override
    protected Data newEntityInstance() {
      throw new UnsupportedOperationException();
    }

    @Override
    protected String getInsertOneSql() {
      return INSERT;
    }

    @Override
    protected String getUpdateOneSql() {
      return UPDATE;
    }

    @Override
    protected String getDeleteOneSql() {
      return DELETE;
    }

    @Override
    protected void bindOneInsert(PreparedStatement ps, Data entity)
        throws SQLException {
      ps.setInt(1, entity.id);
    }

    @Override
    protected void bindOneUpdate(PreparedStatement ps, Data entity)
        throws SQLException {
      ps.setInt(1, entity.id);
    }

    @Override
    protected void bindOneDelete(PreparedStatement ps, Data entity)
        throws SQLException {
      ps.setInt(1, entity.id);
    }

    @Override
    protected void bindOneFetch(java.sql.ResultSet rs, Data entity)
        throws SQLException {
      throw new UnsupportedOperationException();
    }

    @Override
    public int getRelationID() {
      throw new UnsupportedOperationException();
    }

    @Override
    public ResultSet<Data> iterateAllEntities() throws OrmException {
      throw new UnsupportedOperationException();
    }

  }

}
