//  
//  infoPlayer.cs
//  
//  Author:
//       Robert BRACCAGNI alias Gai-Luron <lfsgailuron@free.fr>
// 
//  Copyright (c) 2010 Gai-Luron
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
// 
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections;
using System.Text;


namespace LFSLapper
{
    public class infoPlayer
    {
        public class elpasedInfo
        {
            public long[] elapsedTime = new long[(int)paramLapper.maxSplit + 1];
            public long[] lap = new long[(int)paramLapper.maxSplit + 1];
        }

        public int UCID;
        public int PLID;

        public int finishedPLID;
        private InSim.Connect IC;
        public string userName;
        public string nickName;
		public bool isServerAdmin = false;	// Is the player a server admin

        public string idLang = "en";

		public bool isConfigPlayerChanged = false;

        public bool OnTrack = false;
        public bool OnPit = false;
        public string pitWork;
        public bool allowIdleOnTrack = false;

        //result race
        public int finishedPos = -1;
        public long raceTotalTime = 0;
        public long racePBTime = 0;

        //Tyre
        public InSim.tyre oldTyreRearLeft = InSim.tyre.TYRE_NUM;
        public InSim.tyre oldTyreRearRight = InSim.tyre.TYRE_NUM;
        public InSim.tyre oldTyreFrontLeft = InSim.tyre.TYRE_NUM;
        public InSim.tyre oldTyreFrontRight = InSim.tyre.TYRE_NUM;

        public InSim.tyre tyreRearLeft = InSim.tyre.TYRE_NUM;
        public InSim.tyre tyreRearRight = InSim.tyre.TYRE_NUM;
        public InSim.tyre tyreFrontLeft = InSim.tyre.TYRE_NUM;
        public InSim.tyre tyreFrontRight = InSim.tyre.TYRE_NUM;

		public int currPos = 0;
		public int lastPos = 0;
		public string UNameBehind = "";
        public string UNameBefore = "";
        public string gapBehind = "";
        public string gapBefore = "";
        public long MaxLapTime;

        public int sessLaps;
        public int lapsDone;

        public string sPlayerFlags = "";

        public int lastIdxSplit = -1;
        public long[] split = new long[(int)paramLapper.maxSplit];
        public long lapTime;
        public long diffLapTimeToPb;
        public long[] sectorSplit = new long[(int)paramLapper.maxSplit];
        public long sectorSplitLast;
        public long[] bestSectorSplit = new long[(int)paramLapper.maxSplit];
        public long bestSectorSplitLast;
        public long[] diffSectorSplit = new long[(int)paramLapper.maxSplit];
        public long diffSectorSplitLast;
        public bool[] isBestSectorSplit = new bool[(int)paramLapper.maxSplit];
        public bool isBestSectorSplitLast;

        public long splitLast;

        public long currSplit;
        public long diffSplit;
        public long bestSplit;
        public bool newSessBestSplit;
        public bool newPBBestSplit;
        public bool newWRBestSplit;

        public long lastSplitTime;


        public long[] sessBestSplitDiff = new long[(int)paramLapper.maxSplit];
        public long sessBestSplitDiffLast;


        public double bestSpeed;
        public string CName;
        public string TName;

        public LFSDbs.gripDbs.DriverLapEntry gripDriverLapInfo;
        public LFSDbs.driftDbs.DriverLapEntry driftDriverLapInfo;
        public bool isNewPBLtime;
        public bool isNewPBLap;
        // Drift Infos
        public double absangle;
        public double totaldriftscore, lastdriftscore, driftticks;
		public bool isDriftReset = false;
		public bool isNewBestdriftScore;
		public double instantSpeed, direction, heading;

        // Car Reset
        public int NumCarResets = 0;

        // Node Infos
        public int LastNode = -1;
        public int CurrNode = -1;

        // Zode Infos
        public int LastZone = -1;
        public int CurrZone = -1;
		public string idCurrZone = "NONE";

        // Idle Infos
        public int idleticks;
        public bool OnIdleAction1Sended = false;

        public int stuntticks;
        public double AngVel;

        public double maxLapSpeed;
        // Acceleration Info
        public bool accelerationInProgress;
        public System.DateTime timeSinceZeroSpeed;
        public System.TimeSpan accelerationTime;
        public bool accelerationTimeValid;

		public int x = 0, y = 0, z = 0;
		public int old_x = 0, old_y = 0, old_z = 0;
		public double totDistMeter = 0;
		public double lastTotDistMeter = 0; // Last tot dist meter. Reset to totDistMeter when OnDistDone triggered

