// 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 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;
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;

@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;

  abstract static 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<>(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);
    when(conn.getAutoCommit()).thenReturn(true);
    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 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 {
    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 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);
    }

    @Override
    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();
    }
  }
}
