"""The sample demonstrates real-time data receiving"""

import logging

from tabulate import tabulate
from win32com.client import Dispatch, constants

import CELEnvironment

# region Settings

# Logging settings: specify log level and log format here.
# Set log level to DEBUG to see more internal messages.
# See more information about logging lib usage: https://docs.python.org/3/howto/logging-cookbook.html
CELEnvironment.LOG_LEVEL = logging.INFO
# CELEnvironment.LOG_FORMAT = ...

# CELEnvironment.SinkInternal uses own LOG_LEVEL (which is inherited from the global one) and own LOG_FORMAT.
# You can redefine them as follows:
# CELEnvironment.SinkInternal.LOG_LEVEL = logging.DEBUG
# CELEnvironment.SinkInternal.LOG_FORMAT = ...

LOG = CELEnvironment.GetLogger()

SYMBOL = "SO3"
QUOTE_LEVEL = constants.qsQuotes | constants.qsBBA
PROPERTY_LEVEL = constants.psContractOpenInterestExtended | constants.psTotalVolumes

# endregion

QUOTE_HEADERS = ["Type", "Price", "Volume", "Time"]
PROPERTY_HEADERS = ["Name", "Value", "Time"]


def GetQuoteData(quote):
    return [quote.Name, quote.Price, quote.Volume, quote.ServerTimestamp]


def GetPropertyData(prop):
    return [prop.Name, prop.Value, prop.ServerTimestamp]


class RealTimeMarketDataReceiving(CELEnvironment.CELSinkBase):
    def Init(self, celEnvironment):
        self.celEnvironment = celEnvironment

    def Start(self):
        request = self.celEnvironment.cqgCEL.CreateInstrumentRequest()
        request.Symbol = SYMBOL
        request.QuoteLevel = QUOTE_LEVEL
        request.PropertyLevel = PROPERTY_LEVEL

        LOG.info("Request realtime market data for '%s'", request.Symbol)
        self.celEnvironment.cqgCEL.SubscribeNewInstrument(request)

        input()

    def OnDataError(self, cqgError, errorDescription):
        if cqgError is not None:
            error = Dispatch(cqgError)
            LOG.error("OnDataError: Code: %d Description: %s", error.Code, error.Description)

    def OnInstrumentResolved(self, symbol, cqgInstrument, cqgError):
        if cqgError is not None:
            error = Dispatch(cqgError)
            LOG.error("OnInstrumentResolved error: Error code: %d Description: %s", error.Code, error.Description)
            return

        instrument = Dispatch(cqgInstrument)
        quotes = [GetQuoteData(quote) for quote in instrument.Quotes]
        properties = [GetPropertyData(prop) for prop in instrument.Properties]
        LOG.info(
            "OnInstrumentResolved: Symbol: %s Instrument full name: %s\nQuotes:\n%s\nProperties:\n%s\n\n",
            symbol,
            instrument.FullName,
            tabulate(quotes, headers=QUOTE_HEADERS),
            tabulate(properties, headers=PROPERTY_HEADERS),
        )

    def OnInstrumentChanged(self, cqgInstrument, cqgQuotes, cqgInstrumentProperties):
        instrument = Dispatch(cqgInstrument)
        oldQuotes = Dispatch(cqgQuotes)
        oldProperties = Dispatch(cqgInstrumentProperties)

        if oldQuotes.Count > 0:
            newQuotes = [instrument.Quotes.Item(quote.Type) for quote in oldQuotes]
            oldData = [GetQuoteData(quote) for quote in oldQuotes]
            newData = [GetQuoteData(quote) for quote in newQuotes]

            LOG.info(
                "New quotes for '%s'.\nPrevious values:\n%s\n\nNew values:\n%s\n\n",
                instrument.FullName,
                tabulate(oldData, headers=QUOTE_HEADERS),
                tabulate(newData, headers=QUOTE_HEADERS),
            )

        if oldProperties.Count > 0:
            newProperties = [instrument.Properties(prop.Type) for prop in oldProperties]
            oldData = [GetPropertyData(prop) for prop in oldProperties]
            newData = [GetPropertyData(prop) for prop in newProperties]
            LOG.info(
                "New properties for '%s'.\nPrevious values:\n%s\n\nNew values:\n%s\n\n",
                instrument.FullName,
                tabulate(oldData, headers=PROPERTY_HEADERS),
                tabulate(newData, headers=PROPERTY_HEADERS),
            )


# If CQGCEL.APIConfiguration must be customized then do it in this function
def CustomAPIConfiguration(APIConfiguration):
    # http://partners.cqg.com/sites/default/files/docs/CQGAPI_4.0R/webframe.html#CQG~CQGAPIConfig~NewInstrumentMode.html
    APIConfiguration.NewInstrumentMode = True


if __name__ == "__main__":
    CELEnvironment.Start(RealTimeMarketDataReceiving, CustomAPIConfiguration)
