package org.couchbase.mock.memcached.client;

import org.couchbase.mock.memcached.protocol.CommandCode;
import org.couchbase.mock.memcached.protocol.ErrorCode;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

/**
 * Created by mnunberg on 1/15/14.
 */
public class ClientResponse {
    private CommandCode code;
    private ErrorCode status;
    private ByteBuffer extras;
    private ByteBuffer key;
    private ByteBuffer value;
    private byte[] body;
    private int opaque;
    private byte opcode;

    long cas;

    public long getCas() {
        return cas;
    }

    public long getOpaque() {
        return opaque;
    }

    public String getKey() {
        return new String(key.array());
    }

    public String getValue() {
        return new String(value.array());
    }

    public ByteBuffer getRawValue() {
        return value.asReadOnlyBuffer();
    }

    public byte[] getExtras() {
        return extras.array();
    }

    public ErrorCode getStatus() {
        return status;
    }

    public byte getOpcode() {
        return opcode;
    }

    public CommandCode getComCode() {
        return code;
    }

    public boolean success() { return status == ErrorCode.SUCCESS; }


    public static ClientResponse read(InputStream input) throws IOException {
        byte[] header = new byte[24];
        int remaining = header.length;

        while (remaining > 0) {
            int nr = input.read(header, header.length-remaining, remaining);
            if (nr == -1) {
                break;
            }
            remaining -= nr;
        }

        if (remaining > 0) {
            throw new IOException("Incomplete read before stream closed");
        }

        ByteBuffer buf = ByteBuffer.wrap(header);
        byte magic = buf.get();
        if (magic != (byte)0x81) {
            throw new IOException("Illegal magic: " + magic);
        }

        ClientResponse ret = new ClientResponse();
        ret.opcode = buf.get();
        ret.code = CommandCode.valueOf(ret.opcode);

        short keylen = buf.getShort();
        byte extlen = buf.get();
        buf.get(); // ignore datatype

        ret.status = ErrorCode.valueOf(buf.getShort());
        int totalLen = buf.getInt();
        ret.opaque = buf.getInt();
        ret.cas = buf.getLong();
        ret.body = new byte[totalLen];
        ret.extras = ByteBuffer.wrap(ret.body, 0, extlen);
        ret.key = ByteBuffer.wrap(ret.body, extlen, keylen);
        ret.value = ByteBuffer.wrap(ret.body, extlen+keylen, totalLen - (extlen + keylen));

        remaining = ret.body.length;
        while (remaining > 0) {
            int nr = input.read(ret.body, ret.body.length-remaining, remaining);
            if (nr < 0) {
                throw new IOException("Incomplete read");
            }
            remaining -= nr;
        }

        return ret;
    }
}

@@ -237,16 +237,41 @@
 eBuffer;
+%0Aimport java.util.Arrays;
 %0A%0A/**%0A *
@@ -409,26 +409,22 @@
 private 
-ByteBuffer
+byte%5B%5D
  extras;
@@ -436,26 +436,22 @@
 private 
-ByteBuffer
+byte%5B%5D
  key;%0A  
@@ -460,26 +460,22 @@
 private 
-ByteBuffer
+byte%5B%5D
  value;%0A
@@ -736,24 +736,16 @@
 ring(key
-.array()
 );%0A    %7D
@@ -808,24 +808,16 @@
 ng(value
-.array()
 );%0A    %7D
@@ -875,31 +875,29 @@
 urn 
-value.asReadOnlyBuffer(
+ByteBuffer.wrap(value
 );%0A 
@@ -959,16 +959,8 @@
 tras
-.array()
 ;%0A  
@@ -2351,220 +2351,8 @@
 en%5D;
-%0A        ret.extras = ByteBuffer.wrap(ret.body, 0, extlen);%0A        ret.key = ByteBuffer.wrap(ret.body, extlen, keylen);%0A        ret.value = ByteBuffer.wrap(ret.body, extlen+keylen, totalLen - (extlen + keylen));
 %0A%0A  
@@ -2629,32 +2629,251 @@
  nr;%0A        %7D%0A%0A
+        ret.extras = Arrays.copyOfRange(ret.body, 0, extlen);%0A        ret.key = Arrays.copyOfRange(ret.body, extlen, extlen + keylen);%0A        ret.value = Arrays.copyOfRange(ret.body, extlen + keylen, ret.body.length);%0A
         return r

fix bad uses of ByteBuffer