package database;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.TreeMap;
import ntp.NTP;
import org.mapdb.BTreeKeySerializer;
import org.mapdb.DB;
import com.google.common.primitives.UnsignedBytes;
import qora.transaction.Transaction;
import qora.transaction.TransactionFactory;
import utils.ObserverMessage;
import utils.TransactionsList;
public class TransactionDatabase extends Observable implements Observer {
private TransactionDatabase parent;
private DBSet databaseSet;
private Map<byte[], byte[]> transactionMap;
public TransactionDatabase(DBSet databaseSet, DB database)
{
this.databaseSet = databaseSet;
//OPEN MAP
this.transactionMap = database.createTreeMap("transactions")
.keySerializer(BTreeKeySerializer.BASIC)
.comparator(UnsignedBytes.lexicographicalComparator())
.makeOrGet();
}
public TransactionDatabase(TransactionDatabase parent)
{
this.parent = parent;
//OPEN MAP
this.transactionMap = new TreeMap<byte[], byte[]>(UnsignedBytes.lexicographicalComparator());
}
public List<Transaction> getTransactions()
{
try
{
//GET ALL TRANSACTIONS IN MAP
List<byte[]> keyList = this.getKeys();
if(this.parent != null)
{
keyList.addAll(this.parent.getKeys());
//TODO REMOVE DUPLICATES
}
//RETURN
return new TransactionsList(keyList);
}
catch(Exception e)
{
e.printStackTrace();
return new ArrayList<Transaction>();
}
}
private List<byte[]> getKeys()
{
//GET ALL KEYS
List<byte[]> keyList = new ArrayList<byte[]>();
for(byte[] key: this.transactionMap.keySet())
{
keyList.add(key);
}
return keyList;
}
public Transaction getTransaction(byte[] signature)
{
try
{
if(this.transactionMap.containsKey(signature))
{
return TransactionFactory.getInstance().parse(this.transactionMap.get(signature));
}
else
{
if(this.parent != null)
{
return this.parent.getTransaction(signature);
}
}
return null;
}
catch(Exception e)
{
//NO BLOCK FOUND
return null;
}
}
public void addTransaction(Transaction transaction)
{
try
{
this.transactionMap.put(transaction.getSignature(), transaction.toBytes());
//COMMIT
if(this.databaseSet != null)
{
this.databaseSet.commit();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void remove(Transaction transaction)
{
//REMOVE TRANSACTION FROM 0 CONFIRMS
this.transactionMap.remove(transaction.getSignature());
//COMMIT
if(this.databaseSet != null)
{
this.databaseSet.commit();
}
}
public boolean contains(Transaction transaction)
{
if(this.transactionMap.containsKey(transaction.getSignature()))
{
return true;
}
else
{
if(this.parent != null)
{
return this.parent.contains(transaction);
}
}
return false;
}
@Override
public void update(Observable o, Object arg)
{
ObserverMessage message = (ObserverMessage) arg;
//ON NEW BLOCK
if(message.getType() == ObserverMessage.ADD_BLOCK_TYPE)
{
//CLEAN UP
for(Transaction transaction: this.getTransactions())
{
//CHECK IF DEADLINE PASSED
if(transaction.getDeadline() < NTP.getTime())
{
this.remove(transaction);
//NOTIFY
this.setChanged();
this.notifyObservers(new ObserverMessage(ObserverMessage.REMOVE_TRANSACTION_TYPE, transaction));
}
}
}
}
}