#!/usr/bin/env python3
"""motion_recorder.py : self-contained camera video processing and data collection example
"""
import argparse, time
import numpy as np

# https://docs.opencv.org/modules/highgui/doc/highgui.html
# https://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html
# https://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html
import cv2 as cv

from pythonosc import osc_message_builder
from pythonosc import udp_client

# import the model learning code from the same folder
import motion_model

#================================================================
if __name__ == "__main__":
    parser = argparse.ArgumentParser( description = "Process a video stream from the default camera.")
    parser.add_argument( '--camera', default=0, type=int, help="Select camera by number (default: %(default)s).")
    parser.add_argument( '-s','--saturation', action='store_true', help='Use only saturation channel.')
    parser.add_argument( '-b','--background', action='store_false', help='Disable background subtraction.')
    parser.add_argument( '-q','--quiet', action='store_true', help="Run without viewer window or console output.")
    parser.add_argument( '--debug', action='store_true', help='Enable debugging output to log file.' )
    parser.add_argument( '--verbose', action='store_true', help='Enable even more detailed logging output.' )
    parser.add_argument("--ip", default="127.0.0.1",  help="IP address of the OSC receiver (default: %(default)s).")
    parser.add_argument("--port", type=int, default=22000,  help="OSC receiver UDP port (default: %(default)s).")
    parser.add_argument("--data", type=str, default="motion.data",  help="File to write with data (default: %(default)s).")
    args = parser.parse_args()

    capture = cv.VideoCapture(args.camera)
    if not capture.isOpened():
        print("Unable to open camera, exiting.")
        exit(1)

    if not args.quiet:
        cv.namedWindow("motion detector")

    if args.background:
        bgs = cv.createBackgroundSubtractorMOG2()

    client = udp_client.SimpleUDPClient(args.ip, args.port)

    data_file = open(args.data, "a")
    recording = False

    # build the motion classifier from previously saved data
    classifier = motion_model.build_model()
    history = None

    def repeat():
        success, frame = capture.read()
        if success:
            if args.saturation:
                # transform the image
                frame = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
                # pick out saturation
                frame = frame[:,:,1]

            if args.background:
                foreground_mask = bgs.apply(frame)
                frame = foreground_mask

            # flip the image left to right for 'selfie' mode
            frame = frame[:,::-1]

            # reduce the whole frame to a tiny 1D image
            rows, cols = frame.shape[0:2]
            motion = cv.resize(frame, (16, 1))

            # replace a stripe at the bottom with a blocky 1D image for preview
            preview_height = rows // 10
            frame[-preview_height:][:] = cv.resize(motion, (cols, preview_height), interpolation=cv.INTER_NEAREST)

            # print ("Showing image...")
            if not args.quiet:
                cv.imshow("viewer", frame)

            if args.background:
                # apply the new sample to the history and classify it
                global history
                history = motion_model.update_history(history, motion)
                label = motion_model.classify_history(classifier, history)
                print(label)

                # send black and white values as an OSC message
                msg = [int(i) for i in motion[:][0]]
                # print("Sending", msg, type(msg[0]))
                client.send_message("/motion", msg)

                if recording:
                    line = " ".join([str(i) for i in msg]) + "\n"
                    data_file.write(line)

        else:
            if args.verbose:
                print ("no image")

    try:
        while True:
            repeat()

            # Calling waitKey allows the window system event loop to run and update
            # the display.  The waitKey argument is in milliseconds.
            key = cv.waitKey(33) & 0xFF
            if key == ord('q'):
                break
            elif key == ord(' '):
                recording = not recording
                print("Recording:", recording)

    except KeyboardInterrupt:
        print ("User quit.")

    capture.release()
    data_file.close()
