import base64
import socket
import threading
import time
import numpy as np
import cv2
from io import BytesIO
import argparse
import gevent
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
from flask_restful import Api , Resource 
from flask import Flask , request
from flask_sockets import Sockets
from flask_cors import CORS
import json
from threading import Thread
import threading
import numpy as np
import argparse
import cv2 as cv
import subprocess
import time
import os
from yolo_utils import infer_image, show_image
from PIL import Image
from datetime import date
import os
import sys
import random

FLAGS = []
import random
app = Flask(__name__)
sockets = Sockets(app)
cors = CORS(app, resources={r"/*": {"origins": "*"}})

#path='C:/Users/setze/Desktop/Ecole/master/iot/GazeTracking-master/page/preuve/voices'
path = os.path.join(os.getcwd(), 'preuve/images')


def counter(list,element):
	j=0
	for i in list:
		if(i==element):
			j+=1
	return j


class Streamera:

	def __init__(self):

		self.clientConnected = False
		self.frame = None


	def display_image(self, bytes,count,flag):
		self.frame = cv2.imdecode(np.frombuffer(bytes, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
		frame = self.frame
		height, width = frame.shape[:2]

		if count == 0:
			frame, boxes, confidences, classids, idxs = infer_image(net, layer_names, \
		   						height, width, frame, colors, labels, FLAGS)
			count += 1
		else:
			frame, boxes, confidences, classids, idxs = infer_image(net, layer_names, \
		   						height, width, frame, colors, labels, FLAGS, boxes, confidences, classids, idxs, infer=False)
			count = (count + 1) % 6
		cv2.namedWindow('streamera',cv2.WINDOW_NORMAL)
		cv.imshow('streamera', frame)
		if(len(classids)!=0):
			print(labels[classids[0]])
			#if(0 in classids):
			if(67 in classids or 0 in classids or 63 in classids or 73 in classids or 62 in classids):
					print('FLAAAG')
					nom='preuve'+str(random.randint(0,1000))+'.jpg'
					Image.fromarray(frame, "RGB").save(path+'/' +nom, 'JPEG')
					flag=0
					#os.system("taskkill /im chrome.exe /f")
					#exit()
                    
		cv2.waitKey(1)


	def main(self, server, port):
		
		try:
			server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			server_socket.bind((server, port))
			print(f'[+] streamera server created at {server}:{port}')
		except:
			print(f'[!] Could not create streamera server at {server}:{port}')
			return -1

		server_socket.listen(5)

		cli_sock, ret = server_socket.accept()
		print(f"[+] CLIENT JOINED: {cli_sock}")

		SIZE = 1500
		str_buf = b''
		count = 0
		while True:
			
			try:
				cli_sock.sendall(b'asdf')
				msg = cli_sock.recv(SIZE)
				self.clientConnected = True
			except:
				print('[-] Client disconnected.\n[-] Terminating server.')
				break

			if(msg):
				str_buf += msg

				# if string contains ffd9 (it means end of image)
				pos = str_buf.find(b'\xff\xd9')
				if pos >= 0:
					flag=0
					Streamera.display_image(self, str_buf[:pos+2],count,flag)
					#self.frame = cv2.imdecode(np.frombuffer(str_buf[:pos+2], dtype=np.uint8), cv2.IMREAD_UNCHANGED)
					# replace str_buf with left over bytes
					str_buf = str_buf[pos+2:]
					if(flag==1):
						exit()
						#break
					    

		server_socket.close()
		self.clientConnected = False
		cv2.destroyAllWindows()
		
		#Streamera.main(self, server, port)
		

	def get_ip_address():
		s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		s.settimeout(0)
		
		try:
			# doesn't even have to be reachable
			s.connect(('10.254.254.254', 1))
			IP = s.getsockname()[0]
		except Exception:
			IP = None
		finally:
			s.close()
		return IP


@app.route('/getIpAddPort', methods = ["GET"])
def def_getIpAddPort():

	server = Streamera.get_ip_address()
	print("in getIpAddPort")
	global objStreamera

	data = {
            "server" : server,
			"port" : 5000
        }

	response = app.response_class(
        json.dumps(data),
        status=200,
        mimetype='application/json'
    )
	
	return response

@sockets.route('/clientConnected')
def def_clientConnected(ws):

	global objStreamera

	while True:
		clientConnected = objStreamera.clientConnected
		outFrame = objStreamera.frame
		if outFrame is not None:
			outFrame        = cv2.imencode('.jpg', outFrame)[1].tobytes()
			image_64_encode = base64.b64encode(outFrame)
			data            = json.dumps({'clientConnected': clientConnected, 'frame': image_64_encode.decode('ascii')})
			if ws.closed == False:
				ws.send(data)
		else:
			data            = json.dumps({'clientConnected': clientConnected})
			if ws.closed == False:
				ws.send(data)
		gevent.sleep(.05)
	return


if __name__ == "__main__":
	server = Streamera.get_ip_address()
	port = 5000

	objStreamera = Streamera()
	global wsServer

	thread = Thread(target = objStreamera.main, args=[server, port])
	thread.deamon = True
	thread.start()

	parser = argparse.ArgumentParser()

	parser.add_argument('-m', '--model-path',
		type=str,
		default='./yolov3-coco/',
		help='The directory where the model weights and \
			  configuration files are.')

	parser.add_argument('-w', '--weights',
		type=str,
		default='./yolov3-coco/yolov3.weights',
		help='Path to the file which contains the weights \
			 	for YOLOv3.')

	parser.add_argument('-cfg', '--config',
		type=str,
		default='./yolov3-coco/yolov3.cfg',
		help='Path to the configuration file for the YOLOv3 model.')

	parser.add_argument('-i', '--image-path',
		type=str,
		help='The path to the image file')

	parser.add_argument('-v', '--video-path',
		type=str,
		help='The path to the video file')


	parser.add_argument('-vo', '--video-output-path',
		type=str,
        default='./output.avi',
		help='The path of the output video file')

	parser.add_argument('-l', '--labels',
		type=str,
		default='./yolov3-coco/coco-labels',
		help='Path to the file having the \
					labels in a new-line seperated way.')

	parser.add_argument('-c', '--confidence',
		type=float,
		default=0.5,
		help='The model will reject boundaries which has a \
				probabiity less than the confidence value. \
				default: 0.5')

	parser.add_argument('-th', '--threshold',
		type=float,
		default=0.3,
		help='The threshold to use when applying the \
				Non-Max Suppresion')

	parser.add_argument('--download-model',
		type=bool,
		default=False,
		help='Set to True, if the model weights and configurations \
				are not present on your local machine.')

	parser.add_argument('-t', '--show-time',
		type=bool,
		default=False,
		help='Show the time taken to infer each image.')

	FLAGS, unparsed = parser.parse_known_args()


	# Get the labels
	labels = open(FLAGS.labels).read().strip().split('\n')

	# Intializing colors to represent each label uniquely
	colors = np.random.randint(0, 255, size=(len(labels), 3), dtype='uint8')

	# Load the weights and configutation to form the pretrained YOLOv3 model
	net = cv.dnn.readNetFromDarknet(FLAGS.config, FLAGS.weights)

	# Get the output layer names of the model
	layer_names = net.getLayerNames()
	layer_names = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]

	if FLAGS.image_path is None and FLAGS.video_path is None:
	    print ('Neither path to an image or path to video provided')
	    print ('Starting Inference on Webcam')

	print('<<-----[+] WEB SOCKET SERVER STARTED AT 127.0.0.1:8000----->>')
	wsServer = pywsgi.WSGIServer(('127.0.0.1',8000),app,handler_class = WebSocketHandler)
	wsServer.serve_forever()
	#objStreamera.display_image(20)