import socket
import struct
import math
from time import sleep
import argparse

global option

global CAMERA_MODEL
global SOCKET_OPT
global MCAST_GRP
global PORT
global ENDPNT_ADDR
global FPS

CAMERA_MODEL = 1
SOCKET_OPT = 2
MCAST_GRP = '239.192.1.1'
PORT = 5432
ENDPNT_ADDR = '127.0.0.1'
FPS = 24

def parseArgs():
	parser = argparse.ArgumentParser(description='Metadata Emulator Configuration Settings')

	parser.add_argument('--default', action='store_true', help='Keep the default configuration settings and start sending data')
	parser.add_argument('--camera_model', type=int, help='Set UMC4 (1) or ALEXA35 (2) (Default is UMC4)')
	parser.add_argument('--socket_type', type=int, help='Set Unicast (1) or Multicast (2) (Default is Multicast)')
	parser.add_argument('--multicast_addr', type=str, help='Set Multicast Address (Default is 239.192.1.1)')
	parser.add_argument('--port', type=int, help='Set Port (Default is 5432)')
	parser.add_argument('--endpoint_addr', type=str, help='Set Endpoint Address (Default is 127.0.0.1)')
	parser.add_argument('--fps', type=int, help='Set FPS (Default is 24)')

	args = parser.parse_args()

	print(args)

	if check_all_none_or_false(args):
		menu()
	elif (args.default):
		sendData()
	else:
		if(args.camera_model != None):
			global CAMERA_MODEL
			CAMERA_MODEL = args.camera_model

		if(args.socket_type != None):
			global SOCKET_OPT
			SOCKET_OPT = args.socket_type

		if(args.multicast_addr != None):
			global MCAST_GRP
			MCAST_GRP = args.multicast_addr

		if(args.port != None):
			global PORT
			PORT = args.port

		if(args.endpoint_addr != None):
			global ENDPNT_ADDR
			ENDPNT_ADDR = args.endpoint_addr

		if(args.fps != None):
			global FPS
			FPS = args.fps

		print()
		print("###################################")

		if CAMERA_MODEL == 1:
			print("Camera Model: UMC4")
		elif CAMERA_MODEL == 2:
			print("Camera Model: ALEXA 35")

		if SOCKET_OPT == 1:
			print("Socket Type: Unicast")
		elif SOCKET_OPT == 2:
			print("Socket Type: Multicast")
		print("Multicast Address: ", MCAST_GRP)
		print("Endpoint Address: ", ENDPNT_ADDR)
		print("Port: ", PORT)
		print("FPS: ", FPS)
		print("###################################")
		print()

		sendData()

def check_all_none_or_false(args):
    return all(arg is None or arg is False for arg in vars(args).values())



def menu():
	print("###################################")
	print()
	print("[1] UMC4 (1) or ALEXA35 (2)? (Default is UMC4)")
	print("[2] Unicast (1) or Multicast (2)? (Default is Multicast)")
	print("[3] Set Mutlicast Address (Default is 239.192.1.1)")
	print("[4] Set Port (Default is 5432)")
	print("[5] Set endpoint Address (Default is 127.0.0.1)")
	print("[6] Set FPS (Default is 24)")
	print("[7] Print all current Settings")
	print("[8] Send Metadata (CTRL + C to end)")
	print("[0] EXIT")
	print()
	print("###################################")

	global option
	option = int(input("What would you like to do?: "))

	while option !=0:
		if option == 1:
			setCameraModel()
		elif option == 2:
			setSocketType()
		elif option == 3:
			setMulticast()
		elif option == 4:
			setPort()
		elif option == 5:
			setEndpointAddress()
		elif option == 6:
			setFPS()
		elif option == 7:
			printSettings()
		elif option == 8:
			sendData()
		else:
			print("invalid option")


