#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from time import sleep, strftime
import time, datetime
import ConfigParser
from optparse import OptionParser
import logging
import thread
import threading
import traceback
import json
from threading import Lock
from ib.ext.Contract import Contract
from ib.ext.EWrapper import EWrapper
from ib.ext.EClientSocket import EClientSocket
from ib.ext.ExecutionFilter import ExecutionFilter
from ib.ext.Execution import Execution
from ib.ext.OrderState import OrderState
from ib.ext.Order import Order

from kafka import KafkaProducer
from kafka import KafkaConsumer
from kafka.errors import KafkaError


from misc2.helpers import ContractHelper, OrderHelper, ExecutionFilterHelper
from comms.ib_heartbeat import IbHeartBeat

from comms.test.base_messaging import Prosumer, BaseMessageListener
from misc2.observer import Subscriber, Publisher
from tws_protocol_helper import TWS_Protocol 

import redis
         

        
        
class TWS_event_handler(EWrapper):

    TICKER_GAP = 1000
    
    
    def __init__(self, tws_gateway):
        
        # reference to the parent TWS_gateway
        self.producer = tws_gateway
 
 

 
    def broadcast_event(self, message, mapping): #, source='IB'):

        try:
            dict = self.tick_process_message(message, mapping) #, source)     
            if message == 'gw_subscriptions' or message == 'gw_subscription_changed':   
                logging.info('TWS_event_handler: broadcast event: %s [%s]' % (dict['typeName'], dict))
            self.producer.send(message, self.producer.message_dumps(dict))    
        except:
            logging.error('broadcast_event: exception while encoding IB event to client:  [%s]' % message)
            logging.error(traceback.format_exc())
            
            
            

    
    def tick_process_message(self, message_name, items):  #, source):
        
        
        t = items.copy()
        # if the tickerId is in the snapshot range
        # deduct the gap to derive the original tickerId
        # --- check logic in subscription manager
        if (t['tickerId']  >= TWS_event_handler.TICKER_GAP):
            t['tickerId'] = t['tickerId']  - TWS_event_handler.TICKER_GAP
        try:
            del(t['self'])
        except (KeyError, ):
            pass          
        

        for k,v in t.iteritems():
                #print k, v, type(v)
                #if type(v) in [Contract, Execution, ExecutionFilter, OrderState, Order, CommissionReport]:
            if 'ib.ext.' in str(type(v)):     
                t[k] = v.__dict__
            else:
                t[k] = v
        
               
