/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.ignite.internal.binary;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.client.ClientCache;
import org.apache.ignite.client.Config;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.BinaryConfiguration;
import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.internal.binary.BinaryMarshallerSelfTest.TestClass1;
import org.apache.ignite.internal.binary.mutabletest.GridBinaryTestClasses.TestObjectContainer;
import org.apache.ignite.internal.processors.cache.CacheEnumOperationsAbstractTest.TestEnum;
import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.testframework.GridTestUtils;
import org.junit.Test;

import static org.apache.ignite.internal.processors.cache.CacheEnumOperationsAbstractTest.TestEnum.VAL1;
import static org.apache.ignite.internal.processors.cache.CacheEnumOperationsAbstractTest.TestEnum.VAL2;
import static org.apache.ignite.internal.processors.cache.CacheEnumOperationsAbstractTest.TestEnum.VAL3;
import static org.junit.Assert.assertArrayEquals;

/** */
public class BinaryArraySelfTest extends AbstractBinaryArraysTest {
    /** */
    private static Ignite server;

    /** */
    private static Ignite client;

    /** */
    private static CacheAdapter<Object, Object> srvCache;

    /** */
    private static CacheAdapter<Object, Object> cliCache;

    /** */
    private static final Function<Object, Object> TO_TEST_CLS = arr -> arr instanceof TestClass1[][]
        ? new TestClass2(null, (TestClass1[][])arr)
        : new TestClass2((TestClass1[])arr, null);

    /** {@inheritDoc} */
    @Override protected void beforeTestsStarted() throws Exception {
        super.beforeTestsStarted();

        server = startGrid(0);
        client = startClientGrid(1);

        srvCache = new IgniteCacheAdapter<>(server.createCache(DEFAULT_CACHE_NAME));
        cliCache = new IgniteCacheAdapter<>(client.getOrCreateCache(DEFAULT_CACHE_NAME));
    }

    /** */
    @Test
    public void testArrayKey() {
        doTestKeys(srvCache, arr -> arr);
        doTestKeys(cliCache, arr -> arr);
        try (IgniteClient thinClient = thinClient()) {
            // Using other cache because
            // 1. Removed entry store in `GridCacheAdapter#map`
            // 2. Bytes representation of multidimensional BinaryArray from thin client and Ignite node differ.
            // 2a. Thin client reads array from byte stream and preserve pointer equality (look at #dataToTest() -> arr6).
            // 2b. Client node invoke `CacheObjectBinaryProcessorImpl#marshallToBinary` before storing
            // which breaks link equality of array
            // 3. During invocation of `put` node inserts key representation from previous invocation of methods from client node.
            // 4. This lead to `ClientCache#containsKey` can't find key because
            // it invokes search based equality on `byte[]` key representaion.
            //
            // This doesn't happen in `useBinaryArrays=false` becuase Ignite node obtain `Object[]`
            // from byte stream and invoke marshallToBinary for it which also breaks pointer equality
            // therefore during serialization handle will NOT be used.
            // In `useBinaryArrays=true` node read `BinaryArray` from stream which mean no need to marshall to binary
            // therefore link equality preserved which mean during serialization handle will be used.
            doTestKeys(
                new ClientCacheAdapter<>(thinClient.getOrCreateCache(DEFAULT_CACHE_NAME + (useBinaryArrays ? "2" : ""))),
                arr -> arr
            );
        }
    }

    /** */
    @Test
    public void testArrayFieldInKey() {
        doTestKeys(srvCache, TO_TEST_CLS);
        doTestKeys(cliCache, TO_TEST_CLS);
        try (IgniteClient thinClient = thinClient()) {
            doTestKeys(new ClientCacheAdapter<>(thinClient.getOrCreateCache(DEFAULT_CACHE_NAME)), TO_TEST_CLS);
        }
    }