        public int floodcount;
        public DateTime LastLine = DateTime.Now;

        public DateTime LastCrossedFinishLine = DateTime.Now;
        public bool MaxLapTime1Reached = false;
        public bool MaxLapTime2Reached = false;

        public int swearWordsCount = 0;

        public int drivethroughcount;
        public int NbFastDriveOnPit;

        public int PenaltyNew = (int)InSim.pen.PENALTY_NONE;
        public int PenaltyOld = (int)InSim.pen.PENALTY_NONE;

        public long totalPitTime;
        public long pitTime;
        public long pitStops;

        public int showButton = 0;
        // Config for the curr player
        public string viewSPBSplit = "P";
        public bool showSplitPB = true;
        public bool unitSpeedKmh = true;
        //Handicap info
        public int P_Mass = 0; // Player Handicap Mass
        public int P_TRes = 0; // Player Handicap ntake restriction
        public int H_Mass = 0; // Player Handicap Mass
        public int H_TRes = 0; // Player Handicap ntake restriction

        // Vote
        public int currVote = (int)InSim.vtn.VOTE_NONE;
        public DateTime expireVote = DateTime.Now;

        // Player Box
        public ISMB.msgBox playerBox;

        // GLScript
        // GLScript Player Function
        public System.Collections.Hashtable functionsLapper = new System.Collections.Hashtable();
        // GLSCript Player Var
        public GLScript.SetOfVars playerVars;

        // Elpased Info
        public elpasedInfo currElapsedInfo = new elpasedInfo();

        // Player Task
        public System.Collections.ArrayList tasks = new System.Collections.ArrayList();

        private GLDebug.Debug myDebug;

		public LapperThreads.PubStatUser pubStatUser; 

		public LapperThreads.PubStatUser.PubStatUserPb pubStatUserPB;
		public LapperThreads.PubStatUser.PubStatUserPst pubStatUserPst;

		// limit update statistic with skip counter
		private int skipCounter = 0;

