001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package net.tridentsdk.server.service;
018
019import com.google.common.collect.ForwardingCollection;
020import com.google.common.collect.Lists;
021import net.tridentsdk.Trident;
022import net.tridentsdk.service.Transaction;
023import net.tridentsdk.service.Transactions;
024import net.tridentsdk.util.TridentLogger;
025
026import java.util.Collection;
027import java.util.List;
028import java.util.concurrent.ConcurrentHashMap;
029import java.util.concurrent.ConcurrentMap;
030import java.util.concurrent.atomic.AtomicInteger;
031
032/**
033 * Performs API transactions
034 *
035 * @author The TridentSDK Team
036 */
037public class TransactionHandler extends ForwardingCollection<Transaction> implements Transactions {
038    private final ConcurrentMap<Object, TransactionAudit> transactions = new ConcurrentHashMap<>();
039    private final AtomicInteger transactionIds = new AtomicInteger(2);
040
041    /**
042     * Do not instantiate.
043     * <p>
044     * <p>To access this handler, use this code:
045     * <pre><code>
046     *     Transactions handler = Registered.transactions();
047     * </code></pre></p>
048     */
049    public TransactionHandler() {
050        if (!Trident.isTrident())
051            TridentLogger.get().error(new IllegalAccessException("This class should only be instantiated by Trident"));
052    }
053
054    @Override
055    public int newAcount() {
056        return transactionIds.incrementAndGet();
057    }
058
059    @Override
060    public int globalEconomy() {
061        return 1;
062    }
063
064    @Override
065    public int globalExchange() {
066        return 2;
067    }
068
069    @Override
070    public void deposit(int account, Transaction transaction) {
071        TransactionAudit audit = transactions.computeIfAbsent(transaction.receiver(), (k) -> new TransactionAudit());
072
073        audit.put(account, transaction);
074        transaction.doTransaction(Transaction.Type.DEPOSIT);
075    }
076
077    @Override
078    public boolean withdraw(int account, final Transaction transaction) {
079        TransactionAudit audit = transactions.get(transaction.sender());
080        if (audit == null)
081            return false;
082
083        Transaction withdrawl =
084                new Transaction(
085                        transaction.item(),
086                        transaction.sender(),
087                        transaction.receiver(),
088                        -Math.abs(transaction.amount())) {
089                    @Override
090                    public void doTransaction(Type type) {
091                        transaction.doTransaction(type);
092                    }
093                };
094
095        audit.put(account, withdrawl);
096        withdrawl.doTransaction(Transaction.Type.WITHDRAW);
097        return true;
098    }
099
100    @Override
101    public int amount(int account, Object person, Object type) {
102        TransactionAudit audit = transactions.get(person);
103        if (audit == null)
104            return Integer.MIN_VALUE;
105
106        List<Transaction> queue = audit.transactionsFor(account);
107        if (queue == null)
108            return Integer.MAX_VALUE;
109
110        int amount = 0;
111        for (Transaction transaction : queue) {
112            if (type.equals(transaction.item())) {
113                amount += transaction.amount();
114            }
115        }
116
117        return amount;
118    }
119
120    @Override
121    protected Collection<Transaction> delegate() {
122        List<Transaction> transactions = Lists.newArrayList();
123        this.transactions.values().forEach(transactionAudit -> transactions.addAll(transactionAudit.concat()));
124        return transactions;
125    }
126}