def sendData():

	if CAMERA_MODEL == 1:
		jsonMessagePt1 = '{"camera":{"state":{"health":"good","majorState":"IDLE"},"device":{"model":"UMC-4","umc4SerialNumber":"K2.0000642-7201","umc4SoftwareVersion":"2.3","cameraSerialNumber":"33454","cameraSoftwarePackageName":"7.1.0","cameraSoftwarePackageVersion":"7.1.0"},"optic":{"converter":{"converterFocalLenMultiplier":0,"converterLightLossFactor":0,"converterModel":"","converterPhysicalLength":0,"converterSerialNumber":""},"filter":{"ndFilterDensity":0},"lens":{"lensDevice":{"lensModel":"Fujinon Alura AZ15.5-45 T2.8","lensSerialNumber":"23359","lensMotorRawEncoderLimitsFocus":{"min":-1,"max":-1},"lensMotorRawEncoderLimitsIris":{"min":-1,"max":-1},"lensMotorRawEncoderLimitsFL":{"min":-1,"max":-1}},"lensState":{"lensFocusDistanceImperial":680272,"lensFocusDistanceMetric":'
		jsonMessagePt2 = ',"lensIris":'
		jsonMessagePt3 = ',"lensFocalLength":'
		jsonMessagePt4 = ',"lensScaleRawEncoderValueFocus":805,"lensScaleRawEncoderValueIris":3123,"lensScaleRawEncoderValueFL":1174,"lensMotorRawEncoderValueFocus":-1,"lensMotorRawEncoderValueIris":-1,"lensMotorRawEncoderValueFL":-1}}},"sensor":{"sensorState":{"shutterAngle":5.36954e+06,"exposureTime":"1000/60000","exposureIndex":800,"sensorSampleRate":"30000/1000"}},"recording":{"medium":{"remainingCapacity":0},"projectRate":{"timebase":"'
		jsonMessagePt5 = '/1000","dropframe":false},"acquisitionTimestamp":'
		jsonMessagePt6 = ',"clip": {"slateInfo":{"cameraIndex":"A"}}},"processing":{"whiteBalance":{"colorTemperature":6500,"whiteBalanceTint":0}},"positional":{"orientation":{"tilt":0.2,"roll":-41.2}}}}'

	elif CAMERA_MODEL == 2:
		jsonMessagePt1 = '{"camera": {"device": {"cameraModel": "ALEXA 35", "cameraSerialNumber": "50107", "cameraSoftwarePackageName": "1.2.0", "cameraSoftwarePackageVersion": "1.2.0", "cameraVariant": "ALEXA35"}, "optic": {"filter": {"ndFilterDensity": 0.60000000000000000}, "lens": {"lensDevice": {"circleOfConfusion": 0.02500000037252903, "lensLimitsFocusImperial": {"max": -1, "min": 27559}, "lensLimitsFocusMetric": {"max": -1, "min": 700}, "lensLimitsIris": {"max": 10000, "min": 4000}, "lensLimitsZoom": {"max": 75000, "min": 24000}, "lensModel": "ARRI SZ24-75 T2.8", "lensMotorRawEncoderLimitsFL": {"max": 6870, "min": 105}, "lensMotorRawEncoderLimitsFocus": {"max": 21214, "min": 105}, "lensMotorRawEncoderLimitsIris": {"max": 3126, "min": 105}, "lensScaleRawEncoderLimitsFL": {"max": 8557, "min": 16}, "lensScaleRawEncoderLimitsFocus": {"max": 13333, "min": 8}, "lensScaleRawEncoderLimitsIris": {"max": 4108, "min": 16}, "lensScaleRawEncoderSource": "LDS", "lensSerialNumber": "161409", "lensSqueezeFactor": "100/100"}, "lensState": {"lensEffectiveFocalLength": 24340, "lensEntrancePupilOffset": 239099, "lensFocalLength": '
		jsonMessagePt2 = ' , "lensFocusDistanceImperial": 123976, "lensFocusDistanceMetric": '
		jsonMessagePt3 = ' , "lensIris": '
		jsonMessagePt4 = ' , "lensMotorRawEncoderValueFL": 6870, "lensMotorRawEncoderValueFocus": 18020, "lensMotorRawEncoderValueIris": 1639, "lensScaleRawEncoderValueFL": 8554, "lensScaleRawEncoderValueFocus": 2014, "lensScaleRawEncoderValueIris": 2021}}}, "positional": {"orientation": {"roll": -3.500000000, "tilt": -0.40000000596046448}}, "processing": {"whiteBalance": {"colorTemperature": 5600, "whiteBalanceTint": 0.00000000000000000}}, "recording": {"acquisitionTimestamp": '
		jsonMessagePt5 = ' , "clip": {"slateInfo": {"cameraIndex": "A_", "clipName": "A_0004C000_220621_153335_p12LV.mxf", "clipNumber": 0}}, "medium": {"mediumCapacity": 960000}, "projectRate": {"dropframe": false, "timebase": "'
		jsonMessagePt6 ='/1000"}}, "sensor": {"sensorState": {"averagedFrames": 1, "exposureIndex": 800, "exposureTime": "1000/50000", "sensorSampleRate": "24000/1000"}}, "state": {"health": "warning", "majorState": "STANDBY"}}}'





	INDEX = 1
	CameraIndex = 'A'
	LensName = 'MetadataEncoder'
	LensDistanceUnit = "Meter"
	FocusDistance = 200
	LensFocalLength = 25000
	LensIris = " T2  + 2/10"
	LensLinearIris = 5000
	RawEncoderFocus = 0
	RawEncoderFocal = 0
	RawEncoderIris = 0
	EncoderLimFocusMotorMin = 0
	EncoderLimFocusMotorMax  = 0
	EncoderLimFocalMotorMin = 0
	EncoderLimFocalMotorMax = 0
	EncoderLimIrisMotorMin = 0
	EncoderLimIrisMotorMax = 0
	Tilt = -0.7
	Roll = 0.5
	TAB = "\t"
	NEWLINE = "\n"
	Aq_Timestamp = 0

	if SOCKET_OPT == 2:

		sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
		sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
		sock.connect((ENDPNT_ADDR, PORT))

		x = 1
		y = 1
		while True:

			if x<250:
				LensLinearIris += x/10
				FocusDistance += x/10
				LensFocalLength += x
				Aq_Timestamp += 1


				if CAMERA_MODEL == 1:
					message = jsonMessagePt1 + str(FocusDistance) + jsonMessagePt2 + str(LensLinearIris) + jsonMessagePt3 + str(LensFocalLength) + jsonMessagePt4 + str(FPS*1000) + jsonMessagePt5 + str(Aq_Timestamp) + jsonMessagePt6;
				elif CAMERA_MODEL == 2:
					message = jsonMessagePt1 + str(LensFocalLength) + jsonMessagePt2 + str(FocusDistance) + jsonMessagePt3 + str(LensLinearIris) + jsonMessagePt4 + str(Aq_Timestamp) + jsonMessagePt5 + str(FPS*1000) + jsonMessagePt6;
				
				byt = message.encode()

				sock.sendto(byt, (MCAST_GRP, PORT))
				#print(LensLinearIris)
				#print(LensFocalLength)
				sleep(1.0/FPS)

			else:
				x = 1
				LensLinearIris = 5000
				FocusDistance = 200
				LensFocalLength = 25000

			x+=1
			y+=1

	elif SOCKET_OPT == 1:

		sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

		x = 1
		y = 1
		while True:

			if x<250:
				LensLinearIris += x/10
				FocusDistance += x/100
				LensFocalLength += x/1000
				Aq_Timestamp += 1

				if CAMERA_MODEL == 1:
					message = jsonMessagePt1 + str(FocusDistance) + jsonMessagePt2 + str(LensLinearIris) + jsonMessagePt3 + str(LensFocalLength) + jsonMessagePt4 + str(FPS*1000) + jsonMessagePt5 + str(Aq_Timestamp) + jsonMessagePt6;
				elif CAMERA_MODEL == 2:
					message = jsonMessagePt1 + str(LensFocalLength) + jsonMessagePt2 + str(FocusDistance) + jsonMessagePt3 + str(LensLinearIris) + jsonMessagePt4 + str(Aq_Timestamp) + jsonMessagePt5 + str(FPS*1000) + jsonMessagePt6;
				
				byt = message.encode()

				sock.sendto(byt, (ENDPNT_ADDR, PORT))
				#print(LensLinearIris)
				#print(LensFocalLength)
				sleep(1.0/FPS)

			else:
				x = 1
				LensLinearIris = 5000
				FocusDistance = 20
				LensFocalLength = 25.0

			x+=1
			y+=1


