package com.backendless.transaction;

import com.backendless.Persistence;
import com.backendless.exceptions.ExceptionMessage;
import com.backendless.persistence.BackendlessSerializer;
import com.backendless.transaction.operations.Operation;
import com.backendless.transaction.operations.OperationDelete;
import com.backendless.transaction.operations.OperationDeleteBulk;
import com.backendless.transaction.payload.DeleteBulkPayload;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class UnitOfWorkDeleteImpl implements UnitOfWorkDelete
{
  AtomicInteger countDelete = new AtomicInteger( 1 );
  AtomicInteger countDeleteBulk = new AtomicInteger( 1 );

  private final List<Operation> operations;

  public UnitOfWorkDeleteImpl( List<Operation> operations )
  {
    this.operations = operations;
  }

  @Override
  public <E> OpResult delete( E instance )
  {
    Map<String, Object> entityMap = SerializationHelper.serializeEntityToMap( instance );
    String tableName = BackendlessSerializer.getSimpleName( instance.getClass() );

    return delete( tableName, entityMap );
  }

  @Override
  public OpResult delete( String tableName, Map<String, Object> objectMap )
  {
    if( objectMap == null )
      throw new IllegalArgumentException( ExceptionMessage.NULL_MAP );

    String objectId = (String) objectMap.get( Persistence.DEFAULT_OBJECT_ID_FIELD );
    if( objectId == null )
      throw new IllegalArgumentException( ExceptionMessage.NULL_OBJECT_ID_IN_OBJECT_MAP );

    return delete( tableName, objectId );
  }

  @Override
  public OpResult delete( String tableName, String objectId )
  {
    String operationResultId = OperationType.DELETE + "_" + countDelete.getAndIncrement();
    OperationDelete operationDelete = new OperationDelete( OperationType.DELETE, tableName, operationResultId, objectId );

    operations.add( operationDelete );

    return TransactionHelper.makeOpResult( tableName, operationResultId, OperationType.DELETE );
  }

  @Override
  public OpResult delete( String tableName, OpResult result )
  {
    if( result == null )
      throw new IllegalArgumentException( ExceptionMessage.NULL_OP_RESULT );

    if( !OperationType.supportPropNameType.contains( result.getOperationType() ) )
      throw new IllegalArgumentException( ExceptionMessage.REF_TYPE_NOT_SUPPORT );

    String operationResultId = OperationType.DELETE + "_" + countDelete.getAndIncrement();
    OperationDelete operationDelete = new OperationDelete( OperationType.DELETE, tableName, operationResultId,
                                                           result.resolveTo( Persistence.DEFAULT_OBJECT_ID_FIELD ) );

    operations.add( operationDelete );

    return TransactionHelper.makeOpResult( tableName, operationResultId, OperationType.DELETE );
  }

  @Override
  public OpResult delete( String tableName, OpResultIndex resultIndex )
  {
    if( resultIndex == null )
      throw new IllegalArgumentException( ExceptionMessage.NULL_OP_RESULT_INDEX );

    if( !OperationType.supportResultIndexType.contains( resultIndex.getOperationType() ) )
      throw new IllegalArgumentException( ExceptionMessage.REF_TYPE_NOT_SUPPORT );

    String operationResultId = OperationType.DELETE + "_" + countDelete.getAndIncrement();
    OperationDelete operationDelete = new OperationDelete( OperationType.DELETE, tableName, operationResultId,
                                                           resultIndex.getReference() );

    operations.add( operationDelete );

    return TransactionHelper.makeOpResult( tableName, operationResultId, OperationType.DELETE );
  }

  @Override
  public <E> OpResult bulkDelete( List<E> instances )
  {
    List<Map<String, Object>> serializedEntities = TransactionHelper.convertInstancesToMaps( instances );

    String tableName =  BackendlessSerializer.getSimpleName( instances.get( 0 ).getClass() );

    return bulkDelete( tableName, serializedEntities );
  }

  @Override
  public <E> OpResult bulkDelete( String tableName, List<E> arrayOfObjects )
  {
    if( arrayOfObjects == null || arrayOfObjects.isEmpty() )
      throw new IllegalArgumentException( ExceptionMessage.NULL_EMPTY_BULK );

    List<String> objectIds;
    if( arrayOfObjects.get( 0 ) instanceof Map )
      objectIds = TransactionHelper.convertMapToObjectIds( (List<Map<String, Object>>) arrayOfObjects );
    else if( arrayOfObjects.get( 0 ) instanceof String )
      objectIds = (List<String>) arrayOfObjects;
    else
      throw new IllegalArgumentException( ExceptionMessage.LIST_MAP_OR_STRING );

    return bulkDelete( tableName, null, objectIds );
  }

  @Override
  public OpResult bulkDelete( String tableName, String whereClause )
  {
    if( whereClause == null )
      throw new IllegalArgumentException( ExceptionMessage.NULL_WHERE_CLAUSE );

    String operationResultId = OperationType.DELETE_BULK + "_" + countDeleteBulk.getAndIncrement();
    DeleteBulkPayload deleteBulkPayload = new DeleteBulkPayload( whereClause, null );
    OperationDeleteBulk operationDeleteBulk = new OperationDeleteBulk( OperationType.DELETE_BULK, tableName,
                                                                       operationResultId, deleteBulkPayload );

    operations.add( operationDeleteBulk );

    return TransactionHelper.makeOpResult( tableName, operationResultId, OperationType.DELETE_BULK );
  }

  @Override
  public OpResult bulkDelete( String tableName, OpResult result )
  {
    if( result == null )
      throw new IllegalArgumentException( ExceptionMessage.NULL_OP_RESULT );

    if( !OperationType.supportResultIndexType.contains( result.getOperationType() ) )
      throw new IllegalArgumentException( ExceptionMessage.REF_TYPE_NOT_SUPPORT );

    return bulkDelete( tableName, result.getReference(), null );
  }

  private OpResult bulkDelete( String tableName, Map<String, Object> reference, List<String> objectIds )
  {
    Object unconditional = reference != null ? reference : objectIds;

    String operationResultId = OperationType.DELETE_BULK + "_" + countDeleteBulk.getAndIncrement();
    DeleteBulkPayload deleteBulkPayload = new DeleteBulkPayload( null, unconditional );
    OperationDeleteBulk operationDeleteBulk = new OperationDeleteBulk( OperationType.DELETE_BULK, tableName,
                                                                       operationResultId, deleteBulkPayload );

    operations.add( operationDeleteBulk );

    return TransactionHelper.makeOpResult( tableName, operationResultId, OperationType.DELETE_BULK );
  }
}

