// Import section
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;

import com.inforeach.eltrader.ELT;
import com.inforeach.eltrader.ELTSystem;
import com.inforeach.eltrader.engine.ELTConnectionName;
import com.inforeach.eltrader.engine.ELTConnectionState;
import com.inforeach.eltrader.engine.ELTEngineDefs;
import com.inforeach.eltrader.engine.ELTEngineProxy;
import com.inforeach.eltrader.engine.ELTGuaranteedEngineMessageListener;
import com.inforeach.eltrader.engine.cmd.ELTCmdGroupHandler;
import com.inforeach.eltrader.engine.esevent.ELTAdminMessageEvent;
import com.inforeach.eltrader.engine.esevent.ELTAppMessageEvent;
import com.inforeach.eltrader.engine.esevent.ELTConnectionStateEvent;
import com.inforeach.eltrader.engine.util.ELTAbstractEngineProxyActivationHandler;
import com.inforeach.eltrader.message.ELTAppMessage;
import com.inforeach.eltrader.message.ELTMessage;
import com.inforeach.eltrader.service.ELTEngineComponent;
import com.inforeach.util.GlobalSystem;
import com.inforeach.util.ICmdHandler;
import com.inforeach.util.IEventListener;
import com.inforeach.util.UserTicket;
import com.inforeach.util.UtilityFunctions;
import com.inforeach.util.log.ILogFacility;
import com.inforeach.util.xml.XMLData;

