/*
 * Copyright 2021, TeamDev. All rights reserved.
 *
 * 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
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.server.entity.given;

import com.google.common.collect.ImmutableList;
import io.spine.base.Error;
import io.spine.core.Event;
import io.spine.server.entity.EntityRecord;
import io.spine.server.entity.EntityRecordChange;
import io.spine.server.entity.Phase;
import io.spine.server.entity.TransactionListener;
import io.spine.validate.NonValidated;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.List;

import static com.google.common.collect.Lists.newLinkedList;

/**
 * An implementation of {@link TransactionListener} which memoizes all arguments received in the
 * callbacks.
 *
 * @param <I>
 *         ID type of the entity under transaction
 */
public final class MemoizingTransactionListener<I> implements TransactionListener<I> {

    private final List<Phase<I>> phasesOnBefore = newLinkedList();
    private final List<Phase<I>> phasesOnAfter = newLinkedList();

    private final List<@Nullable EntityRecord> recordsBeforeCommit = newLinkedList();
    private final List<@Nullable EntityRecordChange> recordsAfterCommit = newLinkedList();

    private Error lastError;
    private EntityRecord lastErroredRecord;

    private Event lastRejection;
    private EntityRecord lastRejectedRecord;

    @Override
    public void onBeforePhase(Phase<I> phase) {
        phasesOnBefore.add(phase);
    }

    @Override
    public void onAfterPhase(Phase<I> phase) {
        phasesOnAfter.add(phase);
    }

    @Override
    public void onBeforeCommit(@NonValidated EntityRecord entityRecord) {
        recordsBeforeCommit.add(entityRecord);
    }

    @Override
    public void onTransactionFailed(Error cause, @NonValidated EntityRecord entityRecord) {
        lastError = cause;
        lastErroredRecord = entityRecord;
    }

    @Override
    public void onTransactionFailed(Event cause, @NonValidated EntityRecord entityRecord) {
        lastRejection = cause;
        lastRejectedRecord = entityRecord;
    }

    @Override
    public void onAfterCommit(EntityRecordChange change) {
        recordsAfterCommit.add(change);
    }

    public ImmutableList<Phase<I>> phasesOnBefore() {
        return ImmutableList.copyOf(phasesOnBefore);
    }

    public ImmutableList<Phase<I>> phasesOnAfter() {
        return ImmutableList.copyOf(phasesOnAfter);
    }

    public ImmutableList<EntityRecord> recordsBeforeCommit() {
        return ImmutableList.copyOf(recordsBeforeCommit);
    }

    public ImmutableList<EntityRecordChange> recordsAfterCommit() {
        return ImmutableList.copyOf(recordsAfterCommit);
    }

    public Error lastError() {
        return lastError;
    }

    public EntityRecord lastErroredRecord() {
        return lastErroredRecord;
    }

    public Event getLastRejection() {
        return lastRejection;
    }

    public EntityRecord getLastRejectedRecord() {
        return lastRejectedRecord;
    }
}

@@ -1603,68 +1603,8 @@
 ted;
-%0Aimport org.checkerframework.checker.nullness.qual.Nullable;
 %0A%0Aim
@@ -2007,429 +2007,61 @@
 esOn
-Before = newLinkedList();%0A    private final List%3CPhase%3CI%3E%3E phasesOnAfter = newLinkedList();%0A%0A    private final List%3C@Nullable EntityRecord%3E recordsBeforeCommit = newLinkedList();%0A    private final List%3C@Nullable EntityRecordChange%3E recordsAfterCommit = newLinkedList();%0A%0A    private Error lastError;%0A    private EntityRecord lastErroredRecord;%0A%0A    private Event lastRejection;%0A    private EntityRecord lastRejectedRecord
+After = newLinkedList();%0A%0A    private Error lastError
 ;%0A%0A 
@@ -2091,22 +2091,21 @@
  void on
-Before
+After
 Phase(Ph
@@ -2136,22 +2136,21 @@
 phasesOn
-Before
+After
 .add(pha
@@ -2169,55 +2169,37 @@
     
-@Override%0A    public void onAfterPhase(
+public ImmutableList%3C
 Phase%3CI%3E
  pha
@@ -2198,191 +2198,77 @@
 e%3CI%3E
+%3E
  phase
-) %7B%0A        phasesOnAfter.add(phase);
+sOnAfter() %7B
 %0A    
-%7D%0A%0A
     
-@Override%0A    public void onBeforeCommit(@NonValidated EntityRecord entityRecord) %7B%0A        recordsBeforeCommit.add(entityRecord
+return ImmutableList.copyOf(phasesOnAfter
 );%0A 
@@ -2414,155 +2414,38 @@
     
-    lastErroredRecord = entityRecord;%0A    %7D%0A%0A    @Override%0A    public void onTransactionFailed(Event cause, @NonValidated EntityRecord entityRecord
+%7D%0A%0A    public Error lastError(
 ) %7B%0A
@@ -2456,72 +2456,24 @@
     
-lastRejection = cause;%0A        lastRejectedRecord = entityRec
+return lastErr
 or
-d
 ;%0A  
@@ -2513,129 +2513,28 @@
 d on
-AfterCommit(EntityRecordChange change) %7B%0A        recordsAfterCommit.add(change);%0A    %7D%0A%0A    public ImmutableList%3C
+BeforePhase(
 Phase%3CI%3E
 %3E ph
@@ -2533,25 +2533,14 @@
 e%3CI%3E
-%3E
  phase
-sOnBefore(
 ) %7B%0A
@@ -2551,506 +2551,224 @@
     
-return ImmutableList.copyOf(phasesOnBefore);%0A    %7D%0A%0A    public ImmutableList%3CPhase%3CI%3E%3E phasesOnAfter() %7B%0A        return ImmutableList.copyOf(phasesOnAfter);%0A    %7D%0A%0A    public ImmutableList%3CEntityRecord%3E recordsBeforeCommit() %7B%0A        return ImmutableList.copyOf(recordsBeforeCommit);%0A    %7D%0A%0A    public ImmutableList%3CEntityRecordChange%3E recordsAfterCommit() %7B%0A        return ImmutableList.copyOf(recordsAfterCommit);%0A    %7D%0A%0A    public Error lastError() %7B%0A        return lastError;%0A    %7D%0A%0A    public
+// Do nothing.%0A    %7D%0A%0A    @Override%0A    public void onBeforeCommit(@NonValidated EntityRecord entityRecord) %7B%0A        // Do nothing.%0A    %7D%0A%0A    @Override%0A    public void onTransactionFailed(Event cause, @NonValidated
  Ent
@@ -2781,26 +2781,20 @@
 ord 
-lastErrored
+entity
 Record
-(
 ) %7B%0A
@@ -2805,200 +2805,125 @@
     
-return lastErroredRecord;%0A    %7D%0A%0A    public Event getLastRejection() %7B%0A        return lastRejection;%0A    %7D%0A%0A    public EntityRecord getLastRejectedRecord() %7B%0A        return lastRejectedRecord;
+// Do nothing.%0A    %7D%0A%0A    @Override%0A    public void onAfterCommit(EntityRecordChange change) %7B%0A        // Do nothing.
 %0A   

Remove the unused code.