#!/usr/bin/python3  -O
import asyncio
from tcpip import Message
import pickle
import sys,getopt
import io
from PIL import Image
import matplotlib.pyplot as plt

from config_manager import ConfigReader

class Client:
    
    def __init__(self,i_o, callback):
        self._conf = ConfigReader('regimes.ini')
        self._server = self._conf.server()
        self._port = self._conf.port()
        self._loop = asyncio.get_event_loop()
        self._callback  = callback
        self._poll = True
        self._loop = asyncio.get_event_loop()
        self._processes = set()
        self._connections = {}
        self._messages =  asyncio.Queue(loop=self._loop)
        self._i_o = i_o
        self._th1 = asyncio.ensure_future(self.poll())
        if self._i_o == 'i':
            print('starting input thread')
            self._th2 = asyncio.ensure_future(self.scan_input())
        
        #self._th3 = asyncio.ensure_future(self.connect())
        self._server = self._loop.run_until_complete(asyncio.gather(self._th1))        
    
    
    async def connect(self):
        if self._i_o == 'i':
            self._inreader = asyncio.StreamReader(loop=self._loop)
            self._reader_protocol = asyncio.StreamReaderProtocol(self._inreader)        
            await self._loop.connect_read_pipe(lambda: self._reader_protocol, sys.stdin)
            
        self._reader, self._writer =  await asyncio.open_connection(self._server,self._port,loop=self._loop)
        self._writer.transport.set_write_buffer_limits(0)
    
    async def poll(self):
        await self.connect()
        while self._poll:
            
            
            header = await self._reader.read(4)
            size = int.from_bytes(header,byteorder='big')
            s = 0
            data = b''
            while s < size:
                toread = min(size - len(data),2**8)
                chunk = await self._reader.read(toread)
                s += len(chunk)
                data += chunk
            
           
            if data == '\n' or self._reader._eof:
                return
            else:
                M = pickle.loads(data)
                self._callback(self,M)
        
    def run(self):
        self._loop.run_forever()
        self._loop.close()
        
        
    def send(self, data):
        self._writer.write(data)
        self._writer.drain()
        
 
    async def scan_input(self):
        while True:
            await asyncio.sleep(0)
            try:
                print ('>')
                i = await  self._inreader.readline()
                self.input(i.decode())
                
            except:
                return 
            
    def input(self, line):
        cmd = line.strip().split(' ')
        if (cmd[0] == 'run'):
            self.process_run_cmd(cmd[1])
        elif (cmd[0] == 'send'):
            self.process_send_cmd(cmd[1])
        elif (cmd[0] == 'killall'):
            self.process_killall()
        elif (cmd[0] == 'graph'):
            self.process_graph_cmd(cmd[1:])
        elif (cmd[0] == 'quit'):
            exit(0)
        else :
            print('unknown command:',cmd[0])
        
    def process_run_cmd(self, cmd):
        if cmd == "covariances":
            m = Message(Message.RUN_COVARS,'')
            self.send(m.tos())  
        elif cmd == "clusters":
            m  = Message(Message.RUN_CLUSTERS,'')
            self.send(m.tos())
        elif cmd == "regimes":
            m  = Message(Message.RUN_REGIMES,'')
            self.send(m.tos())   
        else :
            print ('unknown argument:',cmd)
    def process_graph_cmd(self, args):
        m  = Message(Message.GRAPH,args)
        self.send(m.tos())    
            
    def process_send_cmd(self, cmd):
        try:
            with open(cmd,'rb') as f:
                data = f.read()
            m = Message(Message.FILE, (cmd,data))
            self.send(m.tos())
        except Exception as e:
            print (e)
    def process_killall(self):
        m = Message(Message.KILL_ALL,'')
        self.send(m.tos())          
        
def cb(c,M):
    if c._i_o == 'o':
        if M.cmd == Message.PROGRESS:
            print(M.args,end='\r')
        elif M.cmd == Message.STRING:
            print('message from server:')
            print (M.args)
        elif M.cmd == Message.GRAPH:
            im = Image.open(M.args)
            im.show()
            
if __name__=="__main__": 
    args = sys.argv[1:]
    try:
        opts, args = getopt.getopt(args, 'i')
        io = 'o'
        for opt, arg in opts:
            print (opt)
            if opt == '-i':
                io='i'
        
        c = Client(io, cb)
        c.run()
    except Exception as e :
        print (e)
        
        
 


