import Six.Sixp.Client.*;
import Six.Sixp.Client.Error;

/**
 * This class implements the ISessionEventListener
 * All of these Callbacks are called from an event dispatcher with only one thread.
 * Because of this try to spend as little time as possible in the callbacks.
 * Create your own dispatcher to execute time consuming operations.
 *
 */

public class SessionEventListener implements ISessionEventListener
{
    private boolean _asynchronous;
    private RequestHandler _requestHandler;
    private ReconnectStrategy _reconnectStrategy;
    private ILoginStrategy _loginStrategy;

    public SessionEventListener(boolean asynchronous,RequestHandler requestHandler,ReconnectStrategy rs,ILoginStrategy loginStrategy)
    {
        //The asynchronous boolean in this demo is just to indicate if we are using the async methods for connect,login or not.
        //You should not use this boolean asynchronous approach as a design pattern, it is just a way to demonstrate
        //both asynchronous and synchronous methods in the same code.
        //You should decide if you will use synchronous or asynchronous approach at design time.

        _asynchronous=asynchronous;
        _requestHandler=requestHandler;
        _reconnectStrategy=rs;
        _loginStrategy=loginStrategy;
    }

    public void OnError(ISession iSession, SixpServerSettings sixpServerSettings, Six.Sixp.Client.Error error, String s)
    {
        //This callback will be called when something goes wrong during connect or login.
        //It will also get called if there is a problem with an established connection.
        //You should not take any special action here. Just log the error.
        //OnDisconnect will be fired after this one.

        System.out.println(Demo.GetDateTimeString() + " (" + error + ") " + s);

    }

    public void OnConnecting(ISession iSession, SixpServerSettings sixpServerSettings, boolean reconnecting)
    {
        //This callback will called when the API begins to connect to the SIXP.
        //Here is a good place to initialize you application state because if you have set up the
        //API to automatically reconnect this callback will get called every time the API tries to reconnect.

        System.out.println(Demo.GetDateTimeString() + " SessionEventListener.OnConnecting reconnecting=" + reconnecting);
    }

    public void OnConnected(ISession session, SixpServerSettings sixpServerSettings, boolean reconnecting)
    {
        //This callback will be called when the API has managed to connect to the SIXP server.
        //If you called the synchronous connect function you don't do anything here.

        //If you called the asynchronous connect (ConnectAsync) you may call the LoginAsync here,
        //but only if reconnecting is false. If reconnecting is true then don't do anything, the API
        //will log you in automatically.

        //In this demo we will use the member _asynchronous to determine if we should use asynchronous
        //methods or not. Again don use this as a design pattern, you should decide if you will
        //use synchronous or asynchronous approach at design time.

        _requestHandler.PrepareRequestItemPopList();
        System.out.println(Demo.GetDateTimeString() + " SessionEventListener.OnConnected reconnecting=" + reconnecting + " Async=" + _asynchronous);
        if (_asynchronous)
        {
            //We are using async.
            if (!reconnecting)
            {
                //First conection attempt, do the async. login
                try
                {
                    System.out.println(Demo.GetDateTimeString() + " SessionEventListener.OnConnected reconnecting=" + reconnecting + " Async=" + _asynchronous + " Calling LoginAsync");
                    session.LoginAsync(_loginStrategy);
                }
                catch (Exception e)
                {
                    System.out.println("SessionEventListener.OnConnected: " + e.getMessage());
                }
            }

        }
        //Otherwise don't do anything here, let the code after the sync. call to Connect execute the Login
    }

    public void OnDisconnected(ISession iSession, boolean unexpected)
    {
        //This callback will be called when the session is disconnected.
        //If you have a reconnect strategy != ReconnectStrategy.ReconnectResubscribe (which means
        //that you don't want the API to resubscribe the request) all request will be destroyed.
        //In that case you have to create new Request when the api is connected again otherwise the
        //API will resubscribe the request automatically.

        //If you supplied a non zero value in reconnectintervall when creating the session you don't
        //initiate a new connect here, the API will reconnect.
        // If you supplied zero in reconnectintervall you have to setup the connection again manually.
        // Don't call synchronous Connect from this callback, dispatch it.

        System.out.println(Demo.GetDateTimeString() + " SessionEventListener.OnDisconnected unexpected=" +  unexpected);

    }