@@ -4836,553 +4836,55 @@
     
-String operationResultId = OperationType.DELETE_BULK + %22_%22 + countDeleteBulk.getAndIncrement();%0A    DeleteBulkPayload deleteBulkPayload = new DeleteBulkPayload( whereClause, null );%0A    OperationDeleteBulk operationDeleteBulk = new OperationDeleteBulk( OperationType.DELETE_BULK, tableName,%0A                                                                       operationResultId, deleteBulkPayload );%0A%0A    operations.add( operationDeleteBulk );%0A%0A    return TransactionHelper.makeOpResult( tableName, operationResultId, OperationType.DELETE_BULK
+return bulkDelete( tableName, whereClause, null
  );%0A
@@ -5276,16 +5276,22 @@
 bleName,
+ null,
  result.
@@ -5304,22 +5304,16 @@
 erence()
-, null
  );%0A  %7D%0A
@@ -5366,138 +5366,54 @@
 me, 
-Map%3C
 String
-, Object%3E reference, List%3CString%3E objectIds )%0A  %7B%0A    Object unconditional = reference != null ? reference : objectIds;%0A
+ whereClause, Object unconditional )%0A  %7B
 %0A   
@@ -5574,20 +5574,27 @@
 ayload( 
-null
+whereClause
 , uncond

extract duplicate code