    /** */
    @Test
    public void testArrayValue() {
        doTestValue(srvCache, arr -> arr, false, false);
        doTestValue(cliCache, arr -> arr, false, false);
        doTestValue(srvCache, arr -> arr, true, false);
        doTestValue(cliCache, arr -> arr, true, false);

        try (IgniteClient thinClient = thinClient()) {
            ClientCacheAdapter<Object, Object> c =
                new ClientCacheAdapter<>(thinClient.getOrCreateCache(DEFAULT_CACHE_NAME));

            doTestValue(c, arr -> arr, false, false);
            doTestValue(c, arr -> arr, true, false);
        }
    }

    /** */
    @Test
    public void testArrayFieldInValue() {
        doTestValue(srvCache, TO_TEST_CLS, false, true);
        doTestValue(cliCache, TO_TEST_CLS, false, true);
        doTestValue(srvCache, TO_TEST_CLS, true, true);
        doTestValue(cliCache, TO_TEST_CLS, true, true);
        try (IgniteClient thinClient = thinClient()) {
            ClientCacheAdapter<Object, Object> c =
                new ClientCacheAdapter<>(thinClient.getOrCreateCache(DEFAULT_CACHE_NAME));

            doTestValue(c, TO_TEST_CLS, false, true);
            doTestValue(c, TO_TEST_CLS, true, true);
        }
    }

    /** */
    @Test
    public void testArraySerDe() {
        checkArraySerDe(arr -> {
            Object obj = server.binary().toBinary(arr);

            return useBinaryArrays
                ? ((BinaryObject)obj).deserialize()
                : PlatformUtils.unwrapBinariesInArray((Object[])obj);
        }, false);
    }

    /** */
    @Test
    public void testArrayFieldSerDe() {
        checkArraySerDe(arr -> {
            BinaryObject bObj = server.binary().toBinary(new TestObjectContainer(arr));

            return ((TestObjectContainer)bObj.deserialize()).foo;
        }, true);
    }

    /** */
    @Test
    public void testBinaryModeArray() {
        putInBinaryGetRegular(srvCache);
        putInBinaryGetRegular(cliCache);
        try (IgniteClient thinClient = thinClient()) {
            putInBinaryGetRegular(new ClientCacheAdapter<>(thinClient.getOrCreateCache(DEFAULT_CACHE_NAME)));
        }
    }

    /** */
    @Test
    public void testPrimitivesArrays() {
        doTestBoxedPrimitivesArrays(srvCache);
        doTestBoxedPrimitivesArrays(cliCache);

        doTestPrimitivesArrays(srvCache);
        doTestPrimitivesArrays(cliCache);

        try (IgniteClient thinClient = thinClient()) {
            ClientCacheAdapter<Object, Object> c = new
                ClientCacheAdapter<>(thinClient.getOrCreateCache(DEFAULT_CACHE_NAME));

            doTestBoxedPrimitivesArrays(c);
            doTestPrimitivesArrays(c);
        }
    }

    /** */
    @Test
    public void testSimpleBinaryArrayFieldSerDe() {
        TestClass1 src = new TestClass1();

        BinaryMarshallerSelfTest.SimpleObject sobj = GridTestUtils.getFieldValue(src, "obj");

        GridTestUtils.setFieldValue(sobj, "objArr", new Object[] {"string", 1L, null});

        BinaryObject obj = server.binary().toBinary(src);

        BinaryObject simpleObj = obj.field("obj");
        Object objArr = simpleObj.field("objArr");

        assertEquals(useBinaryArrays ? BinaryArray.class : Object[].class, objArr.getClass());

        Object deser = obj.deserialize();

        assertEquals(TestClass1.class, deser.getClass());

        sobj = GridTestUtils.getFieldValue(deser, "obj");

        Object[] arr = GridTestUtils.getFieldValue(sobj, "objArr");

        assertNotNull(arr);
        assertEquals(3, arr.length);
        assertEquals("string", arr[0]);
        assertEquals(1L, arr[1]);
        assertNull(arr[2]);
    }