    public void OnLoggedIn(ISession session, boolean reconnected)
    {
        //This callback will be called when the SIXP server have acknowledged
        //Since there is no synchronous way to execute an IRequest you may create and
        //execute them here. If you have a maximum of 30 requests that you want to subscribe you
        //may execute them all at once here. If you have more than 30 you should serialize them.
        //A good place to execute the next one is in the IRequestEventListener.OnTableFilled or
        //IRequestEventListener.OnText. these methods get called when a table request is completed or
        //when a text request is completed.

        //If you supplied a reconnect strategy == ReconnectStrategy.ReconnectResubscribe (which means
        //that you want the API to resubscribe the request, you may only create and execute request if
        //reconnected is false. The API will do this automatically when reconnected.
        //If you have a reconnect strategy that won't resubscribe, you may create and execute the requests
        //regardless of reconnected.

        System.out.println(Demo.GetDateTimeString() + " SessionEventListener.OnLoggedIn reconnected=" + reconnected + " Async=" + _asynchronous );

        //This demo will act upon the supplied reconnect strategy and act accordingly.
        if (_reconnectStrategy==ReconnectStrategy.ReconnectResubscribe)
        {
            if (!reconnected)
            {
                //First time we get connected.
                //Check this demo's _asynchronous flag to see which connection/login approach we are testing.
                //Don't implement this. Decide at design time if your going for sync. or async.
                if (_asynchronous)
                {
                    if (_requestHandler.IsOkToExecuteAllAtOnce())
                    {
                        System.out.println(Demo.GetDateTimeString() + " SessionEventListener.OnLoggedIn reconnected=" + reconnected + " Async=" + _asynchronous + " Creating all requests");
                        //Execute all at once since num<30. See IsOkToExecuteAllAtOnce method for changing this value
                        RequestItem ri;
                        do {
                            ri=_requestHandler.PopRequestItem();
                            if (ri!=null)
                            {
                                try
                                {
                                    IRequest r=session.CreateRequest(ri.getPrl(),ri.getFormat(),ri.getSubscribe(),ri.getEventListener());
                                    _requestHandler.SetRequestOnRequestItem(ri,r);
                                    r.ExecuteAsync();
                                }
                                catch (Exception e)
                                {
                                    System.out.println("SessionEventListener.OnLoggedIn: " + e.getMessage());
                                }
                            }
                        } while (ri!=null);
                    }
                    else
                    {
                        //execute one by one.
                        RequestItem ri=_requestHandler.PopRequestItem();
                        if (ri!=null)
                        {
                            try
                            {
                                IRequest r=session.CreateRequest(ri.getPrl(),ri.getFormat(),ri.getSubscribe(),ri.getEventListener());
                                _requestHandler.SetRequestOnRequestItem(ri,r);
                                r.ExecuteAsync();
                            }
                            catch (Exception e)
                            {
                                System.out.println("SessionEventListener.OnLoggedIn: " + e.getMessage());
                            }
                        }
                    }
                }
                //Otherwise don't do anything here, let the code after the sync. call to Login execute the requests .
            }
            else
            {
                //Api has reconnected and logged in. Since the reconnect strategy is set to do the resubscribing, we
                // don't do anything
            }
        }
        else
        {
            //If this demo _asynchronous flag is set to false we will let the code after the sync. call to login
            //do the request if it ist the first time we gets connected.
            //If it is a reconnect we must create and execute the request ourselves.
            //Don't implement this. Decide at design time if your going for sync. or async.
            if (!_asynchronous && !reconnected)
            {
                return;
            }

            //We are reconnnected.Here we are responsible to do the resubscribing regardless of reconnected flag since the reconnect strategy
            //is set not to resubscribe.
            if (_requestHandler.IsOkToExecuteAllAtOnce())
            {
                //Execute all at once since num<30. See IsOkToExecuteAllAtOnce method for changing this value
                RequestItem ri;
                do {
                    ri=_requestHandler.PopRequestItem();
                    if (ri!=null)
                    {
                        try
                        {
                            IRequest r=session.CreateRequest(ri.getPrl(),ri.getFormat(),ri.getSubscribe(),ri.getEventListener());
                            _requestHandler.SetRequestOnRequestItem(ri,r);
                            r.ExecuteAsync();
                        }
                        catch (Exception e)
                        {
                            System.out.println("SessionEventListener.OnLoggedIn: " + e.getMessage());
                        }
                    }
                } while (ri!=null);
            }
            else
            {
                //Execute one by one
                RequestItem ri=_requestHandler.PopRequestItem();
                if (ri!=null)
                {
                    try
                    {
                        IRequest r=session.CreateRequest(ri.getPrl(),ri.getFormat(),ri.getSubscribe(),ri.getEventListener());
                        _requestHandler.SetRequestOnRequestItem(ri,r);
                        r.ExecuteAsync();
                    }
                    catch (Exception e)
                    {
                        System.out.println("SessionEventListener.OnLoggedIn: " + e.getMessage());
                    }
                }
            }

        }



    }

    public void OnLoggedOut(ISession session, SixpServerSettings server, Error errorCode, String errorMessage)
    {
        //This Callback's name is a bit misleading. You might think that this one is always fired when the
        //connection to the server is dropped, but that's not the case. If you disposes the session it will not
        //be called. If the connection drops because of some network problem it will not be called.
        //It will only be called when the server forces the session to disconnect. The reason for this can be that
        //someone has logged in elsewhere with the same credentials.
        //Just log the error. Don't do anything more here.
        //OnDisconected will always be called when the connection to the server drops.

    }

    public void OnTimingInfo(ISession session, long pingTurnaroundTime, long estimatedDelayTime,long queueSize)
    {
        //Some statistics
    }
}
