#!/usr/bin/python3
# LAVA Controls RPI CLI - Copyright 2019 Lucid Networks - Stephen Loeckle

import argparse
import socket
import binascii
import sys
import inspect
import traceback
import serial
from lavacontrolslibrpi import CoreDisplaySettings, DisplayInfo, getpowermode, Input, saveconfig, sethdmimodes, setpower, Timeout, Volume

def xor(raw):
    gotthefunc = inspect.stack()[0][3]
    x = raw.split()
    xorstring = ''
    cmdsize = len(x)-1
    for location, y in enumerate(x):
        if location < cmdsize:
            xorstring = xorstring + 'int("{}",16) ^ '.format(y)
        elif location == cmdsize:
            xorstring = xorstring + 'int("{}",16)'.format(y)
    bcc = '{}'.format(hex(eval(xorstring))[2:]).upper()
    if len(bcc) == 1:
       bcc = '0' + bcc
    print('Calculated BCC: {}'.format(bcc))

    cmd = '01 ' + raw + ' {} '.format(bcc) + '0D'
    
    return(cmd)

def main():
    gotthefunc = inspect.stack()[0][3]
    parser = argparse.ArgumentParser(description='LAVA Controls RPI CLI')
    parser.add_argument('serial', help = 'Serial Port e.g. /dev/ttyUSB0')
    parser.add_argument('-c', '--cmd', help = "Full Command to write to Display in format: '01 30 2A 30 43 30 36 02 30 32 33 45 03 1A 0D'", nargs=1)
    parser.add_argument('-r', '--raw', help = "RAW Command to write to Display Without SOH, BCC or Delimiter in format: '30 2A 30 43 30 36 02 30 32 33 45 03'", nargs=1)
    parser.add_argument('-hsize', '--hnum', help = 'Change Tile Horizonal Count (integer 1-10)', nargs=1)
    parser.add_argument('-i', '--input', help = 'Change Input (hdmi, dvi or dp)', nargs=1)
    parser.add_argument('-p', '--pos', help = 'Change Tile Position (integer 1-100)', nargs=1)
    parser.add_argument('-t', '--tilemode', help = 'Change Tile Mode (on or off)', nargs=1)
    parser.add_argument('-s', '--save', help = 'Save config after command')
    parser.add_argument('-vsize', '--vnum', help = 'Change Tile Vertical Count (integer 1-10)', nargs=1)
    parser.add_argument('-vol', '--volume', help = 'Change Volume (integer)', nargs=1)
    cliargs = parser.parse_args()

    if (not cliargs.serial):
        parser.error('Serial Port required')
    else:
        serialport = cliargs.serial.strip()
    
    s = serial.Serial(serialport, baudrate=9600, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=5)
    s.isOpen()
    
    if (not cliargs.raw or not cliargs.cmd):
        displayid = 0
        dispconn = DisplayInfo(displayid,s)
        displayid = dispconn.getid()
    elif cliargs.raw:
        raw = cliargs.raw[0].strip()
        if raw[:2] == '01':
            raw = raw[3:]
        if raw[-2:] == '0D':
            raw = raw[:-5]
        print('\n')
        print('Original RAW Command: {}'.format(rawcmd))
        cmd = xor(raw)
    elif cliargs.cmd:
        cmd = cliargs.cmd[0].strip()
        
    if (cliargs.raw or cliargs.cmd):
        print('Full Command: {}'.format(cmd))
        cmd = bytes.fromhex(cmd)
        s.write(cmd)
        received = s.read(27)
        hexreceived = binascii.b2a_hex(received)
        print('Response: {}'.format(hexreceived.decode()))
        print('\n')

    if cliargs.hnum:
        try:
            tmcomp = Tiling(displayid,s)
        except:
            pass
            msg = ('D{}: Error in {}!'.format(displayid,gotthefunc))
            print(msg)
            err = traceback.format_exc()
            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
            print(msg)
        try:
            hsize = tmcomp.sethsize(int(cliargs.hnum[0]))
        except:
            pass
            msg = ('D{}: Error in {}!'.format(displayid,gotthefunc))
            print(msg)
            err = traceback.format_exc()
            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
            print(msg)
        else:
            print('D{}: Tile horizontal count set to: {}'.format(displayid,hsize))
            
    if cliargs.pos:
        try:
            tmcomp = Tiling(displayid,s)
        except:
            pass
            msg = ('D{}: Error in {}!'.format(displayid,gotthefunc))
            print(msg)
            err = traceback.format_exc()
            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
            print(msg)
        try:
            pos = tmcomp.setpos(int(cliargs.pos[0]))
        except:
            pass
            msg = ('D{}: Error in {}!'.format(displayid,gotthefunc))
            print(msg)
            err = traceback.format_exc()
            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
            print(msg)
        else:
            print('D{}: Tile position set to: {}'.format(displayid,hsize))
        
    if cliargs.vnum:
        try:
            tmcomp = Tiling(displayid,s)
        except:
            pass
            msg = ('D{}: Error in {}!'.format(displayid,gotthefunc))
            print(msg)
            err = traceback.format_exc()
            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
            print(msg)
        try:
            vsize = tmcomp.setvsize(int(cliargs.vnum[0]))
        except:
            pass
            msg = ('D{}: Error in {}!'.format(displayid,gotthefunc))
            print(msg)
            err = traceback.format_exc()
            msg = ('D{}: Error in {} Detail: {}'.format(displayid,gotthefunc,err))
            print(msg)
        else:
            print('D{}: Tile vertical count set to: {}'.format(displayid,vsize))
        
    if cliargs.save:
        saveconfig(displayid,s)

if __name__ == '__main__':
   main()