        public infoPlayer( LapperThreads.PubStatUser ppubStatUser, GLDebug.Debug pmyDebug, InSim.Connect pIC, int SUCID, string Susername, string Snickname, string SProduct)
        {
			this.pubStatUser = ppubStatUser;
            this.myDebug = pmyDebug;
            this.UCID = SUCID;
            this.PLID = -1;
            this.IC = pIC;
            this.userName = Susername.ToLower();
            this.nickName = Snickname;

            for (int i = 0; i < (int)paramLapper.maxSplit; i++)
            {
                this.split[i] = 0;
                this.sectorSplit[i] = 0;
                this.sessBestSplitDiff[i] = 0;
                this.bestSectorSplit[i] = 0;
                this.diffSectorSplit[i] = 0;
                this.isBestSectorSplit[i] = false;
            }
            this.sectorSplitLast = 0;
            this.bestSectorSplitLast = 0;
            this.diffSectorSplitLast = 0;
            this.lapTime = 0;
            this.splitLast = 0;
            this.sessBestSplitDiffLast = 0;
            this.isBestSectorSplitLast = false;
            this.bestSpeed = (double)0;
            this.CName = "";

            this.sessLaps = 0;
            this.lapsDone = 0;

            this.showSplitPB = true;

            this.totalPitTime = 0;
            this.pitStops = 0;
            playerBox = new ISMB.msgBox(IC);
			if( pubStatUser != null )
				pubStatUser.requestPubStat(this.userName);
        }
        public void privateButtonClose(string argString)
        {

            string[] butToClose = argString.Split('&');
            for (int i = 0; i < butToClose.Length; i++)
            {
                this.playerBox.delete(butToClose[i], this.UCID);
                //                Console.WriteLine("Close : " + butToClose[i]);
            }

        }
        public void clearSessionInfo()
        {
            for (int i = 0; i < (int)paramLapper.maxSplit; i++)
            {
                this.sessBestSplitDiff[i] = 0;
            }
            this.sessBestSplitDiffLast = 0;
            this.sessLaps = 0;

        }
        public void UpdateState(int currPos, int node, int zone, string idZone, int x, int y, int z, double speed, double direction, double heading, double anglevelocity, int minspeed, int minangle, int maxangle, int MinVel, double accelStartSpeed, double accelEndSpeed)
        {

			this.lastPos = this.currPos;
			this.currPos = currPos;
			this.LastNode = this.CurrNode;
            this.LastZone = this.CurrZone;
            this.CurrNode = node;
            this.CurrZone = zone;
			this.idCurrZone = idZone;
            this.absangle = AbsoluteAngleDifference(this.direction, this.heading);
            double driftscoreinthistick = this.absangle * speed * speed / 10000d;

            if (speed < minspeed) // Reset drift
            {
				if( totaldriftscore != 0 )
					this.isDriftReset = true;
				else
					this.isDriftReset = false;
				this.driftticks = 0;
                this.totaldriftscore = 0;
                this.lastdriftscore = 0;
            }
            else
            {
				this.isDriftReset = false;
				if (this.absangle > minangle && this.absangle < maxangle)
                {
                    this.driftticks++;
                    this.lastdriftscore += driftscoreinthistick;
                    this.totaldriftscore += driftscoreinthistick;
                    //System.Console.WriteLine(string.Format("DRIFT: {0} {1} {2} {3} score: {4}", this.UserName, this.NickName, this.UniqueID, this.ConnectionNumber, this.driftscore));
                }
                else
                {
                    this.driftticks = 0;
                }
            }

            this.direction = direction;
            this.heading = heading;
            this.instantSpeed = speed;
            this.AngVel = anglevelocity;
            this.x = x;
            this.y = y;
            this.z = z;

            // anglevelocity
            if (anglevelocity > MinVel)
                this.stuntticks++;
            else
                this.stuntticks = 0;

            // voting
            if ((this.currVote != (int)InSim.vtn.VOTE_NONE) && (this.expireVote < DateTime.Now))
                this.currVote = (int)InSim.vtn.VOTE_NONE;

            // idling
            this.idleticks = speed > 1 ? 0 : this.idleticks + 1;
            if (speed > 1)
                this.OnIdleAction1Sended = false;

            // speed
            if (speed > this.maxLapSpeed)
                this.maxLapSpeed = speed;

            if (speed > this.bestSpeed)
                this.bestSpeed = speed;
#region Code executed not every time, limit CPU usage
			if (skipCounter == 5 ) 
			{
				skipCounter = 0;
#region Update distance do by a player
				if (old_x != 0 && old_x != 0 && old_x != 0)
				{
					double diffx = this.old_x - x;
					double diffy = this.old_y - y;
					double addMeter = Math.Sqrt((diffx * diffx) + (diffy * diffy));
					this.totDistMeter += addMeter;
//									Console.WriteLine(this.totDistMeter);
				}
				this.old_x = x;
				this.old_y = y;
				this.old_z = z;
#endregion
			}
			skipCounter++;
#endregion

			// acceleration
            if (speed < accelStartSpeed/*0.1*/)
            {
                this.timeSinceZeroSpeed = System.DateTime.Now;
                this.accelerationInProgress = true;
                //System.Console.WriteLine("measurement started");
            }
            else if (speed > accelEndSpeed/*100*/ && this.accelerationInProgress)
            {
                this.accelerationTime = System.DateTime.Now - this.timeSinceZeroSpeed;
                this.accelerationInProgress = false;
                this.accelerationTimeValid = true;
            }
        }
        public void Rename(string newnick)
        {
            this.nickName = newnick;
        }