    /** */
    @Test
    public void testArrayOfCollectionSerDe() {
        List<TestClass1> l1 = new ArrayList<>(F.asList(new TestClass1(), new TestClass1()));
        List<TestClass1> l2 = new ArrayList<>(F.asList(new TestClass1(), new TestClass1()));
        List<TestClass1> l3 = new ArrayList<>(F.asList(new TestClass1(), new TestClass1()));

        List[] arr = new List[] { l1, l2, l3 };

        Object res = server.binary().toBinary(arr);
        Object[] res0;

        if (useBinaryArrays) {
            assertTrue(res instanceof BinaryArray);

            res0 = ((BinaryArray)res).deserialize();
        }
        else {
            assertTrue(res instanceof Object[]);

            res0 = PlatformUtils.unwrapBinariesInArray((Object[])res);
        }

        assertEquals(arr.length, res0.length);

        for (int i = 0; i < arr.length; i++)
            assertEqualsCollections(arr[i], (Collection<?>)res0[i]);
    }

    /** */
    @Test
    public void testArrayOfBinariesSerDe() {
        BinaryObject[] arr = new BinaryObject[] {
            server.binary().toBinary(new TestClass1()),
            server.binary().toBinary(new TestClass1())
        };

        Object obj = server.binary().toBinary(arr);

        Object deser;

        if (useBinaryArrays) {
            assertTrue(obj instanceof BinaryArray);

            deser = ((BinaryArray)obj).deserialize();
        }
        else {
            assertTrue(obj instanceof Object[]);

            deser = PlatformUtils.unwrapBinariesInArray((Object[])obj);
        }

        assertEquals(Object[].class, deser.getClass());

        Object[] res = ((Object[])deser);

        assertEquals(2, res.length);
        assertTrue(res[0] instanceof TestClass1);
        assertTrue(res[1] instanceof TestClass1);
    }

    /** */
    private void doTestKeys(CacheAdapter<Object, Object> c, Function<Object, Object> wrap) {
        List<?> keys = dataToTest();

        for (int i = 0; i < keys.size(); i++) {
            Object key = wrap.apply(keys.get(i));

            assertFalse(c.containsKey(key));

            c.put(key, i);

            assertTrue(c.containsKey(key));
            assertEquals(i, c.get(key));
            assertTrue(c.replace(key, i, i + 1));
            assertEquals(i + 1, c.get(key));
            assertTrue(c.remove(key));
        }
    }

    /** */
    private void doTestValue(
        CacheAdapter<Object, Object> c,
        Function<Object, Object> wrap,
        boolean keepBinary,
        boolean alwaysSameType
    ) {
        AtomicInteger cntr = new AtomicInteger();

        checkArraySerDe(arr -> {
            c.put(cntr.getAndIncrement(), wrap.apply(arr));

            Object obj;

            if (keepBinary) {
                obj = c.withKeepBinary().get(cntr.get() - 1);

                if (obj instanceof BinaryObject)
                    obj = ((BinaryObject)obj).deserialize();
                else
                    obj = PlatformUtils.unwrapBinariesInArray((Object[])obj);
            }
            else
                obj = c.get(cntr.get() - 1);

            if (obj instanceof Object[])
                return obj;

            TestClass2 cached = (TestClass2)obj;

            return cached.arr != null ? cached.arr : cached.arr2;
        }, alwaysSameType);

        List<?> vals = dataToTest();

        for (int i = 0; i < vals.size(); i++)
            assertTrue(c.replace(i, wrap.apply(vals.get(i)), wrap.apply(vals.get((i + 1) % vals.size()))));

        for (int i = 0; i < cntr.get(); i++)
            assertTrue(c.remove(i));
    }

    /** */
    private List<?> dataToTest() {
        TestClass1[][] arr5 = new TestClass1[3][2];
        TestClass1[][] arr6 = new TestClass1[2][2];

        arr5[0] = new TestClass1[] {new TestClass1()};
        arr5[1] = new TestClass1[] {new TestClass1()};

        // arr6[0] == arr6[1]
        arr6[0] = new TestClass1[] {new TestClass1()};
        arr6[1] = arr6[0];

        return F.asList(
            new TestClass1[0],
            new TestClass1[1][2],
            new TestClass1[] {new TestClass1(), new TestClass1()},
            arr5,
            arr6
        );
    }

