/*
 * Copyright 2014-2017 Real Logic 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
 *
 * http://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 io.aeron.archiver;

import io.aeron.*;
import io.aeron.archiver.codecs.*;
import org.agrona.*;
import org.agrona.concurrent.*;
import uk.co.real_logic.sbe.ir.generated.MessageHeaderEncoder;

import static org.agrona.BitUtil.CACHE_LINE_LENGTH;

class ClientSessionProxy
{
    private static final int HEADER_LENGTH = MessageHeaderEncoder.ENCODED_LENGTH;
    private final IdleStrategy idleStrategy;
    private final UnsafeBuffer outboundBuffer;

    private final MessageHeaderEncoder outboundHeaderEncoder = new MessageHeaderEncoder();
    private final ControlResponseEncoder responseEncoder = new ControlResponseEncoder();
    private final RecordingStartedEncoder recordingStartedEncoder = new RecordingStartedEncoder();
    private final RecordingStoppedEncoder recordingStoppedEncoder = new RecordingStoppedEncoder();

    ClientSessionProxy(final IdleStrategy idleStrategy)
    {
        this.idleStrategy = idleStrategy;
        //TODO: How will the buffer length be verified?
        outboundBuffer =  new UnsafeBuffer(BufferUtil.allocateDirectAligned(4 * 1024, CACHE_LINE_LENGTH));

        outboundHeaderEncoder.wrap(outboundBuffer, 0);
        responseEncoder.wrap(outboundBuffer, MessageHeaderEncoder.ENCODED_LENGTH);
        recordingStartedEncoder.wrap(outboundBuffer, MessageHeaderEncoder.ENCODED_LENGTH);
        recordingStoppedEncoder.wrap(outboundBuffer, MessageHeaderEncoder.ENCODED_LENGTH);
    }

    void sendResponse(final ExclusivePublication reply, final String err, final long correlationId)
    {
        outboundHeaderEncoder
            .blockLength(ControlResponseEncoder.BLOCK_LENGTH)
            .templateId(ControlResponseEncoder.TEMPLATE_ID)
            .schemaId(ControlResponseEncoder.SCHEMA_ID)
            .version(ControlResponseEncoder.SCHEMA_VERSION);

        // reset encoder limit is required for variable length messages
        responseEncoder.limit(MessageHeaderEncoder.ENCODED_LENGTH + ControlResponseEncoder.BLOCK_LENGTH);
        responseEncoder.correlationId(correlationId);
        if (!Strings.isEmpty(err))
        {
            responseEncoder.err(err);
        }

        final int length = HEADER_LENGTH + responseEncoder.encodedLength();
        while (true)
        {
            final long result = reply.offer(outboundBuffer, 0, length);
            if (result > 0)
            {
                idleStrategy.reset();
                break;
            }

            if (result == Publication.NOT_CONNECTED || result == Publication.CLOSED)
            {
                throw new IllegalStateException("Response channel is down: " + reply);
            }

            idleStrategy.idle();
        }
    }
}

@@ -731,71 +731,8 @@
 t.*;
-%0Aimport uk.co.real_logic.sbe.ir.generated.MessageHeaderEncoder;
 %0A%0Aim
@@ -1023,24 +1023,23 @@
 Encoder 
-outbound
+message
 HeaderEn
@@ -1166,206 +1166,8 @@
 r();
-%0A    private final RecordingStartedEncoder recordingStartedEncoder = new RecordingStartedEncoder();%0A    private final RecordingStoppedEncoder recordingStoppedEncoder = new RecordingStoppedEncoder();
 %0A%0A  
@@ -1435,913 +1435,217 @@
 ));%0A
-%0A        outboundHeaderEncoder.wrap(outboundBuffer, 0);%0A        responseEncoder.wrap(outboundBuffer, MessageHeaderEncoder.ENCODED_LENGTH);%0A        recordingStartedEncoder.wrap(outboundBuffer, MessageHeaderEncoder.ENCODED_LENGTH);%0A        recordingStoppedEncoder.wrap(outboundBuffer, MessageHeaderEncoder.ENCODED_LENGTH);%0A    %7D%0A%0A    void sendResponse(final ExclusivePublication reply, final String err, final long correlationId)%0A    %7B%0A        outboundHeaderEncoder%0A            .blockLength(ControlResponseEncoder.BLOCK_LENGTH)%0A            .templateId(ControlResponseEncoder.TEMPLATE_ID)%0A            .schemaId(ControlResponseEncoder.SCHEMA_ID)%0A            .version(ControlResponseEncoder.SCHEMA_VERSION);%0A%0A        // reset encoder limit is required for variable length messages%0A        responseEncoder.limit(MessageHeaderEncoder.ENCODED_LENGTH + ControlResponseEncoder.BLOCK_LENGTH);%0A        responseEncoder
+    %7D%0A%0A    void sendResponse(final ExclusivePublication reply, final String err, final long correlationId)%0A    %7B%0A        responseEncoder.wrapAndApplyHeader(outboundBuffer, 0, messageHeaderEncoder)%0A            
 .cor
@@ -1671,16 +1671,17 @@
 ionId);%0A
+%0A
         

Use wrapAndApplyHeader in ClientSessionProxy.