/*
 * Copyright 2020, TeamDev. All rights reserved.
 *
 * 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.aggregate.given.repo;

import io.spine.base.CommandMessage;
import io.spine.server.aggregate.AggregateRepository;
import io.spine.server.entity.given.Given;
import io.spine.server.type.CommandEnvelope;
import io.spine.test.aggregate.AggProject;
import io.spine.test.aggregate.ProjectId;
import io.spine.test.aggregate.command.AggAddTask;
import io.spine.test.aggregate.command.AggCreateProject;
import io.spine.test.aggregate.command.AggStartProject;
import io.spine.testdata.Sample;

import static io.spine.server.aggregate.given.dispatch.AggregateMessageDispatcher.dispatchCommand;
import static io.spine.server.aggregate.given.repo.AggregateRepositoryTestEnv.requestFactory;
import static io.spine.testdata.Sample.builderForType;

/** Utility factory for test aggregates. */
public class GivenAggregate {

    private final AggregateRepository<ProjectId, ProjectAggregate, AggProject> repository;

    public GivenAggregate(AggregateRepository<ProjectId, ProjectAggregate, AggProject> repository) {
        this.repository = repository;
    }

    public ProjectAggregate withUncommittedEvents() {
        return withUncommittedEvents(Sample.messageOfType(ProjectId.class));
    }

    public ProjectAggregate withUncommittedEvents(ProjectId id) {
        ProjectAggregate aggregate = Given.aggregateOfClass(ProjectAggregate.class)
                                          .withId(id)
                                          .build();

        AggCreateProject.Builder createProject = builderForType(AggCreateProject.class);
        createProject.setProjectId(id);
        AggAddTask.Builder addTask = builderForType(AggAddTask.class);
        addTask.setProjectId(id);
        AggStartProject.Builder startProject = builderForType(AggStartProject.class);
        startProject.setProjectId(id);

        dispatchCommand(aggregate, repository, env(createProject.build()));
        dispatchCommand(aggregate, repository, env(addTask.build()));
        dispatchCommand(aggregate, repository, env(startProject.build()));

        return aggregate;
    }

    /** Generates a command for the passed message and wraps it into the envelope. */
    private static CommandEnvelope env(CommandMessage commandMessage) {
        return CommandEnvelope.of(requestFactory().command()
                                                  .create(commandMessage));
    }
}

@@ -1767,16 +1767,19 @@
 pe;%0A%0A/**
+%0A *
  Utility
@@ -1807,17 +1807,19 @@
 regates.
- 
+%0A *
 */%0Apubli
@@ -2315,19 +2315,38 @@
 ate 
-aggregate =
+givenProject =%0A               
  Giv
@@ -2414,62 +2414,20 @@
     
-                     .withId(id)%0A                     
+.withId(id)%0A
     
@@ -2826,57 +2826,159 @@
     
-dispatchCommand(agg
+new ToProject(givenProject)%0A                .dispatch(c
 re
-g
 ate
-, repository, env(create
+Project.build())%0A                .dispatch(addTask.build())%0A                .dispatch(start
 Proj
@@ -2981,33 +2981,32 @@
 Project.build())
-)
 ;%0A        dispat
@@ -3003,70 +3003,420 @@
     
-dispatchCommand(aggregate, repository, env(addTask.build()));%0A
+return givenProject;%0A    %7D%0A%0A    /**%0A     * Method object which simplifies dispatching of commands to %7B@link ProjectAggregate%7D instances.%0A     */%0A    private final class ToProject %7B%0A%0A        private final ProjectAggregate aggregate;%0A%0A        private ToProject(ProjectAggregate aggregate) %7B%0A            this.aggregate = aggregate;%0A        %7D%0A%0A        private ToProject dispatch(CommandMessage commandMessage) %7B%0A    
     
@@ -3466,33 +3466,30 @@
 env(
-startProject.build()));%0A%0A
+commandMessage));%0A    
     
@@ -3503,26 +3503,29 @@
 urn 
-aggregate;%0A
+this;%0A   
     
+ 
 %7D%0A%0A
+    
     
@@ -3602,24 +3602,28 @@
 nvelope. */%0A
+    
     private 
@@ -3622,23 +3622,16 @@
 private 
-static 
 CommandE
@@ -3667,32 +3667,36 @@
 mmandMessage) %7B%0A
+    
         return C
@@ -3790,16 +3790,20 @@
         
+    
 .create(
@@ -3816,20 +3816,30 @@
 dMessage));%0A
+        %7D%0A
     %7D%0A%7D%0A

Improve the code readability.