/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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
 *
 *     https://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 org.apache.jdo.tck.api.converter;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import javax.jdo.JDOHelper;
import javax.jdo.Query;
import javax.jdo.Transaction;
import org.apache.jdo.tck.JDO_Test;
import org.apache.jdo.tck.pc.converter.IPCRect;
import org.apache.jdo.tck.pc.converter.PCRect;
import org.apache.jdo.tck.pc.converter.PCRectAnnotated;
import org.apache.jdo.tck.pc.mylib.Point;
import org.apache.jdo.tck.util.BatchTestRunner;
import org.apache.jdo.tck.util.PointToStringConverter;

/**
 * <B>Title:</B>PointAttributeConverterTest <br>
 * <B>Keywords:</B> mapping <br>
 * <B>Assertion ID:</B> [not identified] <br>
 * <B>Assertion Description: </B> A IPCRect instance refers two Point instances, that are stored as
 * strings in the datastore. A Point instance is converted using an AttributeConverter.
 */
public class PointAttributeConverterTest extends JDO_Test {

  private static final int UL_X = 1;
  private static final int UL_Y = 10;
  private static final int LR_X = 10;
  private static final int LR_Y = 1;

  /**
   * The <code>main</code> is called when the class is directly executed from the command line.
   *
   * @param args The arguments passed to the program.
   */
  public static void main(String[] args) {
    BatchTestRunner.run(PointAttributeConverterTest.class);
  }

  /**
   * @see org.apache.jdo.tck.JDO_Test#localSetUp()
   */
  @Override
  protected void localSetUp() {
    addTearDownClass(PCRect.class);
    addTearDownClass(PCRectAnnotated.class);
  }

  /** Test method creating and storing a PCRectString instance. */
  public void testStorePCRectStringInstance() {
    runStoreIPCRectInstance(PCRect.class);
  }

  /** Test method reading a PCRectString instance from the datastore. */
  public void testReadPCRectStringInstance() {
    runReadIPCRectInstance(PCRect.class);
  }

  /** Test method modifying a PCRectString instance and storing in the datastore. */
  public void testModifyPCRectStringInstance() {
    runModifyIPCRectInstance(PCRect.class);
  }

  /** Test method running a PCRectString query with a query parameter of type Point. */
  public void testPCRectStringQueryWithPointParam() {
    runQueryWithPointParameter(PCRect.class);
  }

  /** Test method running a PCRectString query with a query parameter of type String. */
  public void testPCRectStringQueryWithStringParam() throws Exception {
    runQueryWithStringParameter(PCRect.class);
  }

  /** Test method creating and storing a PCRectStringAnnotated instance. */
  public void testStorePCRectStringAnnotatedInstance() {
    runStoreIPCRectInstance(PCRectAnnotated.class);
  }

  /** Test method reading a PCRectStringAnnotated instance from the datastore. */
  public void testReadPCRectStringAnnotatedInstance() {
    runReadIPCRectInstance(PCRectAnnotated.class);
  }

  /** Test method modifying a PCRectStringAnnotated instance and storing in the datastore. */
  public void testModifyPCRectStringAnnotatedInstance() {
    runModifyIPCRectInstance(PCRectAnnotated.class);
  }

  /** Test method running a PCRectStringAnnotated query with a query parameter of type String. */
  public void testPCRectStringAnnotatedQueryWithPointParam() {
    runQueryWithPointParameter(PCRectAnnotated.class);
  }

  /** Test method running a PCRectStringAnnotated query with a query parameter of type Point. */
  public void testPCRectStringAnnotatedQueryWithStringParam() throws Exception {
    runQueryWithStringParameter(PCRectAnnotated.class);
  }

  // Helper methods