#         t['ts'] = time.time()
#         t['typeName'] = message_name
#         t['source'] = source
            
        
        return t  
            
                
    
    def tickPrice(self, tickerId, field, price, canAutoExecute):
        
        self.broadcast_event('tickPrice', vars())

    def tickSize(self, tickerId, field, size):
        
        self.broadcast_event('tickSize', vars()) #vars())

    def tickOptionComputation(self, tickerId, field, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice):
        
        #self.broadcast_event('tickOptionComputation', self.tick_process_message(vars())) #vars())
        pass

    def tickGeneric(self, tickerId, tickType, value):
        #self.broadcast_event('tickGeneric', vars())
        self.broadcast_event('tickGeneric', vars()) #vars())

    def tickString(self, tickerId, tickType, value):
        #self.broadcast_event('tickString', vars())
        self.broadcast_event('tickString', vars()) #vars())

    def tickEFP(self, tickerId, tickType, basisPoints, formattedBasisPoints, impliedFuture, holdDays, futureExpiry, dividendImpact, dividendsToExpiry):
        self.broadcast_event('tickEFP', vars())

    def orderStatus(self, orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeId):
        self.broadcast_event('orderStatus', vars())

    def openOrder(self, orderId, contract, order, state):
        self.broadcast_event('openOrder', vars())

    def openOrderEnd(self):
        self.broadcast_event('openOrderEnd', vars())

    def updateAccountValue(self, key, value, currency, accountName):
        self.broadcast_event('updateAccountValue', vars())

    def updatePortfolio(self, contract, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accountName):
        self.broadcast_event('updatePortfolio', vars())

    def updateAccountTime(self, timeStamp):
        self.broadcast_event('updateAccountTime', vars())

    def accountDownloadEnd(self, accountName):
        self.broadcast_event('accountDownloadEnd', vars())

    def nextValidId(self, orderId):
        self.broadcast_event('nextValidId', vars())

    def contractDetails(self, reqId, contractDetails):
        self.broadcast_event('contractDetails', vars())

    def contractDetailsEnd(self, reqId):
        self.broadcast_event('contractDetailsEnd', vars())

    def bondContractDetails(self, reqId, contractDetails):
        self.broadcast_event('bondContractDetails', vars())

    def execDetails(self, reqId, contract, execution):
        self.broadcast_event('execDetails', vars())

    def execDetailsEnd(self, reqId):
        self.broadcast_event('execDetailsEnd', vars())

    def connectionClosed(self):
        self.broadcast_event('connectionClosed', {})

    def error(self, id=None, errorCode=None, errorMsg=None):
        logging.error(self.serialize_vars_to_dict('error', vars()))
        self.broadcast_event('error', vars())

    def error_0(self, strvalue=None):
        logging.error(self.serialize_vars_to_dict('error_0', vars()))
        self.broadcast_event('error_0', vars())

    def error_1(self, id=None, errorCode=None, errorMsg=None):
        logging.error(self.serialize_vars_to_dict('error_1', vars()))        
        self.broadcast_event('error_1', vars())

    def updateMktDepth(self, tickerId, position, operation, side, price, size):
        self.broadcast_event('updateMktDepth', vars())

    def updateMktDepthL2(self, tickerId, position, marketMaker, operation, side, price, size):
        self.broadcast_event('updateMktDepthL2', vars())

    def updateNewsBulletin(self, msgId, msgType, message, origExchange):
        self.broadcast_event('updateNewsBulletin', vars())

    def managedAccounts(self, accountsList):
        logging.info(self.serialize_vars_to_dict('managedAccounts', vars()))
        self.broadcast_event('managedAccounts', vars())

    def receiveFA(self, faDataType, xml):
        self.broadcast_event('receiveFA', vars())

    def historicalData(self, reqId, date, open, high, low, close, volume, count, WAP, hasGaps):
        self.broadcast_event('historicalData', vars())

    def scannerParameters(self, xml):
        self.broadcast_event('scannerParameters', vars())

    def scannerData(self, reqId, rank, contractDetails, distance, benchmark, projection, legsStr):
        self.broadcast_event('scannerData', vars())


    def commissionReport(self, commissionReport):
        self.broadcast_event('commissionReport', vars())


    def currentTime(self, time):
        self.broadcast_event('currentTime', vars())

    def deltaNeutralValidation(self, reqId, underComp):
        self.broadcast_event('deltaNeutralValidation', vars())


    def fundamentalData(self, reqId, data):
        self.broadcast_event('fundamentalData', vars())

    def marketDataType(self, reqId, marketDataType):
        self.broadcast_event('marketDataType', vars())


    def realtimeBar(self, reqId, time, open, high, low, close, volume, wap, count):
        self.broadcast_event('realtimeBar', vars())

    def scannerDataEnd(self, reqId):
        self.broadcast_event('scannerDataEnd', vars())


    def tickSnapshotEnd(self, reqId):
        self.broadcast_event('tickSnapshotEnd', vars())


    def position(self, account, contract, pos, avgCost):
        self.broadcast_event('position', vars())

    def positionEnd(self):
        self.broadcast_event('positionEnd', vars())

    def accountSummary(self, reqId, account, tag, value, currency):
        self.broadcast_event('accountSummary', vars())

    def accountSummaryEnd(self, reqId):
        self.broadcast_event('accountSummaryEnd', vars())



