/*
 * Copyright (c) 2013 - 2015 xxyy (Philipp Nowak; devnull@nowak-at.net). All rights reserved.
 *
 * Any usage, including, but not limited to, compiling, running, redistributing, printing,
 *  copying and reverse-engineering is strictly prohibited without explicit written permission
 *  from the original author and may result in legal steps being taken.
 *
 * See the included LICENSE file (core/src/main/resources) or email xxyy98+xyclicense@gmail.com for details.
 */

package li.l1t.lanatus.sql.position;

import li.l1t.common.collections.cache.OptionalGuavaCache;
import li.l1t.common.collections.cache.OptionalCache;
import li.l1t.lanatus.api.position.Position;
import li.l1t.lanatus.api.position.PositionRepository;
import li.l1t.lanatus.api.purchase.Purchase;
import li.l1t.lanatus.sql.AbstractSqlLanatusRepository;
import li.l1t.lanatus.sql.SqlLanatusClient;

import java.util.Collection;
import java.util.Optional;
import java.util.UUID;

/**
 * Simple implementation of a position repository based on a JDBC SQL data source. Caches positions
 * by purchase id and product ids by player. Caches are automatically invalidated some time after
 * they have been updated from the data source.
 *
 * @author <a href="https://l1t.li/">Literallie</a>
 * @since 2016-10-10
 */
public class SqlPositionRepository extends AbstractSqlLanatusRepository implements PositionRepository {
    public static final String TABLE_NAME = "mt_main.lanatus_position";
    private final OptionalCache<UUID, Position> cache = new OptionalGuavaCache<>();
    private final JdbcPositionFetcher fetcher = new JdbcPositionFetcher(
            new JdbcPositionCreator(client().products()), client().sql()
    );
    private final JdbcPositionWriter writer = new JdbcPositionWriter(client().sql());

    public SqlPositionRepository(SqlLanatusClient client) {
        super(client);
    }

    @Override
    public Optional<Position> findByPurchase(UUID purchaseId) {
        return cache.getOrCompute(purchaseId, fetcher::fetchByPurchase);
    }

    @Override
    public Collection<Position> findAllByPlayer(UUID playerId) {
        return fetcher.fetchAllByPlayer(playerId);
    }

    @Override
    public boolean playerHasProduct(UUID playerId, UUID productId) {
        return false;
    }

    /**
     * Creates a <b>new</b> position from a purchase and writes it to the database.
     *
     * @param purchase the purchase to create a position from
     * @return the created position
     */
    public Position createFromPurchase(Purchase purchase) {
        SqlPosition position = new SqlPosition(purchase);
        writer.write(position);
        return position;
    }

    @Override
    public void clearCache() {
        cache.clear();
    }
}

@@ -505,32 +505,182 @@
 sition;%0A%0Aimport 
+com.google.common.base.VerifyException;%0Aimport li.l1t.common.collections.cache.GuavaMapCache;%0Aimport li.l1t.common.collections.cache.MapCache;%0Aimport 
 li.l1t.common.co
@@ -699,29 +699,24 @@
 che.Optional
-Guava
 Cache;%0Aimpor
@@ -749,32 +749,37 @@
 s.cache.Optional
+Guava
 Cache;%0Aimport li
@@ -861,32 +861,75 @@
 tionRepository;%0A
+import li.l1t.lanatus.api.product.Product;%0A
 import li.l1t.la
@@ -1131,20 +1131,78 @@
 va.util.
-UUID
+Set;%0Aimport java.util.UUID;%0Aimport java.util.stream.Collectors
 ;%0A%0A/**%0A 
@@ -2024,16 +2024,106 @@
 .sql());
+%0A    private final MapCache%3CUUID, Set%3CUUID%3E%3E playerPositionsCache = new GuavaMapCache%3C%3E();
 %0A%0A    pu
@@ -2451,22 +2451,48 @@
         
-return
+Collection%3CPosition%3E positions =
  fetcher
@@ -2528,114 +2528,657 @@
     
-%7D%0A%0A    @Override%0A    public boolean playerHasProduct(UUID playerId, UUID productId) %7B%0A        return false
+    Set%3CUUID%3E positionIds = positions.stream()%0A                .map(Position::getProduct)%0A                .map(Product::getUniqueId)%0A                .collect(Collectors.toSet());%0A        playerPositionsCache.cache(playerId, positionIds);%0A        return positions;%0A    %7D%0A%0A    @Override%0A    public boolean playerHasProduct(UUID playerId, UUID productId) %7B%0A        if (!playerPositionsCache.containsKey(playerId)) %7B%0A            findAllByPlayer(playerId); //adds to cache%0A        %7D%0A        Set%3CUUID%3E playerProducts = playerPositionsCache.get(playerId)%0A                .orElseThrow(VerifyException::new);%0A        return playerProducts.contains(productId)
 ;%0A  

Implement playerHasProduct() method on SqlPositionRepository