/*
 * Copyright 2017, TeamDev Ltd. 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.event;

import com.google.protobuf.Timestamp;
import io.spine.annotation.Internal;
import io.spine.core.Event;
import io.spine.core.EventContext;
import io.spine.core.EventEnvelope;
import io.spine.core.EventId;
import io.spine.core.Events;
import io.spine.server.entity.AbstractEntity;
import io.spine.server.entity.storage.Column;
import io.spine.type.TypeName;

import javax.annotation.Nullable;
import java.util.Comparator;

import static io.spine.util.Exceptions.newIllegalStateException;

/**
 * Stores an event.
 *
 * @author Alexander Yevsyukov
 * @author Dmytro Dashenkov
 */
@Internal
public class EEntity extends AbstractEntity<EventId, Event> {

    /**
     * The name of the entity column representing the time, when the event was fired.
     *
     * @see #getCreated()
     */
    static final String CREATED_TIME_COLUMN = "created";

    /**
     * The name of the entity column representing the Protobuf type name of the event.
     *
     * <p>For example, an Event of type {@code io.spine.test.TaskAdded} whose definition
     * is enclosed in the {@code spine.test} Protobuf package would have this entity column
     * equal to {@code "spine.test.TaskAdded"}.
     *
     * @see #getType()
     */
    static final String TYPE_COLUMN = "type";

    /** Cached value of the event message type name. */
    @Nullable
    private TypeName typeName;

    /**
     * Compares event entities by timestamps of events.
     */
    private static final Comparator<EEntity> comparator = new Comparator<EEntity>() {
        @Override
        public int compare(EEntity e1, EEntity e2) {
            final Event event1 = e1.getState();
            final Event event2 = e2.getState();
            final int result = Events.eventComparator()
                                     .compare(event1, event2);
            return result;
        }
    };

    EEntity(EventId id) {
        super(id);
    }

    EEntity(Event event) {
        this(event.getId());
        final Event compactedEvent = compact(event);
        updateState(compactedEvent);
    }

    /**
     * Returns comparator which sorts event entities chronologically.
     */
    static Comparator<EEntity> comparator() {
        return comparator;
    }

    /**
     * Retrieves the time of the event occurrence.
     *
     * <p>This method represents an entity column {@code created}.
     *
     * @return the time when the underlying event was fired
     * @see #CREATED_TIME_COLUMN
     */
    @Column
    public Timestamp getCreated() {
        return getState().getContext()
                         .getTimestamp();
    }

    /**
     * Retrieves the Protobuf type name of the enclosed event.
     *
     * <p>This method represents an entity column {@link TypeName}.
     *
     * @return the {@link TypeName} value of the event represented by this entity
     * @see #TYPE_COLUMN
     */
    @Column
    public String getType() {
        if (typeName == null) {
            typeName = EventEnvelope.of(getState())
                                    .getTypeName();
        }
        return typeName.value();
    }

    /**
     * Obtains the compacted version of the event.
     *
     * <p>A compacted version doesn't contain:
     * <ul>
     *     <li>the enrichment from the event context</li>
     *     <li>the enrichment from the origin</li>
     *     <li>nested origins if the origin is {@link EventContext}</li>
     * </ul>
     *
     * @param event the event to compact
     * @return the compacted event
     */
    private static Event compact(Event event) {
        final EventContext context = event.getContext();
        final EventContext.Builder resultContext = context.toBuilder()
                                                          .clearEnrichment();
        switch (resultContext.getOriginCase()) {
            case EVENT_CONTEXT:
                resultContext.setEventContext(context.getEventContext()
                                                     .toBuilder()
                                                     .clearOrigin()
                                                     .clearEnrichment());
                break;
            case REJECTION_CONTEXT:
                resultContext.setRejectionContext(context.getRejectionContext()
                                                         .toBuilder()
                                                         .clearEnrichment());
                break;
            case COMMAND_CONTEXT:
                // Does nothing.
                break;
            case ORIGIN_NOT_SET:
                throw newIllegalStateException("EventContext.origin should be set.");
        }
        return event.toBuilder()
                    .setContext(resultContext)
                    .build();
    }
}

@@ -5681,16 +5681,133 @@
 set.%22);%0A
+            default:%0A                throw newIllegalStateException(%22Not all of %60OriginCase%60 values were handled.%22);%0A
         

Add `default` statement for the `switch`