
package uk.co.wingpath.modbus;

import java.io.*;

/**
* This class implements ModbusRequestHandler by forwarding requests
* to another ModbusRequestHandler, and it monitors the data transferred
* in those requests. It does this by also forwarding any write requests
* and replies to read requests (converted into write requests) to a second
* ModbusRequestHandler.
*/

public class ModbusMonitor
    implements ModbusRequestHandler
{
    private final ModbusRequestHandler client;
    private final ModbusRequestHandler slave;

    public ModbusMonitor (ModbusRequestHandler client,
        ModbusRequestHandler slave)
    {
        this.client = client;
        this.slave = slave;
    }

    private void copyReplyToSlave (ModbusRequest request, ModbusResponse reply,
            int function)
        throws ModbusException, InterruptedException, IOException
    {
        MessageBuilder body = new MessageBuilder ();
        body.addInt (request.getInt (0));     // address
        body.addInt (request.getInt (2));     // count
        int length = reply.getByte (0);
        body.addByte ((byte) length);
        body.addData (reply.getData (1, length));
        ModbusRequest message = new ModbusRequest (request.getSlaveId (),
            function, 0, body.getData ());
        slave.handleRequest (message);
    }

    public ModbusResponse handleRequest (ModbusRequest request)
        throws ModbusException, InterruptedException, IOException
    {
        // Send the request to the client and get its reply

        ModbusResponse reply = client.handleRequest (request);

        // Ensure that reply has correct transaction identifier
        // (client may not support transaction IDs, e.g. if RTU).
        reply = new ModbusResponse (reply.getSlaveId (),
            reply.getFunctionCode (),
            request.getTransId (),
            reply.getData ());

        // Try to copy any data to the slave

        try
        {
            switch (request.getFunctionCode ())
            {
            case Modbus.FUNC_WRITE_MULTIPLE_REGISTERS:
            case Modbus.FUNC_WRITE_SINGLE_REGISTER:
            case Modbus.FUNC_WRITE_MULTIPLE_COILS:
            case Modbus.FUNC_WRITE_SINGLE_COIL:
            case Modbus.FUNC_MASK_WRITE_REGISTER:
                slave.handleRequest (request);
                break;

            case Modbus.FUNC_READ_HOLDING_REGISTERS:
                copyReplyToSlave (request, reply,
                    Modbus.FUNC_WRITE_MULTIPLE_REGISTERS);
                break;

            case Modbus.FUNC_READ_COILS:
                copyReplyToSlave (request, reply,
                    Modbus.FUNC_WRITE_MULTIPLE_COILS);
                break;

            case Modbus.FUNC_READ_DISCRETE_INPUTS:
                copyReplyToSlave (request, reply,
                    Modbus.FUNC_WRITE_DISCRETE_INPUTS);
                break;

            case Modbus.FUNC_READ_INPUT_REGISTERS:
                copyReplyToSlave (request, reply,
                    Modbus.FUNC_WRITE_INPUT_REGISTERS);
                break;

            case Modbus.FUNC_READ_WRITE_MULTIPLE_REGISTERS:
                slave.handleRequest (request);
                copyReplyToSlave (request, reply,
                    Modbus.FUNC_WRITE_MULTIPLE_REGISTERS);
                break;
            }
        }
        catch (ModbusException e)
        {
        }

        return reply;
    }
}

