package com.paritytrading.parity.reporter;

import static org.jvirtanen.util.Applications.*;

import com.paritytrading.foundation.ASCII;
import com.paritytrading.parity.net.pmr.PMR;
import com.paritytrading.parity.net.pmr.PMRListener;
import com.paritytrading.parity.util.Timestamps;
import java.util.HashMap;
import java.util.Map;

class TradeProcessor implements PMRListener {

    private Map<Long, Order> orders;

    private Trade trade;

    private TradeListener listener;

    public TradeProcessor(TradeListener listener) {
        this.orders = new HashMap<>();

        this.trade = new Trade();

        this.listener = listener;
    }

    @Override
    public void version(PMR.Version message) {
        if (message.version != PMR.VERSION)
            error("Unsupported protocol version");
    }

    @Override
    public void orderEntered(PMR.OrderEntered message) {
        orders.put(message.orderNumber, new Order(message));
    }

    @Override
    public void orderAdded(PMR.OrderAdded message) {
    }

    @Override
    public void orderCanceled(PMR.OrderCanceled message) {
        Order order = orders.get(message.orderNumber);

        order.remainingQuantity -= message.canceledQuantity;

        if (order.remainingQuantity == 0)
            orders.remove(message.orderNumber);
    }

    @Override
    public void trade(PMR.Trade message) {
        Order resting  = orders.get(message.restingOrderNumber);
        Order incoming = orders.get(message.incomingOrderNumber);

        Order buy  = resting.side == PMR.BUY  ? resting : incoming;
        Order sell = resting.side == PMR.SELL ? resting : incoming;

        long buyOrderNumber = resting.side == PMR.BUY ?
                message.restingOrderNumber : message.incomingOrderNumber;

        long sellOrderNumber = resting.side == PMR.SELL ?
                message.restingOrderNumber : message.incomingOrderNumber;

        trade.timestamp       = Timestamps.format(message.timestamp / 1_000_000);
        trade.matchNumber     = message.matchNumber;
        trade.instrument      = ASCII.unpackLong(resting.instrument).trim();
        trade.quantity        = message.quantity;
        trade.price           = resting.price;
        trade.buyer           = ASCII.unpackLong(buy.username).trim();
        trade.buyOrderNumber  = buyOrderNumber;
        trade.seller          = ASCII.unpackLong(sell.username).trim();
        trade.sellOrderNumber = sellOrderNumber;

        listener.trade(trade);

        resting.remainingQuantity  -= message.quantity;
        incoming.remainingQuantity -= message.quantity;

        if (resting.remainingQuantity == 0)
            orders.remove(message.restingOrderNumber);

        if (incoming.remainingQuantity == 0)
            orders.remove(message.incomingOrderNumber);
    }

    private static class Order {
        public long username;
        public byte side;
        public long instrument;
        public long price;
        public long remainingQuantity;

        public Order(PMR.OrderEntered message) {
            this.username          = message.username;
            this.side              = message.side;
            this.instrument        = message.instrument;
            this.price             = message.price;
            this.remainingQuantity = message.quantity;
        }
    }

}

@@ -478,23 +478,16 @@
 r;%0A%0A    
-public 
 TradePro
@@ -2829,31 +2829,24 @@
 r %7B%0A        
-public 
 long usernam
@@ -2856,23 +2856,16 @@
         
-public 
 byte sid
@@ -2871,31 +2871,24 @@
 de;%0A        
-public 
 long instrum
@@ -2896,31 +2896,24 @@
 nt;%0A        
-public 
 long price;%0A
@@ -2920,23 +2920,16 @@
         
-public 
 long rem
@@ -2953,23 +2953,16 @@
         
-public 
 Order(PM

Clean up 'TradeProcessor'