#!/usr/bin/env python3

#REMARKS ========================
#        ... cv2.V4L2 is used to avoid stuck while cap.read()

# to override print <= can be a big problem with exceptions
from __future__ import print_function # must be 1st
import builtins

import sys

from fire import Fire

from flashcam.version import __version__

from flashcam import config
from flashcam import usbcheck
from flashcam import direct

from flashcam import v4lc
from flashcam.v4lc import set_gem

from flashcam import web

import json

import webbrowser
import multiprocessing
import time
import psutil
###from flashcam.real_camera import Camera
#from flask_script import Manager, Server
import subprocess as sp
import atexit

import flashcam.config as config

import flashcam.uniwrec as uniwrec

class Bcolors:
    HEADER = '[95m'
    OKBLUE = '[94m'
    OKGREEN = '[92m'
    WARNING = '[93m'
    FAIL = '[91m'
    ENDC = '[0m'
    BOLD = '[1m'
    UNDERLINE = '[4m'



def exit_handler():

    ok=False
    kill_gunicorn()

def GUNI():
    CMD="gunicorn -w 1 -b 0.0.0.0:8000 -k gevent --timeout 15 web:app"
    CMD="gunicorn --threads 5  -w 1 -b 0.0.0.0:8000  --timeout 15 web:app"
    print(CMD)
    proc = sp.Popen(CMD.split(), shell=False)
    print(CMD)
    proc.wait()
    proc.kill()
    return proc.pid

def API():
   print('i... In API n',config.CONFIG['port'])
   web.app.run(host='0.0.0.0', port=config.CONFIG['port'], threaded=True)


def kill(proc_pid):
    print(f"kiilling  {proc_pid}")
    process = psutil.Process(proc_pid)
    for proc in process.children(recursive=True):
        proc.kill()
    process.kill()

def kill_gunicorn():
    CMD = f"killall -9 gunicorn"
    print("X... KIILLING", CMD)
    sp.Popen(CMD, shell = True )



def initiate_port( port ):
    config.load_config()
    CMD = f'wget --user  {config.CONFIG["user"]} --password {config.CONFIG["password"]} http://localhost:{port}/video -O /dev/null '
    print("\n\n\ni... ",CMD,"\n\n\n")
    #return
    proc = sp.Popen(CMD, shell=True)
    try:
        proc.wait(timeout=4)
    except sp.TimeoutExpired:
        print("D... wget timeout expired")
    try:
        kill(proc.pid)
    except:
        print("X...  killing wget failed")
        ##    Camera = Camera # creating the OBJECT








