package com.yahoo.slab.perf;

import com.yahoo.slab.SlabStorage;
import com.yahoo.slab.flyweight.AbstractSlabFlyweight;

public class BeanFlyweight extends AbstractSlabFlyweight<Bean> implements Bean {

    private final int myLongArrayFixedSize;
    private final int myCharArrayFixedSize;

    private int myUnsignedIntOffset;
    private int myByteOffset;
    private int myDoubleOffset;
    private int myLongArrayOffset;
    private int myCharArrayOffset;


    public BeanFlyweight(final int myLongArrayFixedSize, final int myCharArrayFixedSize) {
        this.myLongArrayFixedSize = myLongArrayFixedSize;
        this.myCharArrayFixedSize = myCharArrayFixedSize;
    }

    @Override
    public void map(final SlabStorage storage, final long address) {
        super.map(storage, address);
        this.myUnsignedIntOffset = 0;
        this.myByteOffset = storage.getIntOffset();
        this.myDoubleOffset= this.myByteOffset + storage.getByteOffset();
        this.myLongArrayOffset= this.myDoubleOffset + storage.getDoubleOffset();
        this.myCharArrayOffset= this.myLongArrayOffset + storage.getLongArrayOffset(myLongArrayFixedSize);
        setFreeAddressOffset(this.myByteOffset);
    }

    @Override
    public boolean isNull(final SlabStorage storage, final long address) {
        return storage.getInt(address) < 0; // piggy back on unsigned int to reduce memory for null flag
    }

    @Override
    public void setAsFreeAddress(final SlabStorage storage, final long address, final long nextFreeAddress) {
        super.setAsFreeAddress(storage, address, nextFreeAddress);
        storage.setInt(-1, address + myUnsignedIntOffset);  // piggy back on unsigned int to reduce memory for null flag
    }

    @Override
    public void dumpToStorage(final Bean bean, final SlabStorage storage, final long address) {
        long offset = storage.setInt(bean.getMyUnsignedInt(), address);
        offset = storage.setByte(bean.getMyByte(), offset);
        offset = storage.setDouble(bean.getMyDouble(), offset);
        offset = storage.setLongArray(bean.getMyLongArray(), offset);
        storage.setCharArray(bean.getMyCharArray(), offset);
    }

    @Override
    public int getStoredObjectSize(final SlabStorage storage) {
        return storage.getIntOffset() + storage.getByteOffset() + storage.getDoubleOffset() +
        storage.getLongArrayOffset(myLongArrayFixedSize) + storage.getCharArrayOffset(myCharArrayFixedSize);
    }

    @Override
    public Bean asBean() {
        return this;
    }

//////////////////////// Bean impl.

    @Override
    public int getMyUnsignedInt() {
        return getStorage().getInt(getMappedAddress() + myUnsignedIntOffset);
    }

    @Override
    public void setMyUnsignedInt(final int myUnsignedInt) {
        getStorage().setInt(myUnsignedInt, getMappedAddress() + myUnsignedIntOffset);
    }


    @Override
    public byte getMyByte() {
        return getStorage().getByte(getMappedAddress() + myByteOffset);
    }

    @Override
    public void setMyByte(final byte myByte) {
        getStorage().setByte(myByte, getMappedAddress() + myByteOffset);
    }

    @Override
    public double getMyDouble() {
        return getStorage().getDouble(getMappedAddress() + myDoubleOffset);
    }

    @Override
    public void setMyDouble(final double myDouble) {
        getStorage().setDouble(myDouble, getMappedAddress() + myDoubleOffset);
    }

    @Override
    public long[] getMyLongArray() {
        long[] container = new long[myLongArrayFixedSize];
        return getStorage().getLongArray(container, getMappedAddress() + myLongArrayOffset);
    }

    @Override
    public void setMyLongArray(final long[] myLongArray) {
        getStorage().setLongArray(myLongArray, getMappedAddress() + myLongArrayOffset);
    }

    @Override
    public char[] getMyCharArray() {
        char[] container = new char[myCharArrayOffset];
        return getStorage().getCharArray(container, getMappedAddress() + myCharArrayOffset);
    }

    @Override
    public void setMyCharArray(final char[] myCharArray) {
        getStorage().setCharArray(myCharArray, getMappedAddress() + myCharArrayOffset);
    }
}

@@ -809,26 +809,23 @@
 s.my
-UnsignedInt
+LongArray
 Offset
- 
 = 0;
@@ -844,20 +844,46 @@
 s.my
-Byte
+DoubleOffset= this.myLongArray
 Offset 
-=
++
  sto
@@ -890,26 +890,52 @@
 rage.get
-IntOffset(
+LongArrayOffset(myLongArrayFixedSize
 );%0A     
@@ -940,36 +940,42 @@
      this.my
-Double
+UnsignedInt
 Offset
+ 
 = this.myByt
@@ -967,27 +967,29 @@
 et = this.my
-Byt
+Doubl
 eOffset + st
@@ -989,35 +989,37 @@
 et + storage.get
-Byt
+Doubl
 eOffset();%0A     
@@ -1028,31 +1028,27 @@
  this.my
-LongArray
+Byte
 Offset
+ 
 = this.m
@@ -1040,38 +1040,43 @@
 Offset = this.my
-Double
+UnsignedInt
 Offset + storage
@@ -1071,38 +1071,35 @@
 et + storage.get
-Double
+Int
 Offset();%0A      
@@ -1127,33 +1127,28 @@
 set= this.my
-LongArray
+Byte
 Offset + sto
@@ -1159,44 +1159,19 @@
 .get
-LongArrayOffset(myLongArrayFixedSize
+ByteOffset(
 );%0A 
@@ -1201,28 +1201,33 @@
 fset(this.my
-Byte
+LongArray
 Offset);%0A   
@@ -1311,32 +1311,142 @@
 long address) %7B%0A
+        int unsignedIntOffset = storage.getLongArrayOffset(myLongArrayFixedSize) + storage.getDoubleOffset();%0A
         return s
@@ -1466,16 +1466,36 @@
 (address
+ + unsignedIntOffset
 ) %3C 0; /
@@ -1744,32 +1744,142 @@
 xtFreeAddress);%0A
+        int unsignedIntOffset = storage.getLongArrayOffset(myLongArrayFixedSize) + storage.getDoubleOffset();%0A
         storage.
@@ -1899,19 +1899,17 @@
 dress + 
-myU
+u
 nsignedI
@@ -2131,19 +2131,25 @@
 rage.set
-Int
+LongArray
 (bean.ge
@@ -2151,27 +2151,25 @@
 an.getMy
-UnsignedInt
+LongArray
 (), addr
@@ -2202,19 +2202,21 @@
 rage.set
-Byt
+Doubl
 e(bean.g
@@ -2219,19 +2219,21 @@
 an.getMy
-Byt
+Doubl
 e(), off
@@ -2258,38 +2258,35 @@
 et = storage.set
-Double
+Int
 (bean.getMyDoubl
@@ -2272,38 +2272,43 @@
 etInt(bean.getMy
-Double
+UnsignedInt
 (), offset);%0A   
@@ -2328,33 +2328,28 @@
  storage.set
-LongArray
+Byte
 (bean.getMyL
@@ -2343,33 +2343,28 @@
 e(bean.getMy
-LongArray
+Byte
 (), offset);

fix flyweight in perf test to bypass JVM bug with unsafe