    /** */
    private void putRegularGetInBinary(IgniteCache<Object, Object> c) {
        List<?> vals = dataToTest();

        for (Object val : vals) {
            c.put(1, val);

            Object obj = c.withKeepBinary().get(1);

            assertEquals(useBinaryArrays ? BinaryArray.class : Object[].class, obj.getClass());

            if (useBinaryArrays)
                assertEquals(val.getClass(), ((BinaryObject)obj).deserialize().getClass());

            assertTrue(c.remove(1));
        }
    }

    /** */
    private void putInBinaryGetRegular(CacheAdapter<Object, Object> c) {
        Runnable checker = () -> {
            Object[] arr = (Object[])c.get(1);

            assertTrue(arr[0] instanceof TestClass1);
            assertTrue(arr[1] instanceof TestClass1);

            assertTrue(c.withKeepBinary().remove(1));

            assertNull(c.withKeepBinary().get(1));
            assertNull(c.get(1));
        };

        {
            BinaryObject[] src = new BinaryObject[] {
                server.binary().toBinary(new TestClass1()),
                server.binary().toBinary(new TestClass1())
            };

            c.withKeepBinary().put(1, src);

            checker.run();
        }

        {
            Object src = server.binary().toBinary(
                new Object[] {
                    server.binary().toBinary(new TestClass1()),
                    server.binary().toBinary(new TestClass1())
                }
            );

            assertEquals(useBinaryArrays ? BinaryArray.class : Object[].class, src.getClass());

            c.withKeepBinary().put(1, src);

            checker.run();
        }
    }

    /** */
    private void doTestPrimitivesArrays(CacheAdapter<Object, Object> c) {
        Object[] data = new Object[] {
            new byte[] {1, 2, 3},
            new short[] {1, 2, 3},
            new int[] {1, 2, 3},
            new long[] {1L, 2L, 3L},
            new float[] {1f, 2f, 3f},
            new double[] {1d, 2d, 3d},
            new char[] {'a', 'b', 'c'},
            new boolean[] {true, false}
        };

        for (Object item : data) {
            c.put(1, item);

            Object item0 = c.get(1);

            assertTrue(c.replace(1, item, item));
            assertTrue(c.remove(1));
            assertEquals(item.getClass(), item0.getClass());
            assertEqualsArraysAware(item, item0);

            c.put(item, 1);

            assertTrue(c.containsKey(item));
            assertEquals(1, c.get(item));
            assertTrue(c.replace(item, 1, 2));
            assertTrue(c.remove(item));
        }
    }

    /** */
    private void doTestBoxedPrimitivesArrays(CacheAdapter<Object, Object> c) {
        Object[] data = new Object[] {
            new Byte[] {1, 2, 3},
            new Short[] {1, 2, 3},
            new Integer[] {1, 2, 3},
            new Long[] {1L, 2L, 3L},
            new Float[] {1f, 2f, 3f},
            new Double[] {1d, 2d, 3d},
            new Character[] {'a', 'b', 'c'},
            new Boolean[] {true, false},
            new TestEnum[] {VAL1, VAL2, VAL3}
        };

        for (Object item : data) {
            c.put(1, item);

            Object item0 = c.get(1);

            assertTrue(c.replace(1, item, item));
            assertTrue(c.remove(1));

            if (useBinaryArrays)
                assertEquals(item.getClass(), item0.getClass());

            assertTrue(Arrays.equals((Object[])item, (Object[])item0));

            c.put(item, 1);

            assertTrue(c.containsKey(item));
            assertEquals(1, c.get(item));
            assertTrue(c.replace(item, 1, 2));
            assertTrue(c.remove(item));

        }
    }

