#!/usr/bin/python3
# Cloud Display Control - Copyright 2016 Lucid Networks - Stephen Loeckle

import socket
import binascii
import codecs
import logging
import os
import time
from time import time
import datetime
import collections
import configparser
import argparse
from multiprocessing import Process, Queue, current_process
from cdclib import getinput, getfirmware, getmodel, getpowermode, getserial, gettmmode, gettmpos, getvolume

outputargs = {}

outputargs['debugoutput'] = 0
outputargs['modelserialoutput'] = 0
outputargs['firmwareoutput'] = 0
outputargs['inputoutput'] = 0
outputargs['tileoutput'] = 0
outputargs['poweroutput'] = 0
outputargs['volumeoutput'] = 0

PORT = 7142

def DisplayWorker(ip, port, socketid, out_q, outputargs):
            name = current_process().name
            ts = time()
#            output = [0,1,2,3,4,5,6,7,8]
            output = {}
            s = [0,1,2,3,4,5,6,7,8,9]
            now = str(datetime.datetime.now())
            if outputargs['debugoutput'] == 1:
                print("{0} Setting up network socket {1} to {2}".format(name,socketid,ip))
                output[socketid,0]=("{0} Work started: {1}".format(name,now))
                output[socketid,1]=("{0} Setting up network socket {1}".format(name,socketid))
            s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            if outputargs['debugoutput'] == 1:
                output[socketid,2]=("{0} Connecting to network socket".format(name))
            s[socketid].connect((ip, port))
            if outputargs['debugoutput'] == 1:
                output[socketid,3]=("{0} Beginning to send data to network socket".format(name))
            s[socketid].send(b"\x01\x30\x2A\x30\x43\x30\x36\x02\x30\x32\x33\x45\x03\x1A\x0D")
            response = s[socketid].recv(27)
            hexresponse = binascii.b2a_hex(response)
            if hexresponse == b'01303041443132023030303233453030303036343030303103700d':
                displayid = 1
            if hexresponse == b'01303042443132023030303233453030303036343030303203700d':
                displayid = 2
            if hexresponse == b'01303043443132023030303233453030303036343030303303700d':
                displayid = 3
            if hexresponse == b'01303044443132023030303233453030303036343030303403700d':
                displayid = 4
            if hexresponse == b'01303045443132023030303233453030303036343030303503700d':
                displayid = 5
            if hexresponse == b'01303046443132023030303233453030303036343030303603700d':
                displayid = 6
            if hexresponse == b'01303047443132023030303233453030303036343030303703700d':
                displayid = 7
            if hexresponse == b'01303048443132023030303233453030303036343030303803700d':
                displayid = 8
            if hexresponse == b'01303049443132023030303233453030303036343030303903700d':
                displayid = 9
            if hexresponse == b'0130304a4431320230303032334530303030363430303041030b0d':
                displayid = 10

#            output[socketid,]=(displayid)
            model = getmodel(displayid,s[socketid])
            serial = getserial(displayid,s[socketid])
            firmware1,firmware2,firmware3,firmware4 = getfirmware(displayid,s[socketid])
            input = getinput(displayid,s[socketid])
            tmmode = gettmmode(displayid,s[socketid])
            tmpos = gettmpos(displayid,s[socketid])
            power = getpowermode(displayid,s[socketid])
            volume = getvolume(displayid,s[socketid])

            if outputargs['debugoutput'] == 1:
                output[socketid,4]=("{0} Closing network socket {1}".format(name,socketid))
            s[socketid].close()
            if outputargs['debugoutput'] == 1:
                output[socketid,5]=("{0} Closed network socket {1}".format(name,socketid))

            output[socketid,6]=('Display %s: ' % ip)
            if outputargs['debugoutput'] == 1:
                output[socketid,7]=('    Internal Process: %s' % name)

            output[socketid,8]=('    ID: %d' % displayid)
            if outputargs['modelserialoutput'] == 1:
                output[socketid,9]=('    Model: %s' % model)
                output[socketid,10]=('    Serial: %s' % serial)
            if outputargs['firmwareoutput'] == 1:
                output[socketid,11]=('    Firmware1: %s' % firmware1)
                output[socketid,12]=('    Firmware2: %s' % firmware2)
                output[socketid,13]=('    Firmware3: %s' % firmware3)
                output[socketid,14]=('    Firmware4: %s' % firmware4)
            if outputargs['inputoutput'] == 1:
                output[socketid,15]=('    Input: %s' % input)
            if outputargs['tileoutput'] == 1:
                output[socketid,16]=('    Tile Mode: %s' % tmmode)
                output[socketid,17]=('    Tile Position: %s' % tmpos)
            if outputargs['poweroutput'] == 1:
                output[socketid,18]=('    Power Status: %s' % power)
            if outputargs['volumeoutput'] == 1:
                output[socketid,19]=('    Volume Level: %s' % volume)
            if outputargs['debugoutput'] == 1:
                output[socketid,20]=('Process Took {}'.format(time() - ts))
                now = datetime.datetime.now()
                output[socketid,21]=("{0} Work finished: {1}".format(name,str(now)))
            out_q.put(output)

