# NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
# This code is NOT used, it's just saved for future reference
# NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!

from flask import Flask, render_template, Response
from flask_socketio import SocketIO, emit
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
import numpy as np
from threading import Thread

latest_video_frame_bytes = []

current_time = 0

# initialize the web server:
app = Flask(__name__)
socketio = SocketIO(app, async_mode = "threading")
# (without "async_mode = "threading", sending stuff to the cliend (via socketio) doesn't work!)

def video_thread():
    # enable the thread to modify the global variable 'latest_video_frame_bytes':
    global latest_video_frame_bytes, current_time

    # create an instance of the RPI camera class:
    camera = PiCamera()

    # rotate the camera view 180 deg (the RPI camera is mounted upside down):
    #camera.hflip = True
    #camera.vflip = True

    # set resolution and frame rate:
    camera.resolution = (360, 270)
    camera.framerate = 15

    # create a generator 'video_frame_generator' which will continuously capture
    # video frames from the camera and save them one by one in the container
    # 'generator_output' ('video_frame_generator' is an infinte iterator which
    # on every iteration (every time 'next()' is called on it, like eg in a
    # for loop) gets a video frame from the camera and saves it in 'generator_output')):
    generator_output = PiRGBArray(camera, size=(360, 270))
    video_frame_generator = camera.capture_continuous(generator_output, format="bgr",
                use_video_port=True)

    # allow the camera to warm up:
    time.sleep(0.1)

    for item in video_frame_generator:
        # get the numpy array representing the latest captured video frame from
        # the camera:
        frame = generator_output.array

        # convert the latest read video frame to memory buffer format:
        ret, frame_buffer = cv2.imencode(".jpg", frame)

        # get the raw data bytes of 'frame_buffer' (convert to binary):
        frame_bytes = frame_buffer.tobytes()
        # save it globally for everyone to access:
        latest_video_frame_bytes = frame_bytes

        # clear the output container so it can store the next frame in the next loop cycle
        # (please note that this step is absolutely necessary!):
        generator_output.truncate(0)

def gen_normal():
    while 1:
        if len(latest_video_frame_bytes) > 0: # if we have started receiving actual frames:
            frame = latest_video_frame_bytes

            # yield ('return') the frame: (yield: returns a value and saves the current
            # state of the generator function, the next time this generator function
            # is called, execution will resume on the next line of code in the function
            # (i.e., it will in this example start a new cycle of the while loop
            # and yield a new frame))
            #
            # what we yield looks like this, but in binary (binary data is a
            # must for multipart):
            # --frame
            # Content-Type: image/jpeg
            # Content-length: <length frame>
            #
            # <frame data>
            #
            yield (b'--frame\nContent-Type: image/jpeg\nContent-length: ' +
                        str(len(frame)) + '\n\n' + frame + b'\n')

            # delay for 0.066 sec (for ~ 15 Hz loop frequency, we don't get new
            # frames from the camera more frequent than this):
            time.sleep(0.0666)

@app.route("/camera_normal")
def camera_normal():
    # returns a Respone object with a 'gen_normal()' generator function as its data
    # generating iterator. We send a MIME multipart message of subtype Mixed-replace,
    # which means that the browser will read data parts (generated by gen_obj_normal)
    # one by one and immediately replace the previous one and display it. We never
    # close the connection to the client, pretending like we haven't finished sending
    # all the data, and constantly keeps sending new data parts generated by gen_obj_normal.
    #
    # what over time will be sent to the client is the following:
    # Content-Type: multipart/x-mixed-replace; boundary=frame
    #
    # --frame
    # Content-Type: image/jpeg
    #
    #<jpg data>
    #
    # --frame
    # Content-Type: image/jpeg
    #
    #<jpg data>
    #
    # etc, etc
    # where each '--frame' enclosed section represents a jpg image taken from
    # the camera that the browser will read and display one by one, replacing
    # the previous one, thus generating a video stream
    gen_obj_normal = gen_normal()
    return Response(gen_obj_normal, mimetype = "multipart/x-mixed-replace; boundary=frame")

@app.route("/")
def index():
    try:
        return render_template("index.html")
    except Exception as e:
        return render_template("500.html", error = str(e))

@app.errorhandler(404)
def page_not_found(e):
    try:
        return render_template("404.html")
    except Exception as e:
        return render_template("500.html", error = str(e))

if __name__ == '__main__':
    # start a thread constantly reading frames from the camera:
    thread_video = Thread(target = video_thread)
    thread_video.start()

    # start the web app:
    socketio.run(app, "172.24.1.1")
