/*
 * Copyright 2020 Monotonic Ltd.
 *
 * 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
 *
 * 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 uk.co.real_logic.artio.engine.logger;

import io.aeron.ExclusivePublication;
import io.aeron.logbuffer.BufferClaim;
import io.aeron.logbuffer.Header;
import org.agrona.DirectBuffer;
import org.agrona.MutableDirectBuffer;
import org.agrona.concurrent.IdleStrategy;
import uk.co.real_logic.artio.DebugLogger;
import uk.co.real_logic.artio.Pressure;
import uk.co.real_logic.artio.messages.ILinkMessageEncoder;
import uk.co.real_logic.artio.messages.MessageHeaderEncoder;

import static uk.co.real_logic.artio.LogTag.REPLAY_ATTEMPT;

// In ILink cases the UUID is used as a sessionId
public class ILinkReplayerSession extends ReplayerSession
{
    private static final ILinkMessageEncoder ILINK_MESSAGE_ENCODER = new ILinkMessageEncoder();

    private enum State
    {
        REPLAYING,
        SEND_COMPLETE_MESSAGE
    }

    private State state;

    public ILinkReplayerSession(
        final long connectionId,
        final BufferClaim bufferClaim,
        final IdleStrategy idleStrategy,
        final int maxClaimAttempts,
        final ExclusivePublication publication,
        final ReplayQuery replayQuery,
        final int beginSeqNo,
        final int endSeqNo,
        final long sessionId)
    {
        super(connectionId, bufferClaim, idleStrategy, maxClaimAttempts, publication, replayQuery, beginSeqNo, endSeqNo,
            sessionId, 0);

        state = State.REPLAYING;
    }

    MessageTracker messageTracker()
    {
        return new ILink3MessageTracker(this);
    }

    public boolean attemptReplay()
    {
        switch (state)
        {
            case REPLAYING:
            {
                if (replayOperation.attemptReplay())
                {
                    DebugLogger.log(REPLAY_ATTEMPT, "ReplayerSession: REPLAYING step");
                    state = State.SEND_COMPLETE_MESSAGE;
                }
                return false;
            }

            case SEND_COMPLETE_MESSAGE:
            {
                return sendCompleteMessage();
            }

            default:
                return false;
        }
    }

    // Callback for replayed messages
    public Action onFragment(
        final DirectBuffer buffer, final int offset, final int length, final Header header)
    {
        // Update connection id in case we're replaying from a previous connection.
        ILINK_MESSAGE_ENCODER.wrap((MutableDirectBuffer)buffer, offset + MessageHeaderEncoder.ENCODED_LENGTH);
        ILINK_MESSAGE_ENCODER.connection(connectionId);

        return Pressure.apply(publication.offer(buffer, offset, length));
    }

    public void close()
    {
        if (replayOperation != null)
        {
            replayOperation.close();
        }
    }
}