import subprocess
from shlex import split
import sys, time
import os

from .control_comedi_swig import comedi_init, set_bits_in_nidaq_using_mask_and_data


def init_comedi():
    '''
    a wrapper that wraps around control_comedi_swig.comedi_init
    to set all channels to output

    '''
    COMEDI_SETUP_STRING = '/dev/comedi0'
    EXPECTED_COMEDI_SETUP_STR = 'found comedi system with 24 channels\n0'

    comedi_setup_str = comedi_init(COMEDI_SETUP_STRING)

    print(comedi_setup_str)

def write_to_comedi(data, mask=255, base_channel=0, method='use_swig', debug=False):
    '''
    this is just a wrapper that can call 
    Inputs:
        data[int]: 0 o 255 integer number  that writes to the ports masked by the mask
        mask[int]: the set of ports to write to
        base_channel[int]: the channel offset to which the bits are written, default to 0
        method[str]: default to use 'use_swig'. can also choose 'use_subprocess'

    Output
        retval[int]: 0 means properly set to the ports

    example usage:
    init_comedi()
    #set the the first 4 bits to be 1 as 15 = 0b1111
    write_to_comedi(15)
    '''
    
    if method == 'use_swig':
        return write_to_comedi_swig(data, mask = mask, base_channel=base_channel,
                             debug = debug)
    elif method == 'subprocess':
        return write_to_comedi_subprocess(data, mask = mask, debug = debug)
    else:
        raise Exception(f'unrecognized method {method}')
    

def write_to_comedi_swig(data, mask=255, base_channel=0, debug=False):
    '''
    this function requires the C interface code generated by swig interface
    Inputs:
        data[int]: 0 to 255 that maps to the 8 bit channels
        mask[int]: that mask which channels to write e.g. 0x3 means 0b11 writes to channels 0 and 1
        base_channel[int]: the channel offset to which the bits are written, default to 0
        debug: debug flag

    Output
        retval[int]: 0 means succussfully set, -1 means not
    '''
    retval = set_bits_in_nidaq_using_mask_and_data(mask, data, base_channel)

    return retval


COMEDI_DIO_WRITE = 0 #this writes to a channel
COMEDI_DIO_BITFIELD = 1 #tis writes to multiple channel
MODULE_FOLDER_PATH = os.path.dirname(__file__)

def write_to_comedi_subprocess(data, mask=255, debug=False):
    '''
    data: an integer bet. 0 and 255 (inclusive) that maps to the 8 bit channels. 
    mask: an integer that mask which channels to write e.g. 0x3 means 0b11 writes to channels 0 and 1
    debug: decoding switch, if
        True: print out the command
        False (default): do nothing. 
    eg. write_to_comedi(3) sets first two channels to high. 

    note: for efficiency, this function assumes data is in integer in [0, 255], 

    '''
    
    cmd = f'{MODULE_FOLDER_PATH}/control_comedi {COMEDI_DIO_BITFIELD} {hex(mask)} {hex(data)}'

    if debug: print(cmd)

    proc = subprocess.Popen(split(cmd), 
                        stderr= subprocess.PIPE,
                        stdout= subprocess.PIPE,
                        stdin= subprocess.PIPE,
                        shell = False)
    retval = (proc.stdout.readline())
    proc.stdout.flush()
    return retval


def check_comedi() -> bool:
    '''
    this function checks whether 
    comedi is working by simply checking the return has the comedi string in it
    it is knd of useless
    '''
    cmd = 'cat /proc/comedi'
    
    retval = subprocess_write(cmd, debug=True)

    if 'comedi' in retval.decode("utf-8"): 
        return True
    else: 
        return False

def time_write_to_comedi():
    '''
    this function calculates how long one write takes, 
    but does not test how long the signal appears on the port. 
    return the time difference in s
    '''
    data = 255

    t1 = time.perf_counter()
    write_to_comedi(data, mask = 255, debug = True)
    t2 = time.perf_counter()

    return t2 - t1

def subprocess_write(cmd:str, debug:bool = False) -> bytes:
    '''
    helper function that writes a command and returns a string
    note that it only returns the first line
    '''
    if debug: print(f'{__name__}: system command: {cmd}')

    proc = subprocess.Popen(split(cmd), 
                        stderr= subprocess.PIPE,
                        stdout= subprocess.PIPE,
                        stdin= subprocess.PIPE,
                        shell = False)
    retval = (proc.stdout.readline())

    if debug: print(f'{__name__}: one line received: {retval}')

    proc.stdout.flush()

    return retval


if __name__ == "__main__":

    print(f'calling c process takes: {time_write_to_comedi()} s')