class TWS_gateway():

    # config
    config = None
    # redis connection
    rs = None

    
    # channel clients' requests to IB/TWS
    gw_message_prosumer = None

    # manage conID / contracts mapping
    contract_subscription_mgr = None  
    
    connection = None
    
    # handler to process incoming IB/TWS messages and echo back to clients  
    tws_event_handler = None
    
    # monitor IB connection / heart beat
    ibh = None
    tlock = None
    ib_conn_status = None
    ib_order_transmit = False
    
    
    def __init__(self, host, port, clientId, kafka_host, kafka_port, config):
        super(TWS_gateway, self).__init__()
        self.config = config
        self.host = host
        self.port = port
        self.clientId = clientId
        self.ib_order_transmit = config.get("tws_gateway", "tws_gateway.order_transmit").strip('"').strip("'") if \
                                        config.get("tws_gateway", "tws_gateway.order_transmit").strip('"').strip("'") <> None\
                                        else False
        
        logging.info('starting up TWS_gateway...')
        logging.info('Order straight through (no-touch) flag = %s' % ('True' if self.ib_order_transmit == True else 'False'))

        logging.info('connecting to Redis server...')
        self.initialize_redis(config)
        
        
        logging.info('starting up gateway message handler - kafka Prosumer...')
        client_requests = list(TWS_Protocol.topicMethods) + list(TWS_Protocol.gatewayMethods)
        self.gw_message_prosumer = Prosumer(name='tws_gw_prosumer', kwargs={'bootstrap_host':'localhost', 'bootstrap_port':9092,
                                        'redis_host':'localhost', 'redis_port':6379, 'redis_db':0,
                                        'group_id': 'groupA', 'session_timeout_ms':10000,
                                                 'topics': client_requests, 'clear_offsets' : 0})
        
        logging.info('register listeners for client requests')
        
        logging.info('starting up TWS_event_handler...')
        
        self.tws_event_handler = TWS_event_handler(self.gw_message_prosumer)
        logging.info('starting up IB EClientSocket...')
        self.connection = EClientSocket(self.tws_event_handler)
        
        

        

        
        #
        #    register listeners
        #
        


         
        

        if not self.eConnect():
            logging.error('TWS_gateway: unable to establish connection to IB %s:%d' % (self.host, self.port))
            sys.exit(-1)
        else:
            # start heart beat monitor
            logging.info('starting up IB heart beat monitor...')
            self.tlock = Lock()
            self.ibh = IbHeartBeat(config)
            self.ibh.register_listener([self.on_ib_conn_broken])
            self.ibh.run()  


        logging.info('starting up subscription manager...')
        self.initialize_subscription_mgr()


    def start_gateway(self):
        self.get_gw_message_prosumer().start_prosumer()

    def initialize_subscription_mgr(self):
        
        self.contract_subscription_mgr = SubscriptionManager(self)
        self.contract_subscription_mgr.register_persistence_callback(self.persist_subscriptions)
        key = self.config.get("tws_gateway",  "subscription_manager.subscriptions.redis_key").strip('"').strip("'")
        if self.rs.get(key):
            #contracts = map(lambda x: ContractHelper.kvstring2contract(x), json.loads(self.rs.get(key)))
            
            def is_outstanding(c):
                
                today = time.strftime('%Y%m%d') 
                if c.m_expiry < today:
                    logging.info('initialize_subscription_mgr: ignoring expired contract %s%s%s' % (c.m_expiry, c.m_strike, c.m_right))
                    return False
                return True
            
            contracts = filter(lambda x: is_outstanding(x), 
                               map(lambda x: ContractHelper.kvstring2object(x, Contract), json.loads(self.rs.get(key))))
            
            
            
            
            self.contract_subscription_mgr.load_subscription(contracts)
        

    def persist_subscriptions(self, contracts):
         
        key = self.config.get("tws_gateway",  "subscription_manager.subscriptions.redis_key").strip('"').strip("'")
        #cs = json.dumps(map(lambda x: ContractHelper.contract2kvstring(x) if x <> None else None, contracts))
        cs = json.dumps(map(lambda x: ContractHelper.object2kvstring(x) if x <> None else None, contracts))
        logging.debug('Tws_gateway: updating subscription table to redis store %s' % cs)
        self.rs.set(key, cs)


    def initialize_redis(self, config):
        r_host = config.get("redis", "redis.server").strip('"').strip("'")
        r_port = config.get("redis", "redis.port")
        r_db = config.get("redis", "redis.db")     

        self.rs = redis.Redis(r_host, r_port, r_db)
        try:
            self.rs.client_list()
        except redis.ConnectionError:
            logging.error('TWS_gateway: unable to connect to redis server using these settings: %s port:%d db:%d' % (r_host, r_port, r_db))
            logging.error('aborting...')
            sys.exit(-1)
            

    def eConnect(self):
        logging.info('ClientRequestHandler - eConnect. Connecting to %s:%s App Id: %s' % (self.host, self.port, self.clientId))
        self.connection.eConnect(self.host, self.port, self.clientId)
        return self.tws_connect.isConnected()

    def eDisconnect(self, value=None):
        sleep(2)
        self.connection.eDisconnect()
    

    def get_gw_message_prosumer(self):
        return self.gw_message_prosumer
    
 


    def on_ib_conn_broken(self, msg):
        logging.error('TWS_gateway: detected broken IB connection!')
        self.ib_conn_status = 'ERROR'
        self.tlock.acquire() # this function may get called multiple times
        try:                 # block until another party finishes executing
            if self.ib_conn_status == 'OK': # check status
                return                      # if already fixed up while waiting, return 
            
            self.eDisconnect()
            self.eConnect()
            while not self.connection.isConnected():
                logging.error('TWS_gateway: attempt to reconnect...')
                self.eConnect()
                sleep(2)
            
            # we arrived here because the connection has been restored
            # resubscribe tickers again!
            logging.info('TWS_gateway: IB connection restored...resubscribe contracts')
            self.contract_subscription_mgr.force_resubscription()             
            
            
        finally:
            self.tlock.release()          
        