def main(cmd = "usage", product="", res="640x480",
         frame_kind = "direct",
         threshold = 0,
         average = 0,
         blur = 0,
         laps = -1,
         web5000 = False,

         expo = -1,
         gain = -1,
         mmaga = -1,
         histogram = False,

         save = False,  # this is for UNI - save avi
         qpassfile = "~/.pycamfw_userpass",
         otate = False,   # this is for UNI, but also for CONFIG, also for show

         #--astro
         x = 0,
         y = 0,

         debug=False):
    ''' Main function of the project
-d debug

-c  command
-p  product/pathID
-r  resolution

-f  frame_kind  target_frame
-a  average  averaging
-b blur
-t threshold
-l laps
-w web5000 ... view flask

-e  expo ( in v4l )
-g  gain
-m  gamma
-h  histogram (show mean in image)

-s ....  for UNI AVI
-q .... passfile for UNI

-x
-y ... speed of translation for astrophotography

-o rOtate

-d

i j k n  p u v z
    '''

    #problematic - i cannot SAVE directly, it rewrites the changes
    #if  not("debug" in config.CONFIG):
    #config.CONFIG['debug'] = debug
    #config.save_config()

    #======================= I copy this to web.py so that gunicorn runs ok
    if not debug:
        print("X... NO DEBUG colors in main")
        _print = print # keep a local copy of the original print
        builtins.print =lambda *args, **kwargs:  None  if (isinstance(args[0], str)) and (args[0].find("D...")==0) else  _print( *args, **kwargs) if ('file' in kwargs) else _print( "{}".format(Bcolors.FAIL   if ((isinstance(args[0], str)) and (args[0].find("X...")>=0)) else Bcolors.ENDC) , *args, Bcolors.ENDC, **kwargs, file=sys.stderr)
    else:
        print("X... DEBUG COLORS FROM MAIN")
        # debug - show all + colors
        _print = print # keep a local copy of the original print
        builtins.print =lambda *args, **kwargs:   _print( *args, **kwargs) if ('file' in kwargs) else _print( "{}".format(Bcolors.FAIL   if ((isinstance(args[0], str)) and (args[0].find("X...")>=0)) else Bcolors.OKGREEN if  ((isinstance(args[0], str)) and (args[0].find("i...")>=0)) else Bcolors.ENDC  ), *args, Bcolors.ENDC, **kwargs, file=sys.stderr)

    #======== DEFINE THE CONFIG FILE HERE ========
    #========   NONONONO   NO              ======
    #======== in this case, all config handling must be win web.py
    #------- as it is the second ENTRY point
    #-------- and the only for gunicorn -----------------



    all_commands = ["usage","savecfg","flask5000", "flask", "show", "ls" , "getres" , "v4l", "uni"]
    if not (cmd in all_commands):
        print("X... command not found!",  all_commands)
        sys.exit(1)
    #if frame_kind == "histo":
    #    histogram = True



    if cmd == "usage":
        print(''' ... usage:
    flashcam ls
    flashcam getres [product | IDpath ]        # flashcam getres "Webcam C270"
    flashcam show ... show
    flashcam show  "Webcam C270"  -r 320x176

    flashcam flask & # (just a hint for gunicorn+wget)
    flashcam flask5000 [-w]   #  view on port 5000, immediatelly start browser tab

    flashcam savecfg [-a 11 ...]  # save cmdline parameters to congig for flask/gunicorn

..... advanced usage .... (accumulation, blur, threshold, frame_kind)
    flashcam show -a 19 -b 3 -t 100 -f [direct|delta|detect|histo]  [-h]  [-l 3600]

....  v4l setting .......... (exposure, gain  for automatically recommended video)
    flashcam v4l -e [auto | 0.0..1.0]  -g [0.0..1.0]

...... uninteruptable stream .....................
    flashcam uni http://192.168.0.91:8000/video  [-s ] # to save avi
        ''')
        sys.exit(0)

    elif cmd == "uni":
        uniwrec.display2( product, save = save, passfile = qpassfile, rotate = otate)
        sys.exit(0)


    elif cmd == "v4l":

        recomvid = usbcheck.recommend_video( product )

        cc = v4lc.V4L2_CTL("/dev/video"+str(recomvid[0]))
        v4lc.get_resolutions( recomvid[0]  )
        #print(cc._list_controls())


        set_gem(cc, gain, expo, mmaga)
        sys.exit(0)

    elif cmd == "ls":
        usbcheck.recommend_video()


    elif cmd == "savecfg":   # i dont have it loaded ....
        print( "i... USER  bin_fla:", config.CONFIG['user'] )
        config.CONFIG['target_frame'] = frame_kind
        config.CONFIG['threshold'] = threshold
        config.CONFIG['timelaps'] = laps
        config.CONFIG['average'] = average
        config.CONFIG['blur'] = blur
        config.CONFIG['histogram'] = histogram
        config.CONFIG['x'] = x
        config.CONFIG['y'] = y

        config.CONFIG['rotate180'] = otate

        config.CONFIG['expo'] = expo
        config.CONFIG['gamma'] = mmaga
        config.CONFIG['gain'] = gain

        config.save_config()

    elif cmd == "show2":
        recomvid = usbcheck.recommend_video( product )
        # usbcheck.show_cam( recomvid[0], res, recommended= product)

    # --------------------------------------------------
    elif cmd == "show":
        recomvid = usbcheck.recommend_video( product )
        # how recomvid goes there?
        config.CONFIG["recommended"] = product  # hopefully this

        if (threshold>0) and (blur==0) and (average<2):
            print("X... cannot be -thr>0 and average==0")
            sys.exit(1)

        config.CONFIG['timelaps'] = laps
        config.CONFIG['target_frame'] = frame_kind
        config.CONFIG['threshold'] = threshold
        config.CONFIG['average'] = average
        config.CONFIG['blur'] = blur
        config.CONFIG['histogram'] = histogram
        config.CONFIG['resolution'] = res
        config.CONFIG['x'] = x
        config.CONFIG['y'] = y
        config.CONFIG['rotate180'] = otate

        config.CONFIG['expo'] = expo
        config.CONFIG['gain'] = gain
        config.CONFIG['gamma'] = mmaga

        # set_gem(cc, gain, expo, mmaga)


        direct.show_cam( )

    # ------------------------------------------------------------------------------
    elif cmd == "getres":
        recomvid = usbcheck.recommend_video( product )
        resolutions = usbcheck.get_resolutions( recomvid[0] )
    # ------------------------------------------------------------------------------
    elif cmd == "flask":
        print("i... NOT STARTING flask NOT STARTING GUNICORN")

        CMD="gunicorn --threads 5  -w 1 -b 0.0.0.0:8000  --timeout 15 web:app"
        print(CMD)
        print(CMD)
        print(CMD)
        print("i... now i try to initiate port 8000 and quit")
        time.sleep(4)
        initiate_port(8000)
        sys.exit(0)


    # ------------------------------------------------------------------------------
    elif cmd == "flask5000":

        # [x] why I am saving ? because it is the way to tune real flask 8000?
        #     - i can only pass to real_cam by saving CONFIG !

        saveme = False
        print( "i... USER  bin_fla:", config.CONFIG['user'] )
        if config.CONFIG['target_frame'] != frame_kind:
            config.CONFIG['target_frame'] = frame_kind
            saveme = True
        if config.CONFIG['threshold']    != threshold:
            config.CONFIG['threshold']    = threshold
            saveme = True
        if config.CONFIG['average']      != average:
            config.CONFIG['average']      = average
            saveme = True
        if config.CONFIG['blur']         != blur:
            config.CONFIG['blur']         = blur
            saveme = True
        if config.CONFIG['timelaps']         != laps:
            config.CONFIG['timelaps']         = laps
            saveme = True
        if config.CONFIG['histogram']         != histogram:
            config.CONFIG['histogram']         = histogram
            saveme = True
        if config.CONFIG['resolution']         != res:
            config.CONFIG['resolution']         = res
            saveme = True
        if config.CONFIG['x']         != x:
            config.CONFIG['x']         = x
            saveme = True
        if config.CONFIG['y']         != y:
            config.CONFIG['y']         = y
            saveme = True

        if config.CONFIG['rotate180']         != otate:
            config.CONFIG['rotate180'] = otate
            saveme = True

        if product != "":
            config.CONFIG['recommended'] = product
            saveme = True

        # config.CONFIG[''] =

        if saveme:
            config.save_config()

        print("i... flask starting on port 5000 - with autosaving POWER")
        p = multiprocessing.Process(target=API)
        p.start()
        if web5000:
            webbrowser.open('http://localhost:5000')
        else:
            time.sleep(3)
            initiate_port(5000)


    else:
        print("X... NO COMMAND GIVEN, ENDING")
        unitname.func()


if __name__=="__main__":
    Fire(main)