    /** */
    public void checkArraySerDe(Function<Object[], Object> serde, boolean sameArr) {
        for (Object[] arr : (List<Object[]>)dataToTest()) {
            Object deser = serde.apply(arr);

            assertEquals((useBinaryArrays || sameArr) ? arr.getClass() : Object[].class, deser.getClass());

            assertEquals(arr.length, ((Object[])deser).length);
            assertArrayEquals(arr, ((Object[])deser));

            if (arr instanceof TestClass1[][] && arr.length == 2 && sameArr) {
                Object[] val = (Object[])deser;

                // See dataToTest -> dataToTest -> arr6[0] == arr6[1]
                // Check the sanity of test data.
                assertSame(((TestClass1[][])arr)[0], ((TestClass1[][])arr)[1]);
                assertSame(val[0], val[1]);
            }
        }
    }

    /** */
    private IgniteClient thinClient() {
        return Ignition.startClient(new ClientConfiguration()
            .setAddresses(Config.SERVER)
            .setBinaryConfiguration(new BinaryConfiguration().setCompactFooter(true))
        );
    }

    /** */
    public static class TestClass2 {
        /** */
        final TestClass1[] arr;

        /** */
        final TestClass1[][] arr2;

        /** */
        public TestClass2(TestClass1[] arr, TestClass1[][] arr2) {
            this.arr = arr;
            this.arr2 = arr2;
        }
    }

    /** */
    public interface CacheAdapter<K, V> {
        /** */
        public V get(K key);

        /** */
        public void put(K key, V val);

        /** */
        public boolean replace(K key, V oldVal, V newVal);

        /** */
        public boolean remove(K key);

        /** */
        public boolean containsKey(K key);

        /** */
        public <K1, V1> CacheAdapter<K1, V1> withKeepBinary();
    }

    /** */
    private static class IgniteCacheAdapter<K, V> implements CacheAdapter<K, V> {
        /** */
        private final IgniteCache<K, V> c;

        /** */
        public IgniteCacheAdapter(IgniteCache<K, V> c) {
            this.c = c;
        }

        /** {@inheritDoc} */
        @Override public V get(K key) {
            return c.get(key);
        }

        /** {@inheritDoc} */
        @Override public void put(K key, V val) {
            c.put(key, val);

        }

        /** {@inheritDoc} */
        @Override public boolean replace(K key, V oldVal, V newVal) {
            return c.replace(key, oldVal, newVal);
        }

        /** {@inheritDoc} */
        @Override public boolean remove(K key) {
            return c.remove(key);
        }

        /** {@inheritDoc} */
        @Override public boolean containsKey(K key) {
            return c.containsKey(key);
        }

        /** {@inheritDoc} */
        @Override public <K1, V1> CacheAdapter<K1, V1> withKeepBinary() {
            return new IgniteCacheAdapter<>(c.withKeepBinary());
        }
    }

    /** */
    private static class ClientCacheAdapter<K, V> implements CacheAdapter<K, V> {
        /** */
        private final ClientCache<K, V> c;

        /** */
        public ClientCacheAdapter(ClientCache<K, V> c) {
            this.c = c;
        }

        /** {@inheritDoc} */
        @Override public V get(K key) {
            return c.get(key);
        }

        /** {@inheritDoc} */
        @Override public void put(K key, V val) {
            c.put(key, val);

        }

        /** {@inheritDoc} */
        @Override public boolean replace(K key, V oldVal, V newVal) {
            return c.replace(key, oldVal, newVal);
        }

        /** {@inheritDoc} */
        @Override public boolean remove(K key) {
            return c.remove(key);
        }

        /** {@inheritDoc} */
        @Override public boolean containsKey(K key) {
            return c.containsKey(key);
        }

        /** {@inheritDoc} */
        @Override public <K1, V1> CacheAdapter<K1, V1> withKeepBinary() {
            return new ClientCacheAdapter<>(c.withKeepBinary());
        }
    }
}
