/*
 * Copyright 2015 Open Networking Laboratory
 *
 * 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 org.onosproject.store.consistent.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.onosproject.cluster.NodeId;
import org.onosproject.store.service.DatabaseUpdate;
import org.onosproject.store.service.Transaction;
import org.onosproject.store.service.Versioned;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import net.kuujo.copycat.Task;
import net.kuujo.copycat.cluster.Cluster;
import net.kuujo.copycat.resource.ResourceState;
import static com.google.common.base.Preconditions.checkState;

/**
 * A database that partitions the keys across one or more database partitions.
 */
public class PartitionedDatabase implements Database {

    private final String name;
    private final Partitioner<String> partitioner;
    private final List<Database> partitions;
    private final AtomicBoolean isOpen = new AtomicBoolean(false);
    private static final String DB_NOT_OPEN = "Partitioned Database is not open";
    private TransactionManager transactionManager;

    public PartitionedDatabase(
            String name,
            Collection<Database> partitions) {
        this.name = name;
        this.partitions = partitions
                .stream()
                .sorted((db1, db2) -> db1.name().compareTo(db2.name()))
                .collect(Collectors.toList());
        this.partitioner = new SimpleKeyHashPartitioner(this.partitions);
    }

    /**
     * Returns the databases for individual partitions.
     * @return list of database partitions
     */
    public List<Database> getPartitions() {
        return partitions;
    }

    /**
     * Returns true if the database is open.
     * @return true if open, false otherwise
     */
    @Override
    public boolean isOpen() {
        return isOpen.get();
    }

    @Override
    public CompletableFuture<Set<String>> maps() {
        checkState(isOpen.get(), DB_NOT_OPEN);
        Set<String> mapNames = Sets.newConcurrentHashSet();
        return CompletableFuture.allOf(partitions
                .stream()
                .map(db -> db.maps().thenApply(mapNames::addAll))
                .toArray(CompletableFuture[]::new))
            .thenApply(v -> mapNames);
    }

    @Override
    public CompletableFuture<Map<String, Long>> counters() {
        checkState(isOpen.get(), DB_NOT_OPEN);
        Map<String, Long> counters = Maps.newConcurrentMap();
        return CompletableFuture.allOf(partitions
                .stream()
                .map(db -> db.counters()
                             .thenApply(m -> {
                                 counters.putAll(m);
                                 return null;
                             }))
                .toArray(CompletableFuture[]::new))
            .thenApply(v -> counters);
    }

