/*
 * Copyright 2012-2018 Chronicle Map Contributors
 *
 * 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 net.openhft.chronicle.map.example;

import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.bytes.BytesIn;
import net.openhft.chronicle.bytes.BytesMarshallable;
import net.openhft.chronicle.bytes.BytesOut;
import net.openhft.chronicle.hash.serialization.BytesReader;
import net.openhft.chronicle.hash.serialization.BytesWriter;
import net.openhft.chronicle.hash.serialization.impl.EnumMarshallable;
import net.openhft.chronicle.map.ChronicleMap;
import net.openhft.chronicle.map.ChronicleMapBuilder;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

public class PointListSerializationTest {

    @Test
    public void testComplexSerialization() {
        try (ChronicleMap<String, A> map = ChronicleMapBuilder
                .of(String.class, A.class)
                .valueMarshaller(AMarshaller.INSTANCE)
                .entries(5)
                .averageKeySize(4)
                .averageValueSize(1000)
                .create()) {
            A obj_A = new A();
            obj_A.str_ = "a";
            obj_A.list_ = new ArrayList<>();
            B b = new B();
            b.str_ = "b";
            obj_A.list_.add(b);
            map.put("KEY1", obj_A);
            map.get("KEY1");
        }
    }

    static final class AMarshaller implements BytesReader<A>, BytesWriter<A>,
            EnumMarshallable<AMarshaller> {
        public static final AMarshaller INSTANCE = new AMarshaller();

        private AMarshaller() {
        }

        @Override
        public void write(Bytes out, @NotNull A toWrite) {
            out.writeUtf8(toWrite.str_);
            if (toWrite.list_ != null) {
                int size = toWrite.list_.size();
                out.writeStopBit(size);
                for (int i = 0; i < size; i++) {
                    toWrite.list_.get(i).writeMarshallable(out);
                }
            } else {
                out.writeStopBit(-1);
            }
        }

        @NotNull
        @Override
        public A read(Bytes in, A using) {
            if (using == null)
                using = new A();
            using.str_ = in.readUtf8();
            int size = (int) in.readStopBit();
            if (size >= 0) {
                if (using.list_ == null) {
                    using.list_ = new ArrayList<>(size);
                } else {
                    using.list_.clear();
                    if (using.list_ instanceof ArrayList)
                        ((ArrayList) using.list_).ensureCapacity(size);
                }
                for (int i = 0; i < size; i++) {
                    B b = new B();
                    b.readMarshallable(in);
                    using.list_.add(b);
                }
            } else {
                assert size == -1;
                using.list_ = null;
            }
            return using;
        }

        @NotNull
        @Override
        public AMarshaller readResolve() {
            return INSTANCE;
        }
    }

    static class A {
        String str_;
        List<B> list_;
    }

    static class B implements BytesMarshallable {
        String str_;

        @Override
        public void readMarshallable(BytesIn in) {
            str_ = in.readUtf8();
        }

        @Override
        public void writeMarshallable(BytesOut out) {
            out.writeUtf8(str_);
        }
    }
}
