package.path = package.path.. ';.\\Scripts\\?.lua;.\\LuaSocket\\?.lua;'
package.cpath = package.cpath.. ';.\\Scripts\\?.lua;.\\LuaSocket\\?.dll;'
-- package.path  = package.path..";.\\LuaSocket\\?.lua"
-- package.cpath = package.cpath..";.\\LuaSocket\\?.dll"


-- ================================
-- 	Prepare the LEAVU network listener
-- ================================

-- Set of network clients talking to the LEAVU export
clients = {};
dofile(require('lfs').writedir()..'Scripts/netClient.lua')

-- Grab the settings for the listener
dofile(require('lfs').writedir()..'Scripts/netSec.lua');

-- Verify settings exist, else revert to default
listener_port = listener_port or 8079;
listener_password = listener_password or "";
password_required = listener_password~=""
listener_device = listener_device or 'localhost';

--open a socket
inc_socket=require("socket");
listener=inc_socket.bind(listener_device,listener_port);
listener:settimeout(0.0);

-- Time to remember when last time the handle connections function was run
g_last_time_handled_connections = 0.0;
g_last_time_added_removed_clients = 0.0;
g_netUpdateDt = 0.01; -- set to around 0.01 for LAN/local, or 0.1 for over internet


-- ================================================================
-- 	Handles IO from current connections and cleans up old/opens new
-- 	This function is called each frame by LuaExportAfterNextFrame()
-- ================================================================

