#include <math.h>
#include <time.h>
#include <string>
#include <vector>
#include <map>
#include "responselistener.h"
#include "stdafx.h"
#include <sstream>
#include <iomanip>

ResponseListener::ResponseListener(IO2GSession *session)
{
    mSession = session;
    mSession->addRef();
    mSuccess = false;
    mRefCount = 1;
    mResponseEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
    mUpdateEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
}

ResponseListener::~ResponseListener()
{
    mSession->release();
    uni::CloseHandle(mResponseEvent);
    uni::CloseHandle(mUpdateEvent);
}

/** Increase reference counter. */
long ResponseListener::addRef()
{
    return InterlockedIncrement(&mRefCount);
}

/** Decrease reference counter. */
long ResponseListener::release()
{
    long rc = InterlockedDecrement(&mRefCount);
    if (rc == 0)
        delete this;
    return rc;
}

/** Set request. */
void ResponseListener::setRequest(const char *requestId)
{
    mRequestID = requestId;
    mOrderID = "";
    uni::ResetEvent(mResponseEvent);
    uni::ResetEvent(mUpdateEvent);
    mSuccess = false;
}

/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse  *response)
{
    if (response != 0)
    {
        if (response->getType() == CreateOrderResponse && mRequestID == requestId)
        {
            std::cout << "Request complete. ID: " << requestId << std::endl;
            IO2GResponseReaderFactory *readerFactory = mSession->getResponseReaderFactory();
            IO2GOrderResponseReader *responseReader = readerFactory->createOrderResponseReader(response);
            readerFactory->release();

            mOrderID = responseReader->getOrderID();
            mSuccess = responseReader->isSuccessful();

            responseReader->release();
            uni::SetEvent(mResponseEvent);
        }
        else if (response->getType() == GetLastOrderUpdate && mRequestID == requestId)
        {
            std::cout << "Request complete. ID: " << requestId << std::endl;

            IO2GResponseReaderFactory *readerFactory = mSession->getResponseReaderFactory();
            IO2GLastOrderUpdateResponseReader *lastOrderUpdateResponseReader = readerFactory->createLastOrderUpdateResponseReader(response);
            readerFactory->release();

            printLastOrderUpdate(lastOrderUpdateResponseReader);

            mSuccess = true;
            uni::SetEvent(mResponseEvent);
        }
    }
}

/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
    std::cout << "Request failed. ID: " << requestId << " : " << error << std::endl;
    if (requestId != 0 && mRequestID.length() > 0 && strcmp(requestId, mRequestID.c_str()) == 0)
    {
        mSuccess = false;
        uni::SetEvent(mResponseEvent);
    }
}

/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
    if (data)
    {
        IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
        IO2GTablesUpdatesReader *reader = factory->createTablesUpdatesReader(data);
        if (reader)
        {
            for (int i = 0; i < reader->size(); ++i)
            {
                if (reader->getUpdateType(i) == Insert)
                {
                    IO2GTradeRow *tradeRow = reader->getTradeRow(i);
                    if (tradeRow)
                    {
                        if (mOrderID == tradeRow->getOpenOrderID())
                        {
                            std::cout << "Trades table updated: Added trade. ID: " << tradeRow->getTradeID() << std::endl;
                            uni::SetEvent(mUpdateEvent);
                            break;
                        }
                    }
                }
            }
            reader->release();
        }
        factory->release();
    }
}

void ResponseListener::printLastOrderUpdate(IO2GLastOrderUpdateResponseReader *lastOrderUpdateResponseReader)
{
    O2GTableUpdateType updateType = lastOrderUpdateResponseReader->getUpdateType();
    std::string updateTypeString;
    switch(updateType)
    {
    case Delete:
        updateTypeString = "Delete";
        break;
    case Insert:
        updateTypeString = "Insert";
        break;
    case Update:
        updateTypeString = "Update";
        break;
    default:
        updateTypeString = "Undefined";
    }
    O2G2Ptr<IO2GOrderRow> orderRow = lastOrderUpdateResponseReader->getOrder();
    
    std::cout << "UpdateType: " << updateTypeString
              << "; Order ID: " << orderRow->getOrderID()
              << "; Status: "  << orderRow->getStatus() << std::endl;
}
