package org.xbib.datastructures.json.noggit;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class TestObjectBuilder {

    private void test(String val, Object expected) throws IOException {
        val = val.replace('\'', '"');
        Object v = ObjectBuilder.fromJSON(val);

        String s1 = JSONUtil.toJSON(v, -1);
        String s2 = JSONUtil.toJSON(expected, -1);
        assertEquals(s1, s2);

        // not make sure that it round-trips correctly
        JSONParser p2 = TestJSONParser.getParser(s1);
        Object v2 = ObjectBuilder.getVal(p2);
        String s3 = JSONUtil.toJSON(v2, -1);
        assertEquals(s1, s3);
    }

    public static List<Object> L(Object... lst) {
        return Arrays.asList(lst);
    }

    public static Object[] A(Object... lst) {
        return lst;
    }

    public static Map<String, Object> O(Object... lst) {
        LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
        for (int i = 0; i < lst.length; i += 2) {
            map.put(lst[i].toString(), lst[i + 1]);
        }
        return map;
    }

    @Test
    public void testWithoutStartingBraces() throws IOException {
        JSONParser parser = new JSONParser("a: {key:val1}b:{key:val2}");
        parser.setFlags(JSONParser.FLAGS_DEFAULT | JSONParser.OPTIONAL_OUTER_BRACES | JSONParser.ALLOW_MISSING_COLON_COMMA_BEFORE_OBJECT);
        ObjectBuilder objectBuilder = new ObjectBuilder(parser);
        String s1 = JSONUtil.toJSON(objectBuilder.getObject(), -1);
        String expected = JSONUtil.toJSON(O("a", O("key", "val1"), "b", O("key", "val2")), -1);
        assertEquals(s1, expected);
    }

    private void testVariations(String str, Object expected) throws IOException {
        test("[" + str + "]", L(expected));
        test("[" + str + "," + str + "]", L(expected, expected));
        test("[" + str + "," + str + "]", A(expected, expected));
        test("{'foo':" + str + "}", O("foo", expected));
        test("{'foo':" + str + ",'bar':{'a':" + str + "},'baz':[" + str + "],'zzz':[" + str + "]}",
                O("foo", expected, "bar", O("a", expected), "baz", L(expected), "zzz", A(expected)));

    }

    @Test
    public void testBuilder() throws IOException {
        testVariations("[]", L());
        testVariations("[]", L());
        testVariations("{}", O());
        testVariations("[[]]", L(L()));
        testVariations("{'foo':{}}", O("foo", O()));
        testVariations("[false,true,1,1.4,null,'hi']", L(false, true, 1, 1.4, null, "hi"));
        testVariations("'hello'", "hello".toCharArray());

        // test array types
        testVariations("[[10,20],['a','b']]", L(A(10, 20), A("a", "b")));
        testVariations("[1,2,3]", new int[]{1, 2, 3});
        testVariations("[1,2,3]", new long[]{1, 2, 3});
        testVariations("[1.0,2.0,3.0]", new float[]{1, 2, 3});
        testVariations("[1.0,2.0,3.0]", new double[]{1, 2, 3});
        testVariations("[1,2,3]", new short[]{1, 2, 3});
        testVariations("[1,2,3]", new byte[]{1, 2, 3});
        testVariations("[false,true,false]", new boolean[]{false, true, false});
    }

}
