""" Combine the camera control from synchronous.py with LED ring from serialtest.py
Camera trigger should come from LED
IH 5/22/23
"""

import sys
import cv2
from typing import Optional
from vimba import *

import serial
import time

inttimes = [50, 50, 50, 50, 100, 300, 500, 600]
i = 0


# copied but modified to not print help text
def abort(reason: str, return_code: int = 1):
    print(reason + '\n')

    sys.exit(return_code)


# copied from sample code; this function allows a camera id to be passed, e.g. by user argument
# but not including the code to read a camera ID as user argument
# since we'll only have one camera and easier to autodetect
def get_camera(camera_id: Optional[str]) -> Camera:
    with Vimba.get_instance() as vimba:
        if camera_id:
            try:
                return vimba.get_camera_by_id(camera_id)

            except VimbaCameraError:
                abort('Failed to access Camera \'{}\'. Abort.'.format(camera_id))

        else:
            cams = vimba.get_all_cameras()
            if not cams:
                abort('No Cameras accessible. Abort.')

            return cams[0]
        
# below modified from aysnchronous_grab_opencv
# set up for trigger on external signal
def setup_camera(cam: Camera):
    with cam:

        # turns out I would like to knwo if one of these fails
        cam.ExposureMode.set('TriggerWidth')
        cam.LineSelector.set('Line0')
        cam.LineMode.set('Input')
        cam.TriggerSelector.set('FrameStart')
        cam.TriggerActivation.set('LevelHigh')
        cam.TriggerSource.set('Line0')
        cam.TriggerMode.set('On')

        """
        try:
            cam.ExposureMode.set('TriggerWidth')
        except (AttributeError, VimbaFeatureError):
            pass

        try:
            cam.LineSelector.set('Line0')
        except (AttributeError, VimbaFeatureError):
            pass

        try:
            cam.LineMode.set('Input')
        except (AttributeError, VimbaFeatureError):
            pass

        try:
            cam.TriggerSelector.set('FrameStart')
        except (AttributeError, VimbaFeatureError):
            pass

        try:
            cam.TriggerActivation.set('LevelHigh')
        except (AttributeError, VimbaFeatureError):
            pass

        try:
            cam.TriggerSource.set('Line0')
        except (AttributeError, VimbaFeatureError):
            pass

        try:
            cam.TriggerMode.set('On')
        except (AttributeError, VimbaFeatureError):
            pass
        """

        # Query available, open_cv compatible pixel formats
        # monochrome formats only for our camera
        cv_fmts = intersect_pixel_formats(cam.get_pixel_formats(), OPENCV_PIXEL_FORMATS)
        mono_fmts = intersect_pixel_formats(cv_fmts, MONO_PIXEL_FORMATS)

        if mono_fmts:
            cam.set_pixel_format(mono_fmts[0])

        else:
            abort('Camera does not support a OpenCV compatible format natively. Abort.')


def main():
    # cam_id = parse_args() - remove this

    ENTER_KEY_CODE = 13

    with Vimba.get_instance():
        with get_camera(None) as cam:
            setup_camera(cam)

            i = 1

            with serial.Serial('COM3', baudrate=115200, timeout=1) as ser:

                while (i < 100):
                    strtosend = '!{0},{1}\n\r'.format(str(i%8),str(inttimes[i%8]))
                    ser.write(strtosend.encode())

                    # Acquire one frame
                    for frame in cam.get_frame_generator(limit=1, timeout_ms=2000):
                        print('Got {}'.format(frame), flush=True)

                        msg = 'Frames from LED{}, integration {}ms'
                        cv2.imshow(msg.format(str(i%8),str(inttimes[i%8])), frame.as_opencv_image())
                        key = cv2.waitKey(1) 
                        # waitKey(1) waits for 1ms; asynchronous_grab_opencv calls this before imshow to check for Enter, 
                        # but examples online call it after
                        # code doesn't work without it
                        # we'll also check for an Enter to close the window
                        # tried to move out of for loop so it can break out of while loop, but dind't work-
                        # key variable may only exist within the for loop
                        if key == ENTER_KEY_CODE:
                            cv2.destroyAllWindows()
                            break

                    i += 1
                    time.sleep(0.5)


if __name__ == '__main__':
    main()