class ClientRequestHandler(BaseMessageListener):
    
    def __init__(self, name, tws_gateway):
        BaseMessageListener.__init__(self, name, tws_gateway)
        self.producer = tws_gateway
        self.tws_connect = tws_gateway.connection
            
    
    
    def reqAccountUpdates(self, value=None):
        logging.info('ClientRequestHandler - reqAccountUpdates value=%s' % value)
        self.tws_connect.reqAccountUpdates(1, '')
    
    def reqAccountSummary(self, value):
        logging.info('ClientRequestHandler - reqAccountSummary value=%s' % value)
        
        vals = map(lambda x: x.encode('ascii') if isinstance(x, unicode) else x, json.loads(value))
        self.tws_connect.reqAccountSummary(vals[0], vals[1], vals[2])
        
    def reqOpenOrders(self, value=None):
        self.tws_connect.reqOpenOrders()
    
    def reqPositions(self, value=None):
        self.tws_connect.reqPositions()
        
        
    def reqExecutions(self, value):
        try:
            filt = ExecutionFilter() if value == '' else ExecutionFilterHelper.kvstring2object(value, ExecutionFilter)
            self.tws_connect.reqExecutions(0, filt)
        except:
            logging.error(traceback.format_exc())
    
    
    def reqIds(self, value=None):
        self.tws_connect.reqIds(1)
    
    
    def reqNewsBulletins(self):
        self.tws_connect.reqNewsBulletins(1)
    
    
    def cancelNewsBulletins(self):
        self.tws_connect.cancelNewsBulletins()
    
    
    def setServerLogLevel(self):
        self.tws_connect.setServerLogLevel(3)
    
    
    def reqAutoOpenOrders(self):
        self.tws_connect.reqAutoOpenOrders(1)
    
    
    def reqAllOpenOrders(self):
        self.tws_connect.reqAllOpenOrders()
    
    
    def reqManagedAccts(self):
        self.tws_connect.reqManagedAccts()
    
    
    def requestFA(self):
        self.tws_connect.requestFA(1)
    
    
    def reqMktData(self, sm_contract):
        logging.info('ClientRequestHandler received reqMktData request <no action: pass...> : %s' % sm_contract)
    
    def reqHistoricalData(self):
        contract = Contract()
        contract.m_symbol = 'QQQQ'
        contract.m_secType = 'STK'
        contract.m_exchange = 'SMART'
        endtime = strftime('%Y%m%d %H:%M:%S')
        self.tws_connect.reqHistoricalData(
            tickerId=1,
            contract=contract,
            endDateTime=endtime,
            durationStr='1 D',
            barSizeSetting='1 min',
            whatToShow='TRADES',
            useRTH=0,
            formatDate=1)
    
    
    def placeOrder(self, value=None):
        logging.info('TWS_gateway - placeOrder value=%s' % value)
        try:
            vals = json.loads(value)
        except ValueError:
            logging.error('TWS_gateway - placeOrder Exception %s' % traceback.format_exc())
            return
        
    #        c = ContractHelper.kvstring2contract(vals[1])
        o = OrderHelper.kvstring2object(vals[2], Order)
        o.__dict__['transmit'] = self.ib_order_transmit
    #         print c.__dict__
    #         print o.__dict__
    #         print '---------------------'
    
           
        #self.connection.placeOrder(vals[0], ContractHelper.kvstring2contract(vals[1]), OrderHelper.kvstring2object(vals[2], Order))
        self.tws_connect.placeOrder(vals[0], ContractHelper.kvstring2object(vals[1], Contract), OrderHelper.kvstring2object(vals[2], Order))
    #        self.connection.placeOrder(orderId, contract, newOptOrder)
        

    
    """
       Client requests to TWS_gateway
    """
    def gw_req_subscriptions(self, value=None):
        
        #subm = map(lambda i: ContractHelper.contract2kvstring(self.contract_subscription_mgr.handle[i]), range(len(self.contract_subscription_mgr.handle)))
        #subm = map(lambda i: ContractHelper.object2kvstring(self.contract_subscription_mgr.handle[i]), range(len(self.contract_subscription_mgr.handle)))
        subm = map(lambda i: (i, ContractHelper.object2kvstring(self.contract_subscription_mgr.handle[i])), range(len(self.contract_subscription_mgr.handle)))
        
        print subm
        if subm:
            self.producer.send_message('gw_subscriptions', self.produce.message_dumps({'subscriptions': subm}))
            
            
       
    
        
