package database; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.mapdb.BTreeMap; import org.mapdb.Bind; import org.mapdb.DB; import org.mapdb.DBMaker; import org.mapdb.Fun; import org.mapdb.Fun.Tuple4; import qora.assets.Order; import utils.ObserverMessage; import database.DBSet; import database.serializer.OrderSerializer; public class OrderMap extends DBMap<BigInteger, Order> { private Map<Integer, Integer> observableData = new HashMap<Integer, Integer>(); @SuppressWarnings("rawtypes") private BTreeMap haveWantKeyMap; public OrderMap(DBSet databaseSet, DB database) { super(databaseSet, database); this.observableData.put(DBMap.NOTIFY_ADD, ObserverMessage.ADD_ORDER_TYPE); this.observableData.put(DBMap.NOTIFY_REMOVE, ObserverMessage.REMOVE_ORDER_TYPE); //this.observableData.put(DBMap.NOTIFY_LIST, ObserverMessage.LIST_ORDER_TYPE); } public OrderMap(OrderMap parent) { super(parent); } protected void createIndexes(DB database){} @Override protected Map<BigInteger, Order> getMap(DB database) { //OPEN MAP return this.openMap(database); } @Override protected Map<BigInteger, Order> getMemoryMap() { DB database = DBMaker.newMemoryDB().make(); //OPEN MAP return this.openMap(database); } @SuppressWarnings("unchecked") private Map<BigInteger, Order> openMap(DB database) { //OPEN MAP BTreeMap<BigInteger, Order> map = database.createTreeMap("orders") .valueSerializer(new OrderSerializer()) .makeOrGet(); //HAVE/WANT KEY this.haveWantKeyMap = database.createTreeMap("orders_key_have_want") .comparator(Fun.COMPARATOR) .makeOrGet(); //BIND HAVE/WANT KEY Bind.secondaryKey(map, this.haveWantKeyMap, new Fun.Function2<Tuple4<Long, Long, BigDecimal, BigInteger>, BigInteger, Order>() { @Override public Tuple4<Long, Long, BigDecimal, BigInteger> run(BigInteger key, Order value) { return new Tuple4<Long, Long, BigDecimal, BigInteger>(value.getHave(), value.getWant(), value.getPrice(), key); } }); //RETURN return map; } @Override protected Order getDefaultValue() { return null; } @Override protected Map<Integer, Integer> getObservableData() { return this.observableData; } public void add(Order order) { this.set(order.getId(), order); } @SuppressWarnings({ "unchecked", "rawtypes" }) private Collection<BigInteger> getKeys(long have, long want) { //FILTER ALL KEYS Collection<BigInteger> keys = ((BTreeMap<Tuple4, BigInteger>) this.haveWantKeyMap).subMap( Fun.t4(have, want, null, null), Fun.t4(have, want, Fun.HI(), Fun.HI())).values(); //IF THIS IS A FORK if(this.parent != null) { //GET ALL KEYS FOR FORK Collection<BigInteger> forkKeys = ((OrderMap) this.parent).getKeys(have, want); //COMBINE LISTS Set<BigInteger> combinedKeys = new TreeSet<BigInteger>(keys); combinedKeys.addAll(forkKeys); //DELETE DELETED for(BigInteger deleted: this.deleted) { combinedKeys.remove(deleted); } //CONVERT SET BACK TO COLLECTION keys = combinedKeys; } return keys; } public List<Order> getOrders(long have, long want) { //FILTER ALL KEYS Collection<BigInteger> keys = this.getKeys(have, want); //GET ALL ORDERS FOR KEYS List<Order> orders = new ArrayList<Order>(); for(BigInteger key: keys) { orders.add(this.get(key)); } //IF THIS IS A FORK if(this.parent != null) { //RESORT ORDERS Collections.sort(orders); } //RETURN return orders; } @SuppressWarnings({ "unchecked", "rawtypes" }) public SortableList<BigInteger, Order> getOrdersSortableList(long have, long want) { //FILTER ALL KEYS Collection<BigInteger> keys = ((BTreeMap<Tuple4, BigInteger>) this.haveWantKeyMap).subMap( Fun.t4(have, want, null, null), Fun.t4(have, want, Fun.HI(), Fun.HI())).values(); //RETURN return new SortableList<BigInteger, Order>(this, keys); } public void delete(Order order) { this.delete(order.getId()); } }