function handle_connections()

	if g_MeObject and g_time-g_last_time_handled_connections>g_netUpdateDt then
		g_last_time_handled_connections = g_time;

		-- 1. Close old intactive and open new pending
		if ( g_time - g_last_time_added_removed_clients > 0.5 ) then

			g_last_time_added_removed_clients = g_time;

			for i=#clients,1,-1 do
				if not clients[i]:isConnected() then
					clients[i]:destructor();
					table.remove(clients,i);
				end
			end

			local inc_client = listener:accept();
			while inc_client do
				clients[#clients+1] = netClient(inc_client);
				inc_client = listener:accept();
			end

		end

		-- 3. Do IO
		if #clients>0 then
			local data_to_transmit = buildData(); 	-- Creates a data table 'data' to transmit
			local data_received = {}; 	-- Table to store incoming instructions/data in
			for i=1,#clients do
	
				-- Send info (which also maintains current connections)
				clients[i]:transmit(data_to_transmit);
	
				-- Receive info from each client, and store it line by line in table 'data_received'
				local curdata = clients[i]:receive();
				for e=1,#curdata do
					data_received[#data_received+1] = curdata[e];
				end
	
			end
	
			-- 4. Process the received data and (possibly) input commands to lockon
			lockon_input(data_received);
		end

	end
end

-- Puts new information into lockon
function lockon_input(data) -- Not Yet implemented
end


-- No longer looks up wave files. This is done in separate software. This function now simply formats a string for transmission
function signal_format(v1,v2,v3,v4)
	return string.format("%s%s%s%s%s%s%s%s", v1,",",v2,",",v3,",",v4,"\n");
end

function getTargetPriority(ID)
	if g_dTargets then
		for i=1,#g_dTargets do
			if g_dTargets[i]==ID then
				return i;
			end
		end
	end
	return -1;
end

-- Builds the data table for transmission
function buildData()

	local data={};
	data[1+#data] = "!!dnr4jh54jgf94j48!!"; -- begin message

	-- 1. Get the RWR data
	if g_rwrData then
		data[1+#data]="RWR_contacts\n";
		data[1+#data]=string.format("%s%s",#g_rwrData.Emitters,"\n");
		for i,cur in pairs(g_rwrData.Emitters) do
			-- Transmit basic data on the threat
			data[1+#data]=string.format("%s%s%s%s%s%s%s%g%s%s%s",
								cur.ID,"\n",
								signal_format(cur.Type.level1,cur.Type.level2,cur.Type.level3,cur.Type.level4),
								cur.Power,"\n",
								cur.Azimuth,"\n",
								cur.Priority,"\n",
								cur.SignalType,"\n");
		end
	end

	-- 2. HSD -- get my heading
	if g_MeObject then
		data[1+#data]=string.format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
							"Me_data\n",
							g_MeObject.Heading,"\n",
							g_MeObject.LatLongAlt.Lat,"\n",
							g_MeObject.LatLongAlt.Long,"\n",
							g_MeObject.LatLongAlt.Alt,"\n",
							g_MeObject.CoalitionID,"\n",
							g_MeObject.ID,"\n",
							g_acVectors.PITCH,"\n",
							g_acVectors.BANK,"\n",
							g_acVectors.YAW,"\n",
							g_acVectors.TAS,"\n",
							g_acVectors.GSP,"\n",
							g_acVectors.CAS,"\n",
							signal_format(g_MeObject.Type.level1,g_MeObject.Type.level2,g_MeObject.Type.level3,g_MeObject.Type.level4));
	end

	--, Get Waypoints/route data
	if g_route and g_route.route then
		data[1+#data]="WP_data\n";
		data[1+#data]=string.format("%s%s",g_route.goto_point.this_point_num,"\n");  --//index, cur wp
		data[1+#data]=string.format("%s%s",#g_route.route,"\n");  --//Amount of waypoints
		for num,wpt in pairs(g_route.route) do
			local LatLong = LoLoCoordinatesToGeoCoordinates(wpt.world_point.x,wpt.world_point.z);
			data[1+#data]=string.format("%s%s",LatLong.latitude,"\n");  --//coord
			data[1+#data]=string.format("%s%s",LatLong.longitude,"\n");  --//coord
			data[1+#data]=string.format("%s%s",wpt.point_action,"\n");  --//wp type
		end
	end

	-- 3. SMS, Payload data
	if g_stations then
	
		data[1+#data]=string.format("%s%s","Payload_data","\n");
		if g_stations.Stations then
			local entries = #g_stations.Stations + 4;
			data[1+#data]=string.format("%s%s",entries,"\n");
			for i_st,st in pairs (g_stations.Stations) do
				if (st.count and st.count>0) then data[1+#data]=string.format("%s%s%s%s%s%s%s%s", st.weapon.level1,",",st.weapon.level2,",",st.weapon.level3,",",st.weapon.level4,"\n");
				else data[1+#data]=string.format("%s%s","","\n");  end
			end
		else
			data[1+#data]=string.format("%s%s","0","\n");
		end
		data[1+#data]=string.format("%s%s",g_stations.CurrentStation,"\n");
		
		local cf = LoGetSnares() or { chaff=120, flare=60 }; -- DCS supports exporting cannon shells and chaff/flare count!!!, shells, chaff, flare
		data[1+#data] = string.format("%s%s",g_stations.Cannon.shells,"\n");
		data[1+#data] = string.format("%s%s",cf.chaff,"\n");
		data[1+#data] = string.format("%s%s",cf.flare,"\n");
	end

	-- 4. Navigation mode and transmit Targeting data
	if g_acMode then

		data[1+#data] = "Nav_data\n";
		data[1+#data] = string.format("%s%s",g_acMode.SystemMode.master,"\n");
		data[1+#data] = string.format("%s%s",g_acMode.SystemMode.submode,"\n");
		data[1+#data] = "Target_data\n";

		if g_memTargets then
			for i=1,#g_memTargets do

				local target = getObjectById(g_memTargets[i].target.ID);
				
				if not g_memTargets[i].target.jammer_burned then
					target.CoalitionID = -1;
				end
				
				if target then
				
				data[1+#data] = string.format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
									getHeadingFromV( g_memTargets[i].target.velocity ),"\n",
									target.LatLongAlt.Lat,"\n",
									target.LatLongAlt.Long,"\n",
									target.LatLongAlt.Alt,"\n",
									target.CoalitionID,"\n",
									target.ID,"\n",
									target.Type.level1,"\n",
									target.Type.level2,"\n",
									target.Type.level3,"\n",
									target.Type.level4,"\n",
									g_memTargets[i].target.jammer_burned and ((target.Coalition==g_myCoalition and "F\n") or "E\n") or "J\n", -- ECM status
									lockNotSearch(g_memTargets[i].target.flags) and "1\n" or "0\n", 		-- Is it a lock or search contact?	
									g_memTargets[i].usingMem and "0\n" or "1\n", 					-- Is it memorized data being transmitted or something actually scanned this frame?				
									getTargetPriority(target.ID),"\n", 							-- target priority number
									g_time-g_memTargets[i].target.scanTime,"\n", 					-- time since this contact was scanned
									g_memTargets[i].target.hasHeading and 1.0 or -1.0,"\n", 			-- closure
									g_memTargets[i].target.velocity.x,"\n", 						-- target velocity vector
									g_memTargets[i].target.velocity.y,"\n",
									g_memTargets[i].target.velocity.z,"\n",
									g_memTargets[i].target.convergence_velocity,"\n"); 				-- closure

				end
			end
		end

		data[1+#data]="End_targets\n";
	end


	-- 5. Transmit radar and ECM settings
	if g_radarData then
		data[1+#data] = string.format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
							"Radar_data\n",
							g_radarData.PRF.current,"\n",
							g_radarData.ScanZone.position.azimuth,"\n",
							g_radarData.ScanZone.position.elevation,"\n",
							g_radarData.ScanZone.size.azimuth,"\n",
							g_radarData.ScanZone.size.elevation,"\n",
							g_radarData.scale.distance,"\n",
							g_radarData.scale.azimuth,"\n",
							g_radarData.TDC.x,"\n",
							g_radarData.TDC.y,"\n",
							g_radarData.radar_on and 1.0 or -1.0,"\n",
							g_radarData.ECM_on and 1.0 or -1.0,"\n",
							g_radarData.ScanZone.coverage_H.min,"\n",
							g_radarData.ScanZone.coverage_H.max,"\n");
	end
	
	data[1+#data] = "!!sh3jhfij4sn273j7d!!"; -- end message

	return table.concat(data)

end


-- ================================
-- 	Main LEAVU loop
-- ================================

if LuaExportBeforeNextFrame then
	local origLuaExportBeforeNextFrame = LuaExportBeforeNextFrame;
	function LuaExportBeforeNextFrame()
		origLuaExportBeforeNextFrame();
		handle_connections();
	end
else
	function LuaExportBeforeNextFrame()
		handle_connections();
	end
end


-- ================================
-- 	Shutting down
-- ================================

local origLuaExportStop = LuaExportStop;
function LuaExportStop()

	-- Make compatible with other script files
	if origLuaExportStop then
		origLuaExportStop();
	end

	-- Close all incoming network connections for LEAVU
	for i=1,#clients do
		clients[i]:destructor();
	end

end