def main():

    parser = argparse.ArgumentParser(description='Cloud Display Controls - getdisplaystatus')
    parser.add_argument('-a',action="store_true", default=False, dest='all', help = 'All Available Output')
    parser.add_argument('-d', action="store_true", default=False, dest='debug', help = 'Debug output')
    parser.add_argument('-f',action="store_true", default=False, dest='firmware', help = 'Firmware Output Only')
    parser.add_argument('-in', action="store_true", default=False, dest='input', help = 'Input Status Output Only')
    parser.add_argument('-ms', action="store_true", default=False, dest='ms', help = 'Model and Serial Output Only')
    parser.add_argument('-p',action="store_true", default=False, dest='power', help = 'Power Status Output Only')
    parser.add_argument('-pdcomms',action="store_true", default=False, dest='pdcomms', help = 'Output PD Comms Config')
    parser.add_argument('-t',action="store_true", default=False, dest='tile', help = 'Tile Status Output Only')
    parser.add_argument('-v',action="store_true", default=False, dest='volume', help = 'Volume Status Output Only')
    cliargs = parser.parse_args()

    if cliargs.debug:
        logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        logging.getLogger('requests').setLevel(logging.CRITICAL)
        logger = logging.getLogger(__name__)
        outputargs['debugoutput'] = 1
    else:
        logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        logging.getLogger('requests').setLevel(logging.CRITICAL)
        logger = logging.getLogger(__name__)
        outputargs['debugoutput'] = 0

    if cliargs.all:
        outputargs['modelserialoutput'] = 1
        outputargs['firmwareoutput'] = 1
        outputargs['inputoutput'] = 1
        outputargs['tileoutput'] = 1
        outputargs['poweroutput'] = 1
        outputargs['volumeoutput'] = 1

    if cliargs.firmware:
        outputargs['firmwareoutput'] = 1

    if cliargs.input:
        outputargs['inputoutput'] = 1

    if cliargs.ms:
        outputargs['modelserialoutput'] = 1

    if cliargs.pdcomms:
        outputargs['pdcommsoutput'] = 1

    if cliargs.power:
        outputargs['poweroutput'] = 1

    if cliargs.tile:
        outputargs['tileoutput'] = 1

    if cliargs.volume:
        outputargs['volumeoutput'] = 1
    
    config = configparser.ConfigParser()
    config.read(['/etc/cdc/cdc.conf'])
    IP = {}
    ipnum = 0
    for key, val in config.items('network'):
        if 'ip' in key:
            IP[ipnum]=val
            ipnum += 1
    tsmain = time()
    socketnum = 0
    out_q = Queue()
    workers = []
    for ipid, ipaddr in IP.items():
        now = datetime.datetime.now()
#        print("Process started: %s" % str(now))
#        logger.info('Queueing {}'.format(ipaddr))
        worker = Process(target=DisplayWorker, args=(ipaddr, PORT, socketnum, out_q, outputargs))
        workers.append(worker)
        worker.start()
        socketnum += 1
    results = {}
    for i in range(socketnum):
        results.update(out_q.get())
    for w in workers:
        w.join()
    sortedresults = collections.OrderedDict(sorted(results.items()))
    for key,val in sortedresults.items():
        if outputargs['debugoutput'] == 1:
            print("{0} = {1}".format(key,val))
        else:
            print("{}".format(val))
    if outputargs['debugoutput'] == 1:
        print('Took {}'.format(time() - tsmain))

if __name__ == '__main__':
   main()