    @Override
    public CompletableFuture<Integer> mapSize(String mapName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        AtomicInteger totalSize = new AtomicInteger(0);
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet))
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> totalSize.get());
    }

    @Override
    public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return mapSize(mapName).thenApply(size -> size == 0);
    }

    @Override
    public CompletableFuture<Boolean> mapContainsKey(String mapName, String key) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(mapName, key).mapContainsKey(mapName, key);
    }

    @Override
    public CompletableFuture<Boolean> mapContainsValue(String mapName, byte[] value) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        AtomicBoolean containsValue = new AtomicBoolean(false);
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(p -> p.mapContainsValue(mapName, value)
                               .thenApply(v -> containsValue.compareAndSet(false, v)))
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> containsValue.get());
    }

    @Override
    public CompletableFuture<Versioned<byte[]>> mapGet(String mapName, String key) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(mapName, key).mapGet(mapName, key);
    }

    @Override
    public CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(
            String mapName, String key, Match<byte[]> valueMatch,
            Match<Long> versionMatch, byte[] value) {
        return partitioner.getPartition(mapName, key).mapUpdate(mapName, key, valueMatch, versionMatch, value);

    }

    @Override
    public CompletableFuture<Result<Void>> mapClear(String mapName) {
        AtomicBoolean isLocked = new AtomicBoolean(false);
        checkState(isOpen.get(), DB_NOT_OPEN);
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(p -> p.mapClear(mapName)
                            .thenApply(v -> isLocked.compareAndSet(false, Result.Status.LOCKED == v.status())))
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> isLocked.get() ? Result.locked() : Result.ok(null));
    }

    @Override
    public CompletableFuture<Set<String>> mapKeySet(String mapName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        Set<String> keySet = Sets.newConcurrentHashSet();
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(p -> p.mapKeySet(mapName).thenApply(keySet::addAll))
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> keySet);
    }

    @Override
    public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        List<Versioned<byte[]>> values = new CopyOnWriteArrayList<>();
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(p -> p.mapValues(mapName).thenApply(values::addAll))
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> values);
    }

    @Override
    public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet();
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll))
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> entrySet);
    }

    @Override
    public CompletableFuture<Long> counterGet(String counterName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(counterName, counterName).counterGet(counterName);
    }

    @Override
    public CompletableFuture<Long> counterAddAndGet(String counterName, long delta) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(counterName, counterName).counterAddAndGet(counterName, delta);
    }

    @Override
    public CompletableFuture<Long> counterGetAndAdd(String counterName, long delta) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta);
    }


    @Override
    public CompletableFuture<Long> queueSize(String queueName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(queueName, queueName).queueSize(queueName);
    }

    @Override
    public CompletableFuture<Set<NodeId>> queuePush(String queueName, byte[] entry) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(queueName, queueName).queuePush(queueName, entry);
    }

    @Override
    public CompletableFuture<byte[]> queuePop(String queueName, NodeId nodeId) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(queueName, queueName).queuePop(queueName, nodeId);
    }

    @Override
    public CompletableFuture<byte[]> queuePeek(String queueName) {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return partitioner.getPartition(queueName, queueName).queuePeek(queueName);
    }

    @Override
    public CompletableFuture<Boolean> prepareAndCommit(Transaction transaction) {
        Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
        if (subTransactions.isEmpty()) {
            return CompletableFuture.completedFuture(true);
        } else if (subTransactions.size() == 1) {
            Entry<Database, Transaction> entry =
                    subTransactions.entrySet().iterator().next();
            return entry.getKey().prepareAndCommit(entry.getValue());
        } else {
            if (transactionManager == null) {
                throw new IllegalStateException("TransactionManager is not initialized");
            }
            return transactionManager.execute(transaction);
        }
    }

    @Override
    public CompletableFuture<Boolean> prepare(Transaction transaction) {
        Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
        AtomicBoolean status = new AtomicBoolean(true);
        return CompletableFuture.allOf(subTransactions.entrySet()
                .stream()
                .map(entry -> entry
                        .getKey()
                        .prepare(entry.getValue())
                        .thenApply(v -> status.compareAndSet(true, v)))
                .toArray(CompletableFuture[]::new))
            .thenApply(v -> status.get());
    }

    @Override
    public CompletableFuture<Boolean> commit(Transaction transaction) {
        Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
        return CompletableFuture.allOf(subTransactions.entrySet()
                .stream()
                .map(entry -> entry.getKey().commit(entry.getValue()))
                .toArray(CompletableFuture[]::new))
        .thenApply(v -> true);
    }

    @Override
    public CompletableFuture<Boolean> rollback(Transaction transaction) {
        Map<Database, Transaction> subTransactions = createSubTransactions(transaction);
        return CompletableFuture.allOf(subTransactions.entrySet()
                .stream()
                .map(entry -> entry.getKey().rollback(entry.getValue()))
                .toArray(CompletableFuture[]::new))
            .thenApply(v -> true);
    }

    @Override
    public CompletableFuture<Database> open() {
        return CompletableFuture.allOf(partitions
                    .stream()
                    .map(Database::open)
                    .toArray(CompletableFuture[]::new))
                .thenApply(v -> {
                    isOpen.set(true);
                    return this;
                });
    }

    @Override
    public CompletableFuture<Void> close() {
        checkState(isOpen.get(), DB_NOT_OPEN);
        return CompletableFuture.allOf(partitions
                .stream()
                .map(database -> database.close())
                .toArray(CompletableFuture[]::new));
    }

    @Override
    public boolean isClosed() {
        return !isOpen.get();
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public Cluster cluster() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Database addStartupTask(Task<CompletableFuture<Void>> task) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Database addShutdownTask(Task<CompletableFuture<Void>> task) {
        throw new UnsupportedOperationException();
    }

    @Override
    public ResourceState state() {
        throw new UnsupportedOperationException();
    }

    private Map<Database, Transaction> createSubTransactions(
            Transaction transaction) {
        Map<Database, List<DatabaseUpdate>> perPartitionUpdates = Maps.newHashMap();
        for (DatabaseUpdate update : transaction.updates()) {
            Database partition = partitioner.getPartition(update.mapName(), update.key());
            List<DatabaseUpdate> partitionUpdates =
                    perPartitionUpdates.computeIfAbsent(partition, k -> Lists.newLinkedList());
            partitionUpdates.add(update);
        }
        Map<Database, Transaction> subTransactions = Maps.newHashMap();
        perPartitionUpdates.forEach((k, v) -> subTransactions.put(k, new DefaultTransaction(transaction.id(), v)));
        return subTransactions;
    }

    protected void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    @Override
    public boolean hasChangeNotificationSupport() {
        return false;
    }

    @Override
    public void registerConsumer(Consumer<StateMachineUpdate> consumer) {
        partitions.forEach(p -> p.registerConsumer(consumer));
    }

    @Override
    public void unregisterConsumer(Consumer<StateMachineUpdate> consumer) {
        partitions.forEach(p -> p.unregisterConsumer(consumer));
    }
}