  /**
   * Helper method creating a IPCRect instance. It should call AttributeConverter method
   * convertToDatastore.
   */
  private <T extends IPCRect> void runStoreIPCRectInstance(Class<T> pcrectClass) {
    int nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    int nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();

    // Create a persistent IPCRect instance and store its oid
    // AttributeConverter method convertToDatastore is called when persisting instance
    createIPCRectInstances(pcrectClass, 1);

    // convertToDatastore should be called twice
    assertEquals(2, PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
    // convertToAttribute should not be called
    assertEquals(0, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
  }

  /**
   * Helper method reading a IPCRect instance from the datastore. It should call AttributeConverter
   * method convertToAttribute.
   */
  private <T extends IPCRect> void runReadIPCRectInstance(Class<T> pcrectClass) {
    IPCRect rect;
    Object oid;
    int nrOfDbCalls;
    int nrOfAttrCalls;

    // Create a persistent IPCRect instance and store its oid
    oid = createIPCRectInstances(pcrectClass, 1);

    // Cleanup the 2nd-level cache and close the pm to make sure PCRect instances are not cached
    pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcrectClass);
    pm.close();
    pm = null;

    nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
    pm = getPM();
    pm.currentTransaction().begin();
    // Read the IPCRect instance from the datastore, this should call convertToAttribute
    rect = (IPCRect) pm.getObjectById(oid);
    Point ul = rect.getUpperLeft();
    Point lr = rect.getLowerRight();
    pm.currentTransaction().commit();

    // convertToDatastore should not be called
    assertEquals(0, PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
    // convertToAttribute should be called twice
    assertEquals(2, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
    // Check the values of the associated Point instances
    assertEquals(UL_X, ul.getX());
    assertEquals(UL_Y, ul.getY() == null ? 0 : ul.getY().intValue());
    assertEquals(LR_X, lr.getX());
    assertEquals(LR_Y, lr.getY() == null ? 0 : lr.getY().intValue());
  }

  /**
   * Helper method modifying a IPCRect instance. It should call AttributeConverter method
   * convertToDatastore.
   */
  private <T extends IPCRect> void runModifyIPCRectInstance(Class<T> pcrectClass) {
    Transaction tx;
    IPCRect rect;
    Object oid;
    int nrOfDbCalls;
    int nrOfAttrCalls;

    // Create a persistent IPCRect instance and store its oid
    oid = createIPCRectInstances(pcrectClass, 1);

    // Cleanup the 2nd-level cache and close the pm to make sure PCRect instances are not cached
    pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcrectClass);
    pm.close();
    pm = null;

    nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
    pm = getPM();
    tx = pm.currentTransaction();
    tx.begin();
    rect = (IPCRect) pm.getObjectById(oid);
    // should trigger convertToAttribute
    rect.getLowerRight();
    rect.getUpperLeft();
    // Update IPCRect instance, this should call convertToDatastore
    rect.setUpperLeft(new Point(UL_X + 1, UL_Y + 1));
    rect.setLowerRight(new Point(LR_X + 1, LR_Y + 1));
    // IPCRect instance should be dirty
    assertTrue(JDOHelper.isDirty(rect));
    tx.commit();

    // convertToDatastore should be called twice
    assertEquals(2, PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
    // convertToAttribute should be called twice
    assertEquals(2, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
  }

  /**
   * Helper method running a query with a Point parameter. The parameter value is converted using
   * the AttributeConverter.
   *
   * @throws Exception
   */
  private <T extends IPCRect> void runQueryWithPointParameter(Class<T> pcrectClass) {
    int nrOfDbCalls;
    int nrOfAttrCalls;

    nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
    createIPCRectInstances(pcrectClass, 5);
    // convertToDatastore should be called twice per instance = 10 times
    assertEquals(10, PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
    // convertToAttribute should not be called
    assertEquals(0, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);

    // Cleanup the 2nd-level cache and close the pm to make sure PCRect instances are not cached
    pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcrectClass);
    pm.close();
    pm = null;

    nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
    pm = getPM();
    pm.currentTransaction().begin();
    try (Query<T> q = pm.newQuery(pcrectClass, "this.upperLeft == :point")) {
      q.setParameters(new Point(UL_X + 1, UL_Y + 1));
      // AttributeConverter method convertToAttribute is called when loading instance from the
      // datastore
      List<T> res = q.executeList();
      assertEquals(1, res.size());
      IPCRect rect = res.get(0);
      Point ul = rect.getUpperLeft();
      Point lr = rect.getLowerRight();

      // Check the coordinates of the associated Point instances
      assertEquals(UL_X + 1, ul.getX());
      assertEquals(UL_Y + 1, ul.getY() == null ? 0 : ul.getY().intValue());
      assertEquals(LR_X + 1, lr.getX());
      assertEquals(LR_Y + 1, lr.getY() == null ? 0 : lr.getY().intValue());
    } catch (Exception e) {
      fail(e.getMessage());
    } finally {
      pm.currentTransaction().commit();
    }

    // convertToDatastore should be called to handle the query parameter
    assertTrue(PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls >= 1);
    // convertToAttribute should be called at least twice
    assertTrue(PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls >= 2);
  }

  /**
   * Helper method running a query with a Point parameter. The string parameter is compared to the
   * converted Point field.
   *
   * @throws Exception
   */
  private <T extends IPCRect> void runQueryWithStringParameter(Class<T> pcrectClass)
      throws Exception {
    int nrOfDbCalls;
    int nrOfAttrCalls;

    nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
    createIPCRectInstances(pcrectClass, 5);
    // convertToDatastore should be called twice per instance = 10 times
    assertEquals(10, PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
    // convertToAttribute should not be called
    assertEquals(0, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);

    // Cleanup the 2nd-level cache and close the pm to make sure PCRect instances are not cached
    pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcrectClass);
    pm.close();
    pm = null;

    nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
    nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
    pm = getPM();
    pm.currentTransaction().begin();
    try (Query<T> q = pm.newQuery(pcrectClass, "this.upperLeft == str")) {
      q.declareParameters("String str");
      q.setParameters("3:12");
      // AttributeConverter method convertToAttribute is called when loading instance from the
      // datastore
      List<T> res = q.executeList();
      assertEquals(1, res.size());
      IPCRect rect = res.get(0);
      Point ul = rect.getUpperLeft();
      Point lr = rect.getLowerRight();

      // Check the coordinates of the associated Point instances
      assertEquals(UL_X + 2, ul.getX());
      assertEquals(UL_Y + 2, ul.getY() == null ? 0 : ul.getY().intValue());
      assertEquals(LR_X + 2, lr.getX());
      assertEquals(LR_Y + 2, lr.getY() == null ? 0 : lr.getY().intValue());
    } finally {
      pm.currentTransaction().commit();
    }

    // convertToDatastore should not be called
    assertTrue(PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls == 0);
    // convertToAttribute should be called at least twice
    assertTrue(PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls >= 2);
  }

  /**
   * Helper method to create IPCRect instances.
   *
   * @param pcrectClass class instance of the IPCRect implementation class to be created
   * @param nrOfObjects number of IPCRect instances to be created
   * @return ObjectId of the first IPCRect instance
   */
  private <T extends IPCRect> Object createIPCRectInstances(Class<T> pcrectClass, int nrOfObjects) {
    IPCRect rect;
    Object oid = null;

    if (nrOfObjects < 1) {
      return null;
    }

    pm = getPM();
    try {
      pm.currentTransaction().begin();
      rect = pcrectClass.getConstructor().newInstance();
      rect.setUpperLeft(new Point(UL_X, UL_Y));
      rect.setLowerRight(new Point(LR_X, LR_Y));
      pm.makePersistent(rect);
      oid = pm.getObjectId(rect);
      for (int i = 1; i < nrOfObjects; i++) {
        rect = pcrectClass.getConstructor().newInstance();
        rect.setUpperLeft(new Point(UL_X + i, UL_Y + i));
        rect.setLowerRight(new Point(LR_X + i, LR_Y + i));
        pm.makePersistent(rect);
      }
      pm.currentTransaction().commit();
    } catch (NoSuchMethodException
        | SecurityException
        | InstantiationException
        | IllegalAccessException
        | IllegalArgumentException
        | InvocationTargetException ex) {
      fail("Error creating IPCRect instance: " + ex.getMessage());
    } finally {
      if (pm.currentTransaction().isActive()) {
        pm.currentTransaction().rollback();
      }
    }
    return oid;
  }
}
