package network.thunder.core.etc;
import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.ChannelStatusObject;
import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.P2PDataObject;
import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.PubkeyChannelObject;
import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.PubkeyIPObject;
import network.thunder.core.communication.objects.subobjects.PaymentSecret;
import network.thunder.core.database.DBHandler;
import network.thunder.core.database.objects.Channel;
import network.thunder.core.database.objects.PaymentWrapper;
import network.thunder.core.lightning.RevocationHash;
import java.util.*;
/**
* Created by matsjerratsch on 04/12/2015.
*/
public class InMemoryDBHandler implements DBHandler {
public List<Channel> channelList = new ArrayList<>();
public List<PubkeyIPObject> pubkeyIPList = new ArrayList<>();
public List<PubkeyChannelObject> pubkeyChannelList = new ArrayList<>();
public List<ChannelStatusObject> channelStatusList = new ArrayList<>();
public Map<Integer, List<P2PDataObject>> fragmentToListMap = new HashMap<>();
public List<P2PDataObject> totalList = new ArrayList<>();
public List<PubkeyIPObject> pubkeyIPObjectOpenChannel = new ArrayList<>();
public List<RevocationHash> revocationHashListTheir = new ArrayList<>();
public List<RevocationHash> revocationHashListOurs = new ArrayList<>();
List<PaymentWrapper> payments = new ArrayList<>();
List<PaymentSecret> secrets = new ArrayList<>();
public InMemoryDBHandler () {
for (int i = 0; i < 1001; i++) {
fragmentToListMap.put(i, new ArrayList<>());
}
}
@Override
public void insertIPObjects (List<P2PDataObject> ipList) {
syncDatalist(ipList);
}
@Override
public List<PubkeyIPObject> getIPObjects () {
return new ArrayList<>(pubkeyIPList);
}
@Override
public P2PDataObject getP2PDataObjectByHash (byte[] hash) {
for (P2PDataObject object : totalList) {
if (Arrays.equals(object.getHash(), hash)) {
return object;
}
}
return null;
}
@Override
public PubkeyIPObject getIPObject (byte[] nodeKey) {
for (PubkeyIPObject p : pubkeyIPList) {
if (Arrays.equals(p.pubkey, nodeKey)) {
return p;
}
}
return null;
}
@Override
public void syncDatalist (List<P2PDataObject> dataList) {
for (P2PDataObject obj : dataList) {
fragmentToListMap.get(obj.getFragmentIndex()).add(obj);
if (obj instanceof PubkeyIPObject) {
if (!pubkeyIPList.contains(obj)) {
pubkeyIPList.add((PubkeyIPObject) obj);
}
} else if (obj instanceof PubkeyChannelObject) {
if (!pubkeyChannelList.contains(obj)) {
pubkeyChannelList.add((PubkeyChannelObject) obj);
}
} else if (obj instanceof ChannelStatusObject) {
ChannelStatusObject temp = (ChannelStatusObject) obj;
boolean found = false;
for (ChannelStatusObject object : channelStatusList) {
if (Arrays.equals(object.pubkeyA, temp.pubkeyA) && Arrays.equals(object.pubkeyB, temp.pubkeyB)) {
found = true;
break;
}
if (Arrays.equals(object.pubkeyB, temp.pubkeyA) && Arrays.equals(object.pubkeyA, temp.pubkeyB)) {
found = true;
break;
}
}
if (found) {
continue;
}
if (!channelStatusList.contains(obj)) {
channelStatusList.add((ChannelStatusObject) obj);
}
}
List<P2PDataObject> list = getSyncDataByFragmentIndex(obj.getFragmentIndex());
if (!list.contains(obj)) {
list.add(obj);
}
if (!totalList.contains(obj)) {
totalList.add(obj);
}
}
}
@Override
public void insertRevocationHash (RevocationHash hash) {
revocationHashListTheir.add(hash);
}
@Override
public RevocationHash createRevocationHash (Channel channel) {
RevocationHash hash = new RevocationHash(1, 1, Tools.getRandomByte(32));
revocationHashListOurs.add(hash);
return hash;
}
@Override
public List<RevocationHash> getOldRevocationHashes (Channel channel) {
List<RevocationHash> hashList = new ArrayList<>(revocationHashListOurs);
revocationHashListOurs.clear();
return hashList;
}
@Override
public boolean checkOldRevocationHashes (List<RevocationHash> revocationHashList) {
//TODO
return true;
}
@Override
public Channel getChannel (byte[] nodeKey) {
for (Channel channel : channelList) {
if (Arrays.equals(channel.nodeId, nodeKey)) {
return channel;
}
}
return null;
}
@Override
public void saveChannel (Channel channel) {
this.channelList.add(channel);
}
@Override
public void updateChannel (Channel channel) {
Iterator<Channel> iterator = channelList.iterator();
while (iterator.hasNext()) {
Channel c = iterator.next();
if (Arrays.equals(c.nodeId, channel.nodeId)) {
iterator.remove();
channelList.add(channel);
return;
}
}
throw new RuntimeException("Not able to find channel in list, not updated..");
}
@Override
public List<Channel> getOpenChannel () {
return channelList;
}
@Override
public List<P2PDataObject> getSyncDataByFragmentIndex (int fragmentIndex) {
return fragmentToListMap.get(fragmentIndex);
}
@Override
public List<P2PDataObject> getSyncDataIPObjects () {
return null;
}
@Override
public List<PubkeyIPObject> getIPObjectsWithActiveChannel () {
return new ArrayList<>();
}
@Override
public List<ChannelStatusObject> getTopology () {
List<ChannelStatusObject> list = new ArrayList<>();
for (P2PDataObject object : totalList) {
if (object instanceof ChannelStatusObject) {
list.add((ChannelStatusObject) object);
}
}
return list;
}
@Override
public List<PaymentWrapper> getAllPayments () {
return new ArrayList<>();
}
@Override
public List<PaymentWrapper> getOpenPayments () {
return new ArrayList<>();
}
@Override
public List<PaymentWrapper> getRefundedPayments () {
return new ArrayList<>();
}
@Override
public List<PaymentWrapper> getRedeemedPayments () {
return new ArrayList<>();
}
@Override
public void addPayment (PaymentWrapper paymentWrapper) {
if (payments.contains(paymentWrapper)) {
return;
// throw new RuntimeException("Double payment added?");
}
payments.add(paymentWrapper);
}
@Override
public void updatePayment (PaymentWrapper paymentWrapper) {
for (PaymentWrapper p : payments) {
if (p.equals(paymentWrapper)) {
p.paymentData = paymentWrapper.paymentData;
p.receiver = paymentWrapper.receiver;
p.sender = paymentWrapper.sender;
p.statusReceiver = paymentWrapper.statusReceiver;
p.statusSender = paymentWrapper.statusSender;
}
}
}
@Override
public void updatePaymentSender (PaymentWrapper paymentWrapper) {
for (PaymentWrapper p : payments) {
if (p.equals(paymentWrapper)) {
p.paymentData = paymentWrapper.paymentData;
p.statusSender = paymentWrapper.statusSender;
}
}
}
@Override
public void updatePaymentReceiver (PaymentWrapper paymentWrapper) {
for (PaymentWrapper p : payments) {
if (p.equals(paymentWrapper)) {
p.paymentData = paymentWrapper.paymentData;
p.statusReceiver = paymentWrapper.statusReceiver;
}
}
}
@Override
public void updatePaymentAddReceiverAddress (PaymentSecret secret, byte[] receiver) {
for (PaymentWrapper p : payments) {
if (p.paymentData.secret.equals(secret)) {
p.receiver = receiver;
}
}
}
@Override
public PaymentWrapper getPayment (PaymentSecret paymentSecret) {
System.out.println(payments.size());
for (PaymentWrapper payment : payments) {
if (payment.paymentData.secret.equals(paymentSecret)) {
return payment;
}
}
return null;
}
@Override
public void addPaymentSecret (PaymentSecret secret) {
if (secrets.contains(secret)) {
PaymentSecret oldSecret = secrets.get(secrets.indexOf(secret));
oldSecret.secret = secret.secret;
} else {
secrets.add(secret);
}
}
@Override
public PaymentSecret getPaymentSecret (PaymentSecret secret) {
if (!secrets.contains(secret)) {
return null;
}
return secrets.get(secrets.indexOf(secret));
}
@Override
public byte[] getSenderOfPayment (PaymentSecret paymentSecret) {
for (PaymentWrapper payment : payments) {
if (payment.paymentData.secret.equals(paymentSecret)) {
return payment.sender;
}
}
return null;
}
@Override
public byte[] getReceiverOfPayment (PaymentSecret paymentSecret) {
for (PaymentWrapper payment : payments) {
if (payment.paymentData.secret.equals(paymentSecret)) {
return payment.receiver;
}
}
return null;
}
private void pruneLists () {
List<PubkeyIPObject> oldList = new ArrayList<>();
for (PubkeyIPObject oldIP : pubkeyIPList) {
for (PubkeyIPObject newIP : pubkeyIPList) {
if (!oldIP.equals(newIP)) {
if (Arrays.equals(oldIP.pubkey, newIP.pubkey) && (oldIP.timestamp < newIP.timestamp)) {
oldList.add(oldIP);
}
}
}
}
pubkeyIPList.removeAll(oldList);
}
}