package org.apache.rya.indexing.accumulo.entity;

/*
 * 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.
 */

import static org.apache.rya.api.RdfCloudTripleStoreConstants.DELIM_BYTES;

import java.io.IOException;
import java.util.Collection;

import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Mutation;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.rya.api.domain.RyaStatement;
import org.apache.rya.api.domain.RyaType;
import org.apache.rya.api.domain.RyaIRI;
import org.apache.rya.api.resolver.RyaContext;
import org.apache.rya.api.resolver.RyaTypeResolverException;
import org.eclipse.rdf4j.model.vocabulary.XMLSchema;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.google.common.primitives.Bytes;

public class EntityCentricIndexTest {
    private static RyaStatement ryaStatement;
    private static Key subjectCentricKey;
    private static Key objectCentricKey;
    private static Value value;

    @BeforeClass
    public static void init() throws RyaTypeResolverException {
        String subjectStr = ":subject";
        String predicateStr = ":predicate";
        RyaType object = new RyaType(XMLSchema.INTEGER, "3");
        byte[][] objectBytes = RyaContext.getInstance().serializeType(object);
        String contextStr = "http://example.org/graph";
        // no qualifier since entity-centric index doesn't store an actual column qualifier
        long timestamp = (long) 123456789;
        byte[] visibilityBytes = "test_visibility".getBytes();
        byte[] valueBytes = "test_value".getBytes();
        subjectCentricKey = new Key(
                subjectStr.getBytes(),
                predicateStr.getBytes(),
                Bytes.concat(contextStr.getBytes(),
                        DELIM_BYTES, "object".getBytes(),
                        DELIM_BYTES, objectBytes[0], objectBytes[1]),
                visibilityBytes, timestamp);
        objectCentricKey = new Key(
                objectBytes[0],
                predicateStr.getBytes(),
                Bytes.concat(contextStr.getBytes(),
                        DELIM_BYTES, "subject".getBytes(),
                        DELIM_BYTES, subjectStr.getBytes(), objectBytes[1]),
                visibilityBytes, timestamp);
        ryaStatement = new RyaStatement(
                new RyaIRI(subjectStr),
                new RyaIRI(predicateStr),
                new RyaType(XMLSchema.INTEGER, "3"),
                new RyaIRI(contextStr),
                null, visibilityBytes, valueBytes, timestamp);
        value = new Value(valueBytes);
    }

    private static Mutation createMutationFromKeyValue(Key key, Value value) {
        Mutation m = new Mutation(key.getRow());
        m.put(key.getColumnFamily(), key.getColumnQualifier(),
                new ColumnVisibility(key.getColumnVisibility()), key.getTimestamp(), value);
        return m;
    }

    @Test
    public void testSerializeStatement() throws RyaTypeResolverException {
        Collection<Mutation> indexMutations = EntityCentricIndex.createMutations(ryaStatement);
        Assert.assertEquals("Serialization should produce two rows: subject-centric and object-centric.",
                2, indexMutations.size());
        Assert.assertTrue("Serialization of RyaStatement failed to create equivalent subject-centric row.",
                indexMutations.contains(createMutationFromKeyValue(subjectCentricKey, value)));
        Assert.assertTrue("Serialization of RyaStatement failed to create equivalent object-centric row.",
                indexMutations.contains(createMutationFromKeyValue(objectCentricKey, value)));
    }

    @Test
    public void testDeserializeSubjectRow() throws RyaTypeResolverException, IOException {
        RyaStatement deserialized = EntityCentricIndex.deserializeStatement(subjectCentricKey, value);
        Assert.assertEquals("Deserialization of subject-centric row failed to produce equivalent RyaStatement.",
                ryaStatement, deserialized);
    }

    @Test
    public void testDeserializeObjectRow() throws RyaTypeResolverException, IOException {
        RyaStatement deserialized = EntityCentricIndex.deserializeStatement(objectCentricKey, value);
        Assert.assertEquals("Deserialization of object-centric row failed to produce equivalent RyaStatement.",
                ryaStatement, deserialized);
    }
}