class SubscriptionManager(BaseMessageListener):
    
    
    # array list of contracts
    handle = []
    # contract key map to contract ID (index of the handle array)
    tickerId = {}
    
    persist_f = None
    
    def __init__(self, name, tws_gateway):
        BaseMessageListener.__init__(self, name)
        self.producer = tws_gateway
        self.tws_connect = tws_gateway.connection    
   
    def load_subscription(self, contracts):
        for c in contracts:
            self.reqMktData(c)
            
        self.dump()
    
    # returns -1 if not found, else the key id (which could be a zero value)
    def is_subscribed(self, contract):
        #print self.conId.keys()
        ckey = ContractHelper.makeRedisKeyEx(contract) 
        if ckey not in self.tickerId.keys():
            return -1
        else:
            # note that 0 can be a key 
            # be careful when checking the return values
            # check for true false instead of using implicit comparsion
            return self.tickerId[ckey]
    

#     def reqMktDataxx(self, contract):
#         print '---------------'
#         contractTuple = ('USO', 'STK', 'SMART', 'USD', '', 0.0, '')
#         stkContract = self.makeStkContract(contractTuple)     
#         stkContract.m_includeExpired = False       
#         self.parent.connection.reqMktData(1, stkContract, '', False)     
# 
#         contractTuple = ('IBM', 'STK', 'SMART', 'USD', '', 0.0, '')
#         stkContract = self.makeStkContract(contractTuple)
#         stkContract.m_includeExpired = False
#         print stkContract   
#         print stkContract.__dict__         
#         self.parent.connection.reqMktData(2, stkContract, '', False)     
#             
            
    def reqMktData(self, kvs_contract):
                  
        
        #logging.info('SubscriptionManager: reqMktData')
        logging.info('SubscriptionManager received reqMktData request: %s' % kvs_contract)
  
        def add_subscription(contract):
            self.handle.append(contract)
            newId = len(self.handle) - 1
            self.tickerId[ContractHelper.makeRedisKeyEx(contract)] = newId 
             
            return newId
  
        contract = ContractHelper.kvstring2object(kvs_contract, Contract)
        id = self.is_subscribed(contract)
        if id == -1: # not found
            id = add_subscription(contract)

            #
            # the conId must be set to zero when calling TWS reqMktData
            # otherwise TWS will fail to subscribe the contract
            
            self.tws_connect.reqMktData(id, contract, '', False) 
            
            
                   
            if self.persist_f:
                logging.debug('SubscriptionManager reqMktData: trigger callback')
                self.persist_f(self.handle)
                
            logging.info('SubscriptionManager: reqMktData. Requesting market data, id = %d, contract = %s' % (id, ContractHelper.makeRedisKeyEx(contract)))
        
        else:    
            self.tws_connect.reqMktData(1000 + id, contract, '', True)
            logging.info('SubscriptionManager: reqMktData: contract already subscribed. Request snapshot = %d, contract = %s' % (id, ContractHelper.makeRedisKeyEx(contract)))
        #self.dump()

        #
        # instruct gateway to broadcast new id has been assigned to a new contract
        #
        self.producer.send_message('gw_notify_subscription_changed', self.producer.message_dumps({id: ContractHelper.object2kvstring(contract)}))
        #>>>self.parent.gw_notify_subscription_changed({id: ContractHelper.object2kvstring(contract)})
        logging.info('SubscriptionManager reqMktData: gw_notify_subscription_changed: %d:%s' % (id, ContractHelper.makeRedisKeyEx(contract)))
        
        
        
