using System;
using System.Windows.Forms;
using System.Collections.Generic;
using LFS_External;
using LFS_External.InSim;
using System.Diagnostics;

namespace LFS_External_Client
{
	public partial class Form1 : Form 
	{
		// Main InSim object
		public static InSimInterface InSim;

		// InSim connection settings
		InSimSettings Settings = new InSimSettings("localhost", 29999, 0, Flags.InSimFlags.ISF_MSO_COLS | Flags.InSimFlags.ISF_MCI, '!', 500, "password", "^1Unnamed", 5);

		// These are the main lists that contain all Players and Connections (Being maintained automatically)
		public static List<clsConnection> Connections = new List<clsConnection>();
        public static List<clsPlayer> Players = new List<clsPlayer>();

		// Delegate for UI update (Example)
		delegate void dlgMSO(Packets.IS_MSO MSO);

		// Form constructor
		public Form1()
		{
			InitializeComponent();
			InSimConnect();	// Attempt to connect to InSim
		}

		// Always call .Close() on application exit
		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
            try
            {
                InSim.Close();
            }
            catch (Exception E)
            {
                misc.manageHandledException(E);
            }
            finally
            {
                Process.GetCurrentProcess().Kill();
            }
		}

		// Use this method to connect to InSim so you are able to catch any exception that might occure
		private void InSimConnect()
		{
			try
			{
				InSim = new InSimInterface(Settings);	// Initialize a new instance of InSimInterface with the settings specified above
				InSim.ConnectionLost += new InSimInterface.ConnectionLost_EventHandler(LostConnectionToInSim);	// Occurs when connection was lost due to an unknown reason
				InSim.Reconnected += new InSimInterface.Reconnected_EventHandler(ReconnectedToInSim);			// Occurs when connection was recovert automatically

				InitializeInSimEvents();				// Initialize packet receive events
				InSim.Connect();						// Attempt to connect to the InSim host 
			}
			catch (InvalidConfigurationException ex)
			{
				MessageBox.Show(ex.Message);
			}
			catch (UnableToConnectToInSimException ex)
			{
				MessageBox.Show(ex.Message);
			}
			catch (AdminPasswordDoesNotMatchException ex)
			{
				MessageBox.Show(ex.Message);
			}
			catch (UDPListenPortAlreadyInUseException ex)
			{
				MessageBox.Show(ex.Message);
			}
			catch (AutoReconnectFailedException ex)
			{
				MessageBox.Show(ex.Message);
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
			finally
			{
				if (InSim.State == LFS_External.InSim.InSimInterface.InSimState.Connected)
				{
					// Request all players and connections so we can build the Connections and Players list
					InSim.Request_NCN_AllConnections(255);
					InSim.Request_NPL_AllPlayers(255);
                    InSim.Request_STA_State(9);
                    globalVars.checkCreateDirsFiles();
				}
			}
		}

		// Occurs when connection was lost due to an unknown reason
		private void LostConnectionToInSim()
		{
			MessageBox.Show("Connection to InSim lost due to an unknown reason.");
		}

		// Occurs when connection was recovert automatically
		private void ReconnectedToInSim()
		{
			MessageBox.Show("Automatically reconnected to InSim.");
			// You should request all connections and players again so you can check changes in the corresponding lists
		}
		
		// You should only enable the events you need to gain maximum performance. All events are enable by default.
		private void InitializeInSimEvents()
		{
			// Client information
			InSim.NCN_Received += new LFS_External.InSim.InSimInterface.NCN_EventHandler(NCN_ClientJoinsHost);				// A new client joined the server.
			InSim.CNL_Received += new LFS_External.InSim.InSimInterface.CNL_EventHandler(CNL_ClientLeavesHost);				// A client left the server.
			InSim.CPR_Received += new LFS_External.InSim.InSimInterface.CPR_EventHandler(CPR_ClientRenames);				// A client changed name or plate.
			InSim.PFL_Received += new LFS_External.InSim.InSimInterface.PFL_EventHandler(PFL_PlayerFlagsChanged);			// Player help settings changed.
			InSim.PLP_Received += new LFS_External.InSim.InSimInterface.PLP_EventHandler(PLP_PlayerGoesToGarage);			// A player goes to the garage (setup screen).
			InSim.NPL_Received += new LFS_External.InSim.InSimInterface.NPL_EventHandler(NPL_PlayerJoinsRace);				// A player join the race. If PLID already exists, then player leaves pit.
			InSim.LAP_Received += new LFS_External.InSim.InSimInterface.LAP_EventHandler(LAP_PlayerCompletesLap);			// A player crosses start/finish line
			InSim.TOC_Received += new LFS_External.InSim.InSimInterface.TOC_EventHandler(TOC_PlayerCarTakeOver);			// Car got taken over by an other player
			InSim.FIN_Received += new LFS_External.InSim.InSimInterface.FIN_EventHandler(FIN_PlayerFinishedRaces);			// A player finishes race and crosses the finish line
			InSim.CRS_Received += new LFS_External.InSim.InSimInterface.CRS_EventHandler(CRS_PlayerResetsCar);				// A player resets the car
			InSim.PIT_Received += new LFS_External.InSim.InSimInterface.PIT_EventHandler(PIT_PlayerStopsAtPit);				// A player stops for making a pitstop
			InSim.PSF_Received += new LFS_External.InSim.InSimInterface.PSF_EventHandler(PSF_PitStopFinished);				// A pitstop got finished
			InSim.AXO_Received += new LFS_External.InSim.InSimInterface.AXO_EventHandler(AXO_PlayerHitsAutocrossObject);	// A player hits an autocross object
			InSim.PLL_Received += new LFS_External.InSim.InSimInterface.PLL_EventHandler(PLL_PlayerLeavesRace);				// A player leaves the race (spectate)
			InSim.BFN_Received += new LFS_External.InSim.InSimInterface.BFN_EventHandler(BFN_PlayerRequestsButtons);		// A player pressed Shift+I or Shift+B
			InSim.BTC_Received += new LFS_External.InSim.InSimInterface.BTC_EventHandler(BTC_ButtonClicked);				// A player clicked a custom button
			InSim.BTT_Received += new LFS_External.InSim.InSimInterface.BTT_EventHandler(BTT_TextBoxOkClicked);				// A player submitted a custom textbox
			InSim.PEN_Received += new LFS_External.InSim.InSimInterface.PEN_EventHandler(PEN_PenaltyChanged);				// A penalty give or cleared
			InSim.FLG_Received += new LFS_External.InSim.InSimInterface.FLG_EventHandler(FLG_FlagChanged);					// Yellow or blue flag changed
			InSim.PLA_Received += new LFS_External.InSim.InSimInterface.PLA_EventHandler(PLA_PitLaneChanged);				// A player entered or left the pitlane
			InSim.SPX_Received += new LFS_External.InSim.InSimInterface.SPX_EventHandler(SPX_SplitTime);					// A player crossed a lap split
			InSim.CCH_Received += new LFS_External.InSim.InSimInterface.CCH_EventHandler(CCH_CameraChanged);				// A player changed it's camera

			// Host and race information
			InSim.STA_Received += new LFS_External.InSim.InSimInterface.STA_EventHandler(STA_StateChanged);					// The server/race state changed
			InSim.ISM_Received += new LFS_External.InSim.InSimInterface.ISM_EventHandler(ISM_MultiplayerInformation);		// A host is started or joined
			InSim.MPE_Received += new LFS_External.InSim.InSimInterface.MPE_EventHandler(MPE_MultiplayerEnd);				// A host ends or leaves
			InSim.CLR_Received += new LFS_External.InSim.InSimInterface.CLR_EventHandler(CLR_RaceCleared);					// Race got cleared with /clear
			InSim.REO_Received += new LFS_External.InSim.InSimInterface.REO_EventHandler(REO_RaceStartOrder);				// Sent at the start of every race or qualifying session, listing the start order
			InSim.RST_Received += new LFS_External.InSim.InSimInterface.RST_EventHandler(RST_RaceStart);					// A race starts
			InSim.RES_Received += new LFS_External.InSim.InSimInterface.RES_EventHandler(RES_RaceOrQualifyingResult);		// Qualify or confirmed finish
			InSim.REN_Received += new LFS_External.InSim.InSimInterface.REN_EventHandler(REN_RaceEnds);						// A race ends (return to game setup screen)
			InSim.RTP_Received += new LFS_External.InSim.InSimInterface.RTP_EventHandler(RTP_RaceTime);						// Current race time progress in hundredths
			InSim.AXC_Received += new LFS_External.InSim.InSimInterface.AXC_EventHandler(AXC_AutocrossCleared);				// Autocross got cleared
			InSim.AXI_Received += new LFS_External.InSim.InSimInterface.AXI_EventHandler(AXI_AutocrossLayoutInformation);	// Request - autocross layout information
			InSim.CPP_Received += new LFS_External.InSim.InSimInterface.CPP_EventHandler(CPP_CameraPosition);				// LFS reporting camera position and state
			InSim.VTA_Received += new LFS_External.InSim.InSimInterface.VTA_EventHandler(VTA_VoteAction);					// A vote completed
			InSim.VTC_Received += new LFS_External.InSim.InSimInterface.VTC_EventHandler(VTC_VoteCanceled);					// A vote got canceled
			InSim.VTN_Received += new LFS_External.InSim.InSimInterface.VTN_EventHandler(VTN_VoteNotify);					// A vote got called

			// Car tracking
			InSim.MCI_Received += new LFS_External.InSim.InSimInterface.MCI_EventHandler(MCI_CarInformation);				// Detailed car information packet (max 8 per packet)
			InSim.NLP_Received += new LFS_External.InSim.InSimInterface.NLP_EventHandler(NLP_LapNode);						// Compact car information packet

			// Other
			InSim.MSO_Received += new LFS_External.InSim.InSimInterface.MSO_EventHandler(MSO_MessageOut);					// Player chat and system messages.
			InSim.III_Received += new LFS_External.InSim.InSimInterface.III_EventHandler(III_InSimInfo);					// A /i message got sent to this program
			InSim.VER_Received += new LFS_External.InSim.InSimInterface.VER_EventHandler(VER_InSimVersionInformation);		// InSim version information
			InSim.REPLY_Received += new LFS_External.InSim.InSimInterface.REPLY_EventHandler(REPLY_PingReplay);				// Reply to a ping request
		}

		#region ' Utils '
		// Methods for automatically update Players[] and Connection[] lists
		private void RemoveFromConnectionsList(byte ucid)
		{
			// Copy of item to remove
			clsConnection RemoveItem = new clsConnection();

			// Check what item the connection had
			foreach (clsConnection Conn in Connections)
			{
				if (ucid == Conn.UniqueID)
				{
					// Copy item (Can't delete it here)
					RemoveItem = Conn;
					continue;
				}
			}

			// Remove item
			Connections.Remove(RemoveItem);
		}
		private void AddToConnectionsList(Packets.IS_NCN NCN)
		{
			bool InList = false;

			// Check of connection is already in the list
			foreach (clsConnection Conn in Connections)
			{
				if (Conn.UniqueID == NCN.UCID)
				{
					InList = true;
					continue;
				}
			}

			// If not, add it
			if (!InList)
			{
				// Assign values of new connnnection.
				clsConnection NewConn = new clsConnection();
				NewConn.UniqueID = NCN.UCID;
				NewConn.Username = NCN.UName;
				NewConn.PlayerName = NCN.PName;
				NewConn.IsAdmin = NCN.Admin;
				NewConn.Flags = NCN.Flags;

				Connections.Add(NewConn);
			}
		}
		private void RemoveFromPlayersList(byte plid)
		{
			// Copy of item to remove
			clsPlayer RemoveItem = new clsPlayer();

			// Check what item the player had
			foreach (clsPlayer Player in Players)
			{
				if (plid == Player.PlayerID)
				{
					// Copy item (Can't delete it here)
					RemoveItem = Player;
					continue;
				}
			}

			// Remove item
			Players.Remove(RemoveItem);
		}
		private bool AddToPlayersList(Packets.IS_NPL NPL)
		{
			bool InList = false;

			// Check if player is already in the list
			foreach (clsPlayer Player in Players)
			{
				if (Player.PlayerID == NPL.PLID)
				{
					Player.AddedMass = NPL.H_Mass;
					Player.CarName = NPL.CName;
					Player.Flags = NPL.Flags;
					Player.Passengers = NPL.Pass;
					Player.Plate = NPL.Plate;
					Player.PlayerType = (clsPlayer.enuPType)NPL.PType;
					Player.SkinName = NPL.SName;
					Player.Tyre_FL = NPL.Tyre_FL;
					Player.Tyre_FR = NPL.Tyre_FR;
					Player.Tyre_RL = NPL.Tyre_RL;
					Player.Tyre_RR = NPL.Tyre_RR;
					Player.IntakeRestriction = NPL.H_TRes;
					return true;
				}
			}

			// If not, add it
			if (!InList)
			{
				// Assign values of new player.
				clsPlayer NewPlayer = new clsPlayer();
				NewPlayer.AddedMass = NPL.H_Mass;
				NewPlayer.CarName = NPL.CName;
				NewPlayer.Flags = NPL.Flags;
				NewPlayer.Passengers = NPL.Pass;
				NewPlayer.Plate = NPL.Plate;
				NewPlayer.PlayerID = NPL.PLID;
				NewPlayer.UniqueID = NPL.UCID;
				NewPlayer.PlayerName = NPL.PName;
				NewPlayer.PlayerType = (clsPlayer.enuPType)NPL.PType;
				NewPlayer.SkinName = NPL.SName;
				NewPlayer.Tyre_FL = NPL.Tyre_FL;
				NewPlayer.Tyre_FR = NPL.Tyre_FR;
				NewPlayer.Tyre_RL = NPL.Tyre_RL;
				NewPlayer.Tyre_RR = NPL.Tyre_RR;

				Players.Add(NewPlayer);
			}

			return false;
		}

		/// <summary>
		/// Returns an index value for Connections[] that corresponds with the UniqueID of a connection
		/// </summary>
		/// <param name="UNID">UCID to find</param>
		public int GetConnIdx(int UNID)
		{
			for (int i = 0; i < Connections.Count; i++)
			{
				if (Connections[i].UniqueID == UNID) { return i; }
			}
			return 0;
		}

		/// <summary>
		/// Returns an index value for Players[] that corresponds with the UniqueID of a player
		/// </summary>
		/// <param name="PLID">PLID to find</param>
		public int GetPlyIdx(int PLID)
		{
			for (int i = 0; i < Players.Count; i++)
			{
				if (Players[i].PlayerID == PLID) { return i; }
			}
			return 0;
		}

		/// <summary>Returns true if method needs invoking due to threading</summary>
		private bool DoInvoke()
		{
			foreach (Control c in this.Controls)
			{
				if (c.InvokeRequired) return true;
				break;	// 1 control is enough
			}
			return false;
		}

		#endregion

		#region ' Packet receive events '

		// Player chat and system messages.
		private void MSO_MessageOut(Packets.IS_MSO MSO)
		{
            try
            {
                // Invoke method due to threading. Add this line to any receive event before updating the GUI. Just like in this example, you only have to add a new delegate with the right packet parameter and adjust this line in the new method.
                if (DoInvoke()) { object p = MSO; this.Invoke(new dlgMSO(MSO_MessageOut), p); return; }

                textBox1.Text += MSO.Msg + "\r\n";
                string Msg = MSO.Msg.Substring(MSO.TextStart, (MSO.Msg.Length - MSO.TextStart));
                string[] StrMsg = Msg.Split(' ');
                switch (StrMsg[0].ToLower())
                {
                    case "!buy":
                        if (CarHelper.getCarNumber(StrMsg[1].ToUpper()) > 16 && CarHelper.getCarNumber(StrMsg[1].ToUpper()) != 0)
                        {
                            InSim.Send_MTC_MessageToConnection("^3» ^7No such car: ^1" + StrMsg[1].ToUpper(), MSO.UCID, 0);
                        }
                        else
                        {
                            if (misc.matrixIsNotZero(CarHelper.getCarNumber(StrMsg[1].ToUpper()), Connections[GetConnIdx(MSO.UCID)].cars) == false)
                            {
                                Connections[GetConnIdx(MSO.UCID)].cars = misc.matrixAdd(CarHelper.getCarNumber(StrMsg[1].ToUpper()), Connections[GetConnIdx(MSO.UCID)].cars);
                                InSim.Send_MST_Message("/msg ^3» ^7" + Connections[GetConnIdx(MSO.UCID)].PlayerName + " ^L^7has bought a " + StrMsg[1].ToUpper() + ".");
                            }
                            else
                            {
                                InSim.Send_MTC_MessageToConnection("^3» ^7You own the ^2" + StrMsg[1].ToUpper() + " ^7already.", MSO.UCID, 0);
                            }
                        }
                        break;

                    case "!sell":
                        if (CarHelper.getCarNumber(StrMsg[1].ToUpper()) > 16)
                        {
                            InSim.Send_MTC_MessageToConnection("^3» ^7No such car: ^1" + StrMsg[1].ToUpper(), MSO.UCID, 0);
                        }
                        else
                        {
                            if (misc.matrixIsNotZero(CarHelper.getCarNumber(StrMsg[1].ToUpper()), Connections[GetConnIdx(MSO.UCID)].cars) == true)
                            {
                                Connections[GetConnIdx(MSO.UCID)].cars = misc.matrixDel(CarHelper.getCarNumber(StrMsg[1].ToUpper()), Connections[GetConnIdx(MSO.UCID)].cars);
                                InSim.Send_MST_Message("/msg ^3» ^7" + Connections[GetConnIdx(MSO.UCID)].PlayerName + " ^L^7has sold his " + StrMsg[1].ToUpper() + ".");
                            }
                            else
                            {
                                InSim.Send_MTC_MessageToConnection("^3» ^7You do not own the ^1" + StrMsg[1].ToUpper() + " ^7.", MSO.UCID, 0);
                            }
                        }
                        break;

                    case "!track":
                        InSim.Send_MTC_MessageToConnection("^3» ^7Track: ^2" + globalVars.currentTrack, MSO.UCID, 0);
                        break;

                    case "!gcl":
                    case "!getcurrloc":
                    case "!getcurrentlocation":
                        if (StrMsg.Length < 2)
                        {
                            InSim.Send_MTC_MessageToConnection("^3» ^7Current location: " + misc.getLocationOfPlayer(Players[GetPlyIdx(MSO.PLID)]), MSO.UCID, 0);
                        }
                        else
                        {
                            foreach (clsConnection C in Connections)
                            {
                                if (C.Username == Msg.Remove(0, StrMsg[0].Length + 1))
                                {
                                    try
                                    {
                                        InSim.Send_MTC_MessageToConnection("^3» ^7" + C.PlayerName + "^7's location: " + misc.getLocationOfPlayer(Players[GetPlyIdx(MSO.PLID)]), MSO.UCID, 0);
                                        return;
                                    }
                                    catch
                                    {
                                        InSim.Send_MTC_MessageToConnection("^3» ^7Current location: " + misc.getLocationOfPlayer(Players[GetPlyIdx(MSO.PLID)]), MSO.UCID, 0);
                                        return;
                                    }
                                }
                            }
                            InSim.Send_MTC_MessageToConnection("^3» ^6Current location^7: " + misc.getLocationOfPlayer(Players[GetPlyIdx(MSO.PLID)]), MSO.UCID, 0);
                        }
                        break;

                    case "!sbs":
                    case "!showbs":
                    case "!showbuttonsequence":
                        if (StrMsg.Length > 1)
                        {
                            buttonSequence.createSequence(Msg.Remove(0, StrMsg[0].Length + 1), MSO.UCID, Connections[GetConnIdx(MSO.UCID)]);
                        }
                        else
                        {
                            InSim.Send_MTC_MessageToConnection("This command needs a parameter", MSO.UCID, 0);
                        }
                        break;

                    case "!dsp":
                    case "!distsp":
                    case "!distancesincepits":
                        if (StrMsg.Length > 2)
                        {
                            foreach (clsConnection C in Connections)
                            {
                                if (C.Username.ToLower() == StrMsg[2].Trim().ToLower())
                                {
                                    misc.convertToPlayer(C).distanceSincePits = int.Parse(StrMsg[1]);
                                }
                            }
                        }
                        else
                        {
                            InSim.Send_MTC_MessageToConnection("This command needs 2 parameters", MSO.UCID, 0);
                        }
                        break;

                    case "!sbsx":
                    case "!showbsx":
                    case "!showbuttonsequencex":
                        buttonSequence.createSequence(Msg.Remove(0, StrMsg[0].Length + StrMsg[1].Length + 2), MSO.UCID, Connections[GetConnIdx(MSO.UCID)], 3, 142, 0, int.Parse(StrMsg[1]), 0);
                        break;

                    case "!sbsy":
                    case "!showbsy":
                    case "!showbuttonsequencey":
                        buttonSequence.createSequence(Msg.Remove(0, StrMsg[0].Length + StrMsg[1].Length + 2), MSO.UCID, Connections[GetConnIdx(MSO.UCID)], 3, 142, 0, 0, int.Parse(StrMsg[1]));
                        break;

                    case "!sbsxy":
                    case "!showbsxy":
                    case "!showbuttonsequencexy":
                        buttonSequence.createSequence(Msg.Remove(0, StrMsg[0].Length + StrMsg[1].Length + StrMsg[2].Length + 3), MSO.UCID, Connections[GetConnIdx(MSO.UCID)], 3, 142, 0, int.Parse(StrMsg[1]), int.Parse(StrMsg[2]));
                        break;
                }
            }
            catch (Exception E)
            {
                misc.manageHandledException(E);
            }
		}

		// A new client joined the server.
		private void NCN_ClientJoinsHost(Packets.IS_NCN NCN)
		{
			AddToConnectionsList(NCN);	// Update Connections[] list
            try
            {
                buttonSequence.createSequence("hudFull", NCN.UCID, Connections[GetConnIdx(NCN.UCID)]);
            }
            catch (Exception E)
            {
                misc.manageHandledException(E);
            }
			// Your code here
		}

		// A client left the server.
		private void CNL_ClientLeavesHost(Packets.IS_CNL CNL)
		{
			RemoveFromConnectionsList(CNL.UCID);		// Update Connections[] list
		}

		// A client changed name or plate.
		private void CPR_ClientRenames(Packets.IS_CPR CPR)
		{
			foreach (clsConnection c in Connections)	// Update Connections[] list
				if (c.UniqueID == CPR.UCID)
				{
					c.PlayerName = CPR.PName;
				}
			foreach (clsPlayer p in Players)	// Update Players[] list
				if (p.UniqueID == CPR.UCID)
				{
					p.PlayerName = CPR.PName;
					p.Plate = CPR.Plate;
				}
		}

		// Car was taken over by an other player
		private void TOC_PlayerCarTakeOver(Packets.IS_TOC TOC)
		{
			Players[GetPlyIdx(TOC.OldUCID)].UniqueID = TOC.NewUCID;	// Update Players[] list
			Players[GetPlyIdx(TOC.OldUCID)].PlayerID = TOC.PLID;	// Update Players[] list

			// Your code here
		}

		// A player leaves the race (spectate)
		private void PLL_PlayerLeavesRace(Packets.IS_PLL PLL)
		{
			RemoveFromPlayersList(PLL.PLID);		// Update Players[] list

			// Your code here
		}

		// Player help settings changed.
		private void PFL_PlayerFlagsChanged(Packets.IS_PFL PFL)
		{
		}

		// A player goes to the garage (setup screen).
		private void PLP_PlayerGoesToGarage(Packets.IS_PLP PLP)
		{
		}

		// A player joins the race. If PLID already exists, then player leaves pit.
		private void NPL_PlayerJoinsRace(Packets.IS_NPL NPL)
		{
			bool LeavesPits = AddToPlayersList(NPL);	// Update Players[] list

            if (misc.matrixIsNotZero(CarHelper.getCarNumber(NPL.CName), Connections[GetConnIdx(NPL.UCID)].cars) == false)
            {
                InSim.Send_MTC_MessageToConnection("^3» ^7You do ^1not ^7own the " + CarHelper.GetFullCarName(NPL.CName) + ".", NPL.UCID, 0);
            }

			// Your code here
		}

		// A player crosses start/finish line
		private void LAP_PlayerCompletesLap(Packets.IS_LAP LAP)
		{
		}

		// A player finishes race and crosses the finish line
		private void FIN_PlayerFinishedRaces(Packets.IS_FIN FIN)
		{
		}

		// A player resets the car
		private void CRS_PlayerResetsCar(Packets.IS_CRS CRS)
		{
		}

		// A player stops for making a pitstop
		private void PIT_PlayerStopsAtPit(Packets.IS_PIT PIT)
		{
		}

		// A pitstop got finished
		private void PSF_PitStopFinished(Packets.IS_PSF PSF)
		{
		}

		// A player hits an autocross object
		private void AXO_PlayerHitsAutocrossObject(Packets.IS_AXO AXO)
		{
		}

		// A player pressed Shift+I or Shift+B
		private void BFN_PlayerRequestsButtons(Packets.IS_BFN BFN)
        {
            if (Connections[GetConnIdx(BFN.UCID)].hudEnabled == true)
            {
                Connections[GetConnIdx(BFN.UCID)].hudEnabled = false;
                InSim.Send_MTC_MessageToConnection("^3» ^7HUD ^1disabled^7.", BFN.UCID, 0);
            }
            else
            {
                buttonSequence.createSequence("hudFull", BFN.UCID, Connections[GetConnIdx(BFN.UCID)]);
                Connections[GetConnIdx(BFN.UCID)].hudEnabled = true;
                InSim.Send_MTC_MessageToConnection("^3» ^7HUD ^2enabled^7.", BFN.UCID, 0);
            }
		}

		// A player clicked a custom button
		private void BTC_ButtonClicked(Packets.IS_BTC BTC)
		{
		}

		// A player submitted a custom textbox
		private void BTT_TextBoxOkClicked(Packets.IS_BTT BTT)
		{
		}

		// A penalty give or cleared
		private void PEN_PenaltyChanged(Packets.IS_PEN PEN)
		{
		}

		// Yellow or blue flag changed
		private void FLG_FlagChanged(Packets.IS_FLG FLG)
		{
		}

		// A player entered or left the pitlane
		private void PLA_PitLaneChanged(Packets.IS_PLA PLA)
		{
		}

		// A player crossed a lap split
		private void SPX_SplitTime(Packets.IS_SPX SPX)
		{
		}

		// A player changed it's camera
		private void CCH_CameraChanged(Packets.IS_CCH CCH)
		{
		}

		// The server/race state changed
		private void STA_StateChanged(Packets.IS_STA STA)
		{
            globalVars.currentTrack = STA.Track;
		}

		// A host is started or joined
		private void ISM_MultiplayerInformation(Packets.IS_ISM ISM)
		{
            globalVars.serverName = ISM.HName;
		}

		// A host ends or leaves
		private void MPE_MultiplayerEnd()
		{
		}

		// Race got cleared with /clear
		private void CLR_RaceCleared()
		{
		}

		// Sent at the start of every race or qualifying session, listing the start order
		private void REO_RaceStartOrder(Packets.IS_REO REO)
		{
		}

		// Race start information
		private void RST_RaceStart(Packets.IS_RST RST)
		{
            globalVars.currentTrack = RST.Track;
		}

		// Qualify or confirmed finish
		private void RES_RaceOrQualifyingResult(Packets.IS_RES RES)
		{
		}

		// A race ends (return to game setup screen)
		private void REN_RaceEnds()
		{
		}

		// Current race time progress in hundredths
		private void RTP_RaceTime(uint RTP)
		{
		}

		// Autocross got cleared
		private void AXC_AutocrossCleared()
		{
		}

		// Request - autocross layout information
		private void AXI_AutocrossLayoutInformation(Packets.IS_AXI AXI)
		{
		}

		// LFS reporting camera position and state
		private void CPP_CameraPosition(Packets.IS_CPP CPP)
		{
		}

		// A vote completed
		private void VTA_VoteAction(byte VTA)
		{
		}

		// A vote got canceled
		private void VTC_VoteCanceled()
		{
		}

		// A vote got called
		private void VTN_VoteNotify(Packets.IS_VTN VTN)
		{
		}

		// Detailed car information packet (max 8 per packet)
		private void MCI_CarInformation(Packets.IS_MCI MCI)
        {
            try
            {
                //CompCar is the CompCar packet structure I added to clsPlayer
                for (int i = 0; i < MCI.NumC; i++)
                {
                    int idx = 0;
                    idx = GetPlyIdx(MCI.Info[i].PLID);
                    Players[idx].CompCarPrev.AngVel = Players[idx].CompCar.AngVel; //They aren't structures so you cant serialize!
                    Players[idx].CompCarPrev.Direction = Players[idx].CompCar.Direction;
                    Players[idx].CompCarPrev.Heading = Players[idx].CompCar.Heading;
                    Players[idx].CompCarPrev.Info = Players[idx].CompCar.Info;
                    Players[idx].CompCarPrev.Lap = Players[idx].CompCar.Lap;
                    Players[idx].CompCarPrev.Node = Players[idx].CompCar.Node;
                    Players[idx].CompCarPrev.PLID = Players[idx].CompCar.PLID;
                    Players[idx].CompCarPrev.Position = Players[idx].CompCar.Position;
                    Players[idx].CompCarPrev.Speed = Players[idx].CompCar.Speed;
                    Players[idx].CompCarPrev.X = Players[idx].CompCar.X;
                    Players[idx].CompCarPrev.Y = Players[idx].CompCar.Y;
                    Players[idx].CompCarPrev.Z = Players[idx].CompCar.Z;

                    Players[idx].CompCar.AngVel = MCI.Info[i].AngVel; //They aren't structures so you cant serialize!
                    Players[idx].CompCar.Direction = MCI.Info[i].Direction;
                    Players[idx].CompCar.Heading = MCI.Info[i].Heading;
                    Players[idx].CompCar.Info = MCI.Info[i].Info;
                    Players[idx].CompCar.Lap = MCI.Info[i].Lap;
                    Players[idx].prevNode = Players[idx].CompCar.Node;
                    Players[idx].CompCar.Node = MCI.Info[i].Node;
                    Players[idx].CompCar.PLID = MCI.Info[i].PLID;
                    Players[idx].CompCar.Position = MCI.Info[i].Position;
                    Players[idx].CompCar.Speed = MCI.Info[i].Speed;
                    Players[idx].CompCar.X = MCI.Info[i].X;
                    Players[idx].CompCar.Y = MCI.Info[i].Y;
                    Players[idx].CompCar.Z = MCI.Info[i].Z;

                    if (Players[idx].CompCarPrev.X == 0 && Players[idx].CompCarPrev.Y == 0 && Players[idx].CompCarPrev.Z == 0)
                    {
                        Players[idx].CompCarPrev.AngVel = Players[idx].CompCar.AngVel; //They aren't structures so you cant serialize!
                        Players[idx].CompCarPrev.Direction = Players[idx].CompCar.Direction;
                        Players[idx].CompCarPrev.Heading = Players[idx].CompCar.Heading;
                        Players[idx].CompCarPrev.Info = Players[idx].CompCar.Info;
                        Players[idx].CompCarPrev.Lap = Players[idx].CompCar.Lap;
                        Players[idx].CompCarPrev.Node = Players[idx].CompCar.Node;
                        Players[idx].CompCarPrev.PLID = Players[idx].CompCar.PLID;
                        Players[idx].CompCarPrev.Position = Players[idx].CompCar.Position;
                        Players[idx].CompCarPrev.Speed = Players[idx].CompCar.Speed;
                        Players[idx].CompCarPrev.X = Players[idx].CompCar.X;
                        Players[idx].CompCarPrev.Y = Players[idx].CompCar.Y;
                        Players[idx].CompCarPrev.Z = Players[idx].CompCar.Z;
                    }
                    Players[idx].currentSpeedKph = (int)(MCI.Info[i].Speed / 91.02);
                    Players[idx].location = misc.getLocationOfPlayer(Players[idx]);
                    //<--------------------------------------------------------------
                }
                for (int i = 0; i < MCI.NumC; i++)
                {
                    int idx = 0;
                    idx = GetPlyIdx(MCI.Info[i].PLID);

                    double momentDistancePassed = MathHelper.Distance(Players[idx].CompCarPrev.X, Players[idx].CompCarPrev.Y, Players[idx].CompCarPrev.Z, Players[idx].CompCar.X, Players[idx].CompCar.Y, Players[idx].CompCar.Z);
                    Connections[GetConnIdx(Players[idx].UniqueID)].distanceTotal += (int)MathHelper.LengthToMetres(momentDistancePassed);
                    Players[idx].distanceSincePits += (int)MathHelper.LengthToMetres(momentDistancePassed);
                    if (Players[idx].distanceSincePits >= 50000)
                    {
                        cmdManager.userWon(Players[idx].nextDistanceBonusAmount, "Distance bonus.", Players[idx]);
                        Players[idx].distanceSincePits = 25000;
                        Players[idx].nextDistanceBonusAmount += (Players[idx].nextDistanceBonusAmount / 10);
                    }

                    decimal ConvSpeed = (decimal)(MathHelper.SpeedToKph(MCI.Info[i].Speed) * 25 / 1000);
                    Players[GetPlyIdx(MCI.Info[i].PLID)].payout += ConvSpeed;
                    if (Players[idx].payout > 8)
                    {
                        Connections[GetConnIdx(Players[idx].UniqueID)].money += 1;
                        Players[idx].payout = 0;
                    }

                    if ((Connections[GetConnIdx(Players[idx].UniqueID)].health -= (int)(MathHelper.SpeedToKph(MCI.Info[i].Speed) / 20)) < 0)
                    {
                        Connections[GetConnIdx(Players[idx].UniqueID)].health = 0;
                    }
                    else
                    {
                        Connections[GetConnIdx(Players[idx].UniqueID)].health -= (int)(MathHelper.SpeedToKph(MCI.Info[i].Speed) / 20);
                    }

                    if (Connections[GetConnIdx(Players[idx].UniqueID)].hudEnabled == true)
                    {
                        buttonSequence.createSequence("hudPart1smartUpdate", Players[idx].UniqueID, Connections[GetConnIdx(Players[idx].UniqueID)]);
                    }

                    if (Players[idx].location != Players[idx].prevLocation || Players[idx].speedLimit != Players[idx].prevSpeedLimit)
                    {
                        Players[idx].prevLocation = Players[idx].location;
                        Players[idx].prevSpeedLimit = Players[idx].speedLimit;
                        buttonSequence.createSequence("hudPart2LocSpdLmt", Players[idx].UniqueID, misc.convertToConnection(Players[idx]));
                    }

                    bool currentlySpeeding;
                    if (Players[idx].currentSpeedKph > Players[idx].speedLimit)
                    {
                        currentlySpeeding = true;
                    }
                    else
                    {
                        currentlySpeeding = false;
                    }
                    if (Players[idx].currentlySpeeding != currentlySpeeding)
                    {
                        buttonSequence.createSequence("hudPart2SpdLmt", Players[idx].UniqueID, misc.convertToConnection(Players[idx]));
                        Players[idx].currentlySpeeding = currentlySpeeding;
                    }
                }
            }
            catch
            {
            }
		}

		// Compact car information packet
		private void NLP_LapNode(Packets.IS_NLP NLP)
		{
		}

		// A /i message got sent to this program
		private void III_InSimInfo(Packets.IS_III III)
		{
		}

		// InSim version information
		private void VER_InSimVersionInformation(Packets.IS_VER VER)
		{
		}

		// Reply to a ping request
		private void REPLY_PingReplay()
		{
		}

		#endregion
	}
}