        static double AbsoluteAngleDifference(double d, double h)
        {
            double absdiff = Math.Abs(d - h);

            if (absdiff <= 180)
                return absdiff;

            if (d < 180)
            {
                h -= 360;
                return d - h;
            }
            else
            {
                d -= 360;
                return h - d;
            }

        }
        public void updateLapDriftScore(string currentTrackName)
        {
            if (this.totaldriftscore > this.driftDriverLapInfo.driftPoints)
            {
                this.driftDriverLapInfo.driftPoints = (long)this.totaldriftscore;
                this.driftDriverLapInfo.datePb = System.DateTime.Now.ToString("yyyy/MM/dd");
                this.driftDriverLapInfo.timePb = System.DateTime.Now.ToString("HH:mm");

                this.isNewBestdriftScore = true;
            }
            else
            {
                this.isNewBestdriftScore = false;
            }
        }
        public void updateLap(wr currWr, InSim.Decoder.LAP lapDec, long maxLtime, string currentTrackName, int LapTimeUsedForPb)
        {
            long sessDiffSplit;
            long sessBestSplit;
            long PBDiffSplit;
            long PBBestSplit;

            this.lastIdxSplit = (int)paramLapper.maxSplit;
            this.gripDriverLapInfo.laps++;
            this.sessLaps++;
            this.currSplit = lapDec.LTime - this.splitLast;
            this.sectorSplitLast = this.currSplit;
            this.lastSplitTime = lapDec.LTime;
            this.lapTime = lapDec.LTime;

            this.lapsDone = lapDec.LapsDone;
            this.currElapsedInfo.elapsedTime[(int)paramLapper.maxSplit] = lapDec.ETime;
            this.currElapsedInfo.lap[(int)paramLapper.maxSplit] = this.lapsDone;

            sessDiffSplit = currSplit - this.sessBestSplitDiffLast;
            sessBestSplit = this.sessBestSplitDiffLast;
            if (currSplit < this.sessBestSplitDiffLast || this.sessBestSplitDiffLast == 0)
            {
                this.sessBestSplitDiffLast = currSplit;
                this.newSessBestSplit = true;
            }
            else
            {
                this.newSessBestSplit = false;
            }

            PBDiffSplit = currSplit - this.gripDriverLapInfo.PBBestSplitDiffLast;
            PBBestSplit = this.gripDriverLapInfo.PBBestSplitDiffLast;
            if (currSplit < this.gripDriverLapInfo.PBBestSplitDiffLast || this.gripDriverLapInfo.PBBestSplitDiffLast == 0)
            {
                this.gripDriverLapInfo.PBBestSplitDiffLast = currSplit;
                this.newPBBestSplit = true;
            }
            else
            {
                this.newPBBestSplit = false;
            }
            this.isBestSectorSplitLast = false;
            switch (this.viewSPBSplit)
            {
                case "P":
                    this.diffSplit = PBDiffSplit;
                    this.bestSplit = PBBestSplit;
                    if (this.newPBBestSplit)
                        this.isBestSectorSplitLast = true;
                    break;
                case "S":
                    this.diffSplit = sessDiffSplit;
                    this.bestSplit = sessBestSplit;
                    if (this.newSessBestSplit)
                        this.isBestSectorSplitLast = true;
                    break;
                case "W":
                    try
                    {
                        wr.wrInfo wi = currWr.getWR(currentTrackName, this.CName);
                        this.diffSplit = this.currSplit - wi.sectorSplitLast;
                        this.bestSplit = wi.sectorSplitLast;
                        if (this.newWRBestSplit)
                            this.isBestSectorSplitLast = true;
                    }
                    catch
                    {
                        this.diffSplit = 0;
                        this.bestSplit = 0;
                        myDebug.WriteLine("mss","WR not found for combo :" + currentTrackName + "/" + this.CName);
                    }
                    break;
            }
            this.bestSectorSplitLast = this.bestSplit;
            this.diffSectorSplitLast = this.diffSplit;
            this.splitLast = 0;

            this.diffLapTimeToPb = lapDec.LTime - this.gripDriverLapInfo.personalBestLapTime;
            this.isNewPBLap = false;
            this.isNewPBLtime = false;
            if (lapDec.LTime < maxLtime)
            {
                long lastPB = this.gripDriverLapInfo.personalBestLapTime;
                if (this.gripDriverLapInfo.listPB.Count < 10)
                {
                    this.gripDriverLapInfo.listPB.Add(new LFSDbs.gripDbs.PbLapEntry(lapDec.LTime, this.split[0], this.split[1], this.split[2], System.DateTime.Now.ToString("yyyy/MM/dd"), System.DateTime.Now.ToString("HH:mm")));
                    this.gripDriverLapInfo.majPB(LapTimeUsedForPb);
                    this.isNewPBLap = true;
                }
                else
                {
                    if ((this.gripDriverLapInfo.listPB[9] as LFSDbs.gripDbs.PbLapEntry).personalBestLapTime > lapDec.LTime)
                    {
                        this.gripDriverLapInfo.listPB.RemoveAt(9);
                        this.gripDriverLapInfo.listPB.Add(new LFSDbs.gripDbs.PbLapEntry(lapDec.LTime, this.split[0], this.split[1], this.split[2], System.DateTime.Now.ToString("yyyy/MM/dd"), System.DateTime.Now.ToString("HH:mm")));
                        this.gripDriverLapInfo.majPB(LapTimeUsedForPb);
                        this.isNewPBLap = true;
                    }
                }
                if (this.gripDriverLapInfo.personalBestLapTime != lastPB && this.gripDriverLapInfo.personalBestLapTime < (3600000 - 1000))
                {
                    if (this.gripDriverLapInfo.personalBestLapTime < this.wr || this.wr == -1 ) // If new PB retreive WR
						pubStatUser.requestPubStat(this.userName);
                    this.isNewPBLtime = true;
                }
                else
                    this.isNewPBLtime = false;
            }
            LastCrossedFinishLine = DateTime.Now;

        }
        public void updateSplit(wr currWr, InSim.Decoder.SPX splitDec, string track)
        {
            long sessDiffSplit;
            long sessBestSplit;
            long PBDiffSplit;
            long PBBestSplit;

            int idxSplit = splitDec.Split - 1;

            this.lastIdxSplit = idxSplit;


            this.currElapsedInfo.elapsedTime[idxSplit] = splitDec.ETime;
            this.currElapsedInfo.lap[idxSplit] = this.lapsDone;

            // Clear Last Split on first Split
            if (idxSplit == 0)
            {
                this.splitLast = 0;
                for (int i = 0; i < (int)paramLapper.maxSplit; i++)
                {
                    this.split[i] = 0;
                    this.sectorSplit[i] = 0;
                    this.sectorSplitLast = 0;
                }
            }

            this.lastSplitTime = splitDec.STime;
            this.split[idxSplit] = splitDec.STime;
            this.currSplit = splitDec.STime - this.splitLast;
            this.sectorSplit[idxSplit] = this.currSplit;

            sessDiffSplit = this.currSplit - this.sessBestSplitDiff[idxSplit];
            sessBestSplit = this.sessBestSplitDiff[idxSplit];
            if (sessDiffSplit < 0 || this.sessBestSplitDiff[idxSplit] == 0)
            {
                this.sessBestSplitDiff[idxSplit] = this.currSplit;
                this.newSessBestSplit = true;
            }
            else
            {
                this.newSessBestSplit = false;
            }

            PBDiffSplit = this.currSplit - this.gripDriverLapInfo.PBBestSplitDiff[idxSplit];
            PBBestSplit = this.gripDriverLapInfo.PBBestSplitDiff[idxSplit];
            if (PBDiffSplit < 0 || this.gripDriverLapInfo.PBBestSplitDiff[idxSplit] == 0)
            {
                this.gripDriverLapInfo.PBBestSplitDiff[idxSplit] = this.currSplit;
                this.newPBBestSplit = true;
            }
            else
            {
                this.newPBBestSplit = false;
            }
            this.isBestSectorSplit[idxSplit] = false;
            switch (this.viewSPBSplit)
            {
                case "P":
                    this.diffSplit = PBDiffSplit;
                    this.bestSplit = PBBestSplit;
                    if (this.newPBBestSplit)
                        this.isBestSectorSplit[idxSplit] = true;
                    break;
                case "S":
                    this.diffSplit = sessDiffSplit;
                    this.bestSplit = sessBestSplit;
                    if (this.newSessBestSplit)
                        this.isBestSectorSplit[idxSplit] = true;
                    break;
                case "W":
                    try
                    {
                        wr.wrInfo wi = currWr.getWR(track, this.CName);
                        this.diffSplit = this.currSplit - wi.sectorSplit[idxSplit];
                        this.bestSplit = wi.sectorSplit[idxSplit];
                        if (this.newWRBestSplit)
                            this.isBestSectorSplit[idxSplit] = true;
                    }
                    catch
                    {
                        this.diffSplit = 0;
                        this.bestSplit = 0;
                        myDebug.WriteLine( "mss","WR not found for combo :" + track + "/" + this.CName);
                    }
                    break;
            }
            this.bestSectorSplit[idxSplit] = this.bestSplit;
            this.diffSectorSplit[idxSplit] = this.diffSplit;
            this.splitLast = splitDec.STime;
        }
        public void loopTask( Configurator.lexConfigurator newCfg ){

			Task[] listTask = (Task[])tasks.ToArray(typeof(Task));
			for (int i = 0; i < listTask.Length; i++)
            {
				Task currTask = listTask[i];
//				Console.WriteLine("Task : " + currTask.Command);
				if (currTask.IsToExecuteNow() )
                {
					if( currTask.executed == false ){
//						Console.WriteLine("Execution de : " + currTask.Command);
						currTask.executed = true;
						string[] args = new string[1];
						args[0] = this.userName;
						newCfg.executeFunction(currTask.Command, this, args);
						if (currTask.IsOnceToExecuteOnly)
							currTask.toRemove = true;
					}
                }
				else
					currTask.executed = false;
            }
			for (int i = tasks.Count - 1; i >= 0; i--)
			{
				if ((tasks[i] as Task).toRemove)
					tasks.RemoveAt(i);
			}
        }
		public ArrayList getUserListPb(string car, string track)
		{
			ArrayList retPbUser = new ArrayList();
			if (pubStatUserPB == null)
				return retPbUser;
			
			if (car != "" && track != "")
			{
				for (int i = 0; i < pubStatUserPB.listPbElem.Count; i++)
				{
					LapperThreads.PubStatUser.PubStatUserPb.PbElem elem = ( LapperThreads.PubStatUser.PubStatUserPb.PbElem )pubStatUserPB.listPbElem[i];
					if (elem.car == car && elem.track == track)
					{
						retPbUser.Add( elem );
						return retPbUser;
					}
				}
				return retPbUser;
			}
			if (car == "" && track == "")
			{
				pubStatUserPB.sortByCar();
				return pubStatUserPB.listPbElem;
			}
			if (car == "")
			{
				for (int i = 0; i < pubStatUserPB.listPbElem.Count; i++)
				{
					LapperThreads.PubStatUser.PubStatUserPb.PbElem elem = (LapperThreads.PubStatUser.PubStatUserPb.PbElem)pubStatUserPB.listPbElem[i];
					if (elem.track == track)
					{
						retPbUser.Add(elem);
					}
				}
				retPbUser.Sort(new LapperThreads.PubStatUser.PubStatUserPb.sByCar());
				return retPbUser;
			}
			if (track == "")
			{
				for (int i = 0; i < pubStatUserPB.listPbElem.Count; i++)
				{
					LapperThreads.PubStatUser.PubStatUserPb.PbElem elem = (LapperThreads.PubStatUser.PubStatUserPb.PbElem)pubStatUserPB.listPbElem[i];
					if (elem.car == car)
					{
						retPbUser.Add(elem);
					}
				}
				retPbUser.Sort(new LapperThreads.PubStatUser.PubStatUserPb.sByTrack());
				return retPbUser;
			}
			return retPbUser;
		}
        public long wr
        {
            get
            {
	            long wr = -1;
		        if (this.CName != "" && this.TName != "")
			    {
				    System.Collections.ArrayList list = getUserListPb( this.CName,this.TName );
					if (list != null && list.Count != 0)
	                    wr = (list[0] as LapperThreads.PubStatUser.PubStatUserPb.PbElem).lapTime;
		            else
			            wr = -1;
				}
				else
					wr = -1;
            return wr;
			}
        }
		public long PSDistance
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.distance;
				else
					return 0;
			}
		}
		public long PSFuel
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.fuel;
				else
					return 0;
			}
		}
		public long PSLaps
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.laps;
				else
					return 0;
			}
		}
		public long PSHostsJoined
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.hostsJoined;
				else
					return 0;
			}
		}
		public long PSWins
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.wins;
				else
					return 0;
			}
		}
		public long PSSecond
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.second;
				else
					return 0;
			}
		}
		public long PSThird
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.third;
				else
					return 0;
			}
		}
		public long PSFinished
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.finished;
				else
					return 0;
			}
		}
		public long PSQuals
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.quals;
				else
					return 0;
			}
		}
		public long PSPole
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.pole;
				else
					return 0;
			}
		}
		public long PSDrags
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.drags;
				else
					return 0;
			}
		}
		public long PSDragWins
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.dragWins;
				else
					return 0;
			}
		}
		public string PSCountry
		{
			get
			{
				if (this.pubStatUserPst != null)
					return this.pubStatUserPst.country;
				else
					return "";
			}
		}
		public long TPb
        {
            get
            {
                long Tpb = 0;
                switch (this.viewSPBSplit)
                {
                    case "W":
                    case "P":
                        for (int i = 0; i < (int)paramLapper.maxSplit; i++)
                            Tpb += this.gripDriverLapInfo.PBBestSplitDiff[i];
                        Tpb += this.gripDriverLapInfo.PBBestSplitDiffLast;
                        break;
                    case "S":
                        for (int i = 0; i < (int)paramLapper.maxSplit; i++)
                            Tpb += this.sessBestSplitDiff[i];
                        Tpb += this.sessBestSplitDiffLast;
                        break;
                }
                return Tpb;
            }
        }
    }
}