#     def makeStkContract(self, contractTuple):
#         newContract = Contract()
#         newContract.m_symbol = contractTuple[0]
#         newContract.m_secType = contractTuple[1]
#         newContract.m_exchange = contractTuple[2]
#         newContract.m_currency = contractTuple[3]
#         newContract.m_expiry = contractTuple[4]
#         newContract.m_strike = contractTuple[5]
#         newContract.m_right = contractTuple[6]
#         print 'Contract Values:%s,%s,%s,%s,%s,%s,%s:' % contractTuple
#         return newContract        
   
    # use only after a broken connection is restored
    # to re request market data 
    def force_resubscription(self):
        # starting from index 1 of the contract list, call  reqmktdata, and format the result into a list of tuples
        for i in range(1, len(self.handle)):
            self.tws_connect.reqMktData(i, self.handle[i], '', False)
            logging.info('force_resubscription: %s' % ContractHelper.printContract(self.handle[i]))
       
            
    def itemAt(self, id):
        if id > 0 and id < len(self.handle):
            return self.handle[id]
        return -1

    def dump(self):
        
        logging.info('subscription manager table:---------------------')
        logging.info(''.join('%d: {%s},\n' % (i,  ''.join('%s:%s, ' % (k, v) for k, v in self.handle[i].__dict__.iteritems() )\
                                     if self.handle[i] <> None else ''          ) for i in range(len(self.handle)))\
                     )
        
        #logging.info( ''.join('%s[%d],\n' % (k, v) for k, v in self.conId.iteritems()))
        logging.info( 'Number of instruments subscribed: %d' % len(self.handle))
        logging.info( '------------------------------------------------')
        
    def register_persistence_callback(self, func):
        logging.info('subscription manager: registering callback')
        self.persist_f = func
        

    
        



                
    
def test_subscription():        
    s = SubscriptionManager()
    contractTuple = ('HSI', 'FUT', 'HKFE', 'HKD', '20151029', 0, '')
    c = ContractHelper.makeContract(contractTuple)   
    print s.is_subscribed(c)
    print s.add_subscription(c)
    print s.is_subscribed(c)
    s.dump()
    
    fr = open('/home/larry-13.04/workspace/finopt/data/subscription-hsio.txt')
    for l in fr.readlines():
        if l[0] <> '#':
             
            s.add_subscription(ContractHelper.makeContract(tuple([t for t in l.strip('\n').split(',')])))    
    fr.close()
    s.dump()
    
    fr = open('/home/larry-13.04/workspace/finopt/data/subscription-hsio.txt')
    for l in fr.readlines():
        if l[0] <> '#':
             
            print s.add_subscription(ContractHelper.makeContract(tuple([t for t in l.strip('\n').split(',')])))    
    s.dump()
    contractTuple = ('HSI', 'FUT', 'HKFE', 'HKD', '20151127', 0, '')
    c = ContractHelper.makeContract(contractTuple)   
    print s.is_subscribed(c)
    print s.add_subscription(c)
    print s.is_subscribed(c), ContractHelper.printContract(s.itemAt(s.is_subscribed(c))) 
    
    print 'test itemAt:'
    contractTuple = ('HSI', 'OPT', 'HKFE', 'HKD', '20151127', 21400, 'C')
    c = ContractHelper.makeContract(contractTuple)
    print s.is_subscribed(c), ContractHelper.printContract(s.itemAt(s.is_subscribed(c)))
    
    


    
    
if __name__ == '__main__':
    
    if len(sys.argv) != 2:
        print("Usage: %s <config file>" % sys.argv[0])
        exit(-1)    

    cfg_path= sys.argv[1:]
    config = ConfigParser.SafeConfigParser()
    if len(config.read(cfg_path)) == 0: 
        raise ValueError, "Failed to open config file" 
    
   
      
    logconfig = eval(config.get("tws_gateway", "tws_gateway.logconfig").strip('"').strip("'"))
    logconfig['format'] = '%(asctime)s %(levelname)-8s %(message)s'    
    logging.basicConfig(**logconfig)        
    

    
    
    khost = config.get("epc", "kafka.host").strip('"').strip("'")
    kport = config.get("epc", "kafka.port")
    ihost = config.get("market", "ib.gateway").strip('"').strip("'")
    iport = int(config.get("market", "ib.port"))
    iappid = int(config.get("market", "ib.appid.portfolio"))   
    
    
    
    
    #print 'give kafka server some time to register the topics...'
    #sleep(2)
    
    app = TWS_gateway(ihost, iport, iappid, khost, kport, config)
    app.start_gateway()
    print 'TWS_gateway started.'
#     


    


#    test_subscription()
    