// Main application class:
public class SampleClient
{
    public static void main(final String args[])
    {
        try
        {
            ELTEngineProxy.setEngineProxyActivationHandler(new
                ELTAbstractEngineProxyActivationHandler()
            {
                public void onPreEngineProxyActivation()
                {
                    try
                    {
                        String needGuaranteedDelivery;
                        if (args.length > 3)
                        {
                            needGuaranteedDelivery = args[3];
                        }
                        else
                        {
                            needGuaranteedDelivery = "0";
                        }

                        // get engine proxy handle:
                        ELTEngineProxy proxy = ELTSystem.getEngineProxy();

                        // setup listenerProperties XMLData object:
                        XMLData listenerProps = new XMLData();

                        // interested in all visible connections:
                        // alternatively could specify comma-separated list of connections
                        // like "connection1,connection1":
                        listenerProps.setAttributeValue(
                            ELTEngineDefs.CFG_CONNECTION_NAMES,
                            "*");

                        // interested in FIX application messages:
                        listenerProps.setAttributeValue(
                            ELTEngineDefs.CFG_SUBSCRIBE_FOR_APP_MSGS,
                            true);

                        // interested in FIX admin messages:
                        listenerProps.setAttributeValue(
                            ELTEngineDefs.CFG_SUBSCRIBE_FOR_ADMIN_MSGS,
                            true);

                        // interested in Connection State messages:
                        listenerProps.setAttributeValue(
                            ELTEngineDefs.CFG_SUBSCRIBE_FOR_CONN_INFO,
                            true);

                        // now subscribe MessageProcessor to engine proxy:
                        if (needGuaranteedDelivery.equals("1"))
                        {
                            // subscribe with support for guaranteed delivery
                            ELTSystem.getLogFacility().info().write(
                                "Registering guaranteed message listener.");

                            // instantiate guaranteed delivery component:
                            ELTGuaranteedEngineMessageListener
                                guaranteedMsgListener =
                                new ELTGuaranteedEngineMessageListener(
                                    new MessageProcessor());

                            // get array of all visible connections from the proxy.
                            // we cannot get them out of the listenerProps object
                            // because we used '*' to denote all visible connections:
                            ELTConnectionName[] connectionNames =
                                proxy.getConnectionNameList(GlobalSystem.
                                getUserTicket());

                            // for each of the connections set last consumed sent and
                            // received app message id:
                            for (int i = connectionNames.length - 1; i >= 0; i--)
                            {
                                // set last consumed message id of received app message
                                guaranteedMsgListener.
                                    setLastConsumedAppMessageFromCounterPartyId(
                                        connectionNames[i],
                                        ELTEngineDefs.
                                        INITIAL_APP_MESSAGE_FROM_COUNTER_PARTY_ID);

                                // set last consumed message id of sent app message
                                guaranteedMsgListener.
                                    setLastConsumedAppMessageToCounterPartyId(
                                        connectionNames[i],
                                        ELTEngineDefs.
                                        INITIAL_APP_MESSAGE_TO_COUNTER_PARTY_ID);
                            }

                            // here this call is made for demo purposes only since
                            // last consumed message ids are set to initial values
                            // and, thus, no message gaps exist right now:
                            guaranteedMsgListener.
                                retrievePotentiallyLostMessages();

                            // finally subscribe with guaranteedMsgListener as listener:
                            proxy.subscribe(GlobalSystem.getUserTicket(),
                                            guaranteedMsgListener,
                                            listenerProps);
                        }
                        else
                        {
                            // subscribe without overhead of guaranteed delivery:
                            proxy.subscribe(GlobalSystem.getUserTicket(),
                                            new MessageProcessor(),
                                            listenerProps);
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.printStackTrace();
                    }
                }
            });

            // get main parameters including bootstrap file:
            String bootstrap_file_name = args[0];
            String processType = args[1];
            String processName = args[2];

            // initialize Engine component
            ELTEngineComponent.initialize(bootstrap_file_name, processType,
                                          processName);

            // register command handler options:
            registerCommandHandlerOptions();

            GlobalSystem.getCmdInterpreter().start();
            System.out.println(GlobalSystem.getCmdInterpreter().getHelp());

            Thread.currentThread().join();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }

    private static
        void registerCommandHandlerOptions()
    {
        // register command hadler for loading and sending messages from file
        ELTCmdGroupHandler.getDefaultInstance().registerCmdHandler(
            "sendMessages",
            new ICmdHandler()
        {
            public int commandEntered(Writer writer, String command,
                                      String[] args)
            {
                if ( (args != null) && (args.length == 2))
                {
                    try
                    {
                        String connectionName = args[0];

                        ArrayList groups = loadMessagesFromFile(new File(args[1]));

                        ELTEngineProxy engineProxy = ELTSystem.getEngineProxy();

                        for (Iterator iter = groups.iterator(); iter.hasNext(); )
                        {
                            // get next message
                            ELTAppMessage request = (ELTAppMessage) iter.next();

                            // send message over specified connection
                            engineProxy.sendMessage(
                                UserTicket.getSystemTicket(),
                                new ELTConnectionName(connectionName),
                                request);
                        }
                    }
                    catch (Exception ex)
                    {
                        UtilityFunctions.writeln(writer,
                                                 "Failed to send message: ");
                        ex.printStackTrace(new PrintWriter(writer));
                    }
                }
                else
                {
                    UtilityFunctions.writeln(writer,
                                             "Usage: sendMessages <connectionName> <fileName>");
                }
                return 0;
            }
        },
            "Load and send orders from file.\nUsage: sendMessages <connectionName> <file name>",
            new String[]
            {
            "s"}
            );
    }

    private static final
        ArrayList loadMessagesFromFile(File file)
        throws IOException
    {
        ArrayList groups = new ArrayList();

        BufferedReader f = new BufferedReader(new FileReader(file));

        String messageString;
        while ( (messageString = f.readLine()) != null)
        {
            // this is where we use ELTMessage.valueOf() method
            // to create message object from FIX-formatted string
            ELTMessage m = ELTMessage.valueOf(messageString);

            m.setSendingTime(System.currentTimeMillis());

            groups.add(m);
        }

        return groups;
    }

    // Class implementing IEvenListener:
    private static
        class MessageProcessor
        implements IEventListener
    {
        public void onEvent(Object event)
        {
            ILogFacility log = ELTSystem.getLogFacility();
            if (null == event)
            {
                log.error().write("MessageProcessor received null event");
                return;
            }
            else if (event instanceof ELTAppMessageEvent)
            {
                ELTAppMessage m = ( (ELTAppMessageEvent) event).getMessage();
                if (ELTAppMessage.isOriginalOrder(m))
                {
                    log.info().write(">>> Processed order: " +
                                     m.getFieldValue(ELT.fieldClOrdID));
                    // Do something if necessary...
                }
                else if (ELTAppMessage.isOrderConfirmation(m))
                {
                    log.info().write(">>> Received confirmation for: " +
                                     m.getFieldValue(ELT.fieldClOrdID));
                    // Do something if necessary...
                }
                else if (ELTAppMessage.isOrderFillReport(m))
                {
                    log.info().write(">>> Received fill for: " +
                                     m.getFieldValue(ELT.fieldClOrdID));
                    // Do something if necessary...
                }
                else
                {
                    log.info().write(">>> Received app message: " + m);
                    // Do something if necessary...
                }
            }
            else if (event instanceof ELTAdminMessageEvent)
            {
                ELTMessage m = ( (ELTAdminMessageEvent) event).getMessage();
                log.info().write(">>> Processing admin message: " + m);
                // Do something if necessary...
            }
            else if (event instanceof ELTConnectionStateEvent)
            {
                ELTConnectionState state = ( (ELTConnectionStateEvent) event).
                    getConnectionState();
                log.info().write(">>> Processing connection state event: " +
                                 state);
                // Do something if necessary...
            }
        }
    }
}