def setCameraModel(): 
	print()
	print("###################################")
	global CAMERA_MODEL
	CAMERA_MODEL = int(input("Input 1 for UMC4 and 2 for ALEXA35: "))
	if CAMERA_MODEL == 1:
		print("Camera model set to UMC4")
		print("###################################")
		print()
		menu()
	elif CAMERA_MODEL == 2:
		print("Camera model set to ALEXA35")
		print("###################################")
		print()
		menu()
	else:
		print("invalid option")
		menu()


def setSocketType():
	print()
	print("###################################")
	global SOCKET_OPT
	SOCKET_OPT = int(input("Input 1 for Unicast and 2 for Multicast: "))
	if SOCKET_OPT == 1:
		print("Socket set to Unicast")
		print("###################################")
		print()
		menu()
	elif SOCKET_OPT == 2:
		print("Socket set to Multicast")
		print("###################################")
		print()
		menu()
	else:
		print("invalid option")
		menu()


def setMulticast():
	print()
	print("###################################")
	global MCAST_GRP 
	MCAST_GRP = str(input("Input Multicast Address: "))
	print("Multicast Address set to: ", MCAST_GRP)
	print("###################################")
	print()
	menu()

def setFPS():
	print()
	print("###################################")
	global FPS
	FPS = int(input("Input FPS: "))
	print("FPS set to: ", FPS)
	print("###################################")
	print()
	menu()

def setEndpointAddress():
	print()
	print("###################################")
	global ENDPNT_ADDR
	ENDPNT_ADDR = str(input("Input Endpoint Address: "))
	print("Endpoint Address set to: ", ENDPNT_ADDR)
	print("###################################")
	print()
	menu()

def setPort():
	print()
	print("###################################")
	global PORT
	PORT = int(input("Input Port: "))
	print("Port set to: ", PORT)
	print("###################################")
	print()
	menu()

def printSettings():
	print()
	print("###################################")
	print("Multicast Address: ", MCAST_GRP)
	print("Endpoint Address: ", ENDPNT_ADDR)
	print("Port: ", PORT)
	print("FPS: ", FPS)
	print("###################################")
	print()
	menu()

parseArgs()
#menu()