//  
//  TrackInfo.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 Configurator;
namespace LFSLapper
{

    class trackCarData
    {
        public string[] splitAction = new string[(int) paramLapper.maxSplit];
        public string lapTimeAction;
        class carInfo
        {
            public string[] splitAction = new string[(int)paramLapper.maxSplit];
            public bool[] splitActionSet = new bool[(int)paramLapper.maxSplit];
            public string[] split = new string[(int)paramLapper.maxSplit];
            public long MaxLapTime;
            public string lapTimeAction;
            public string LapTime;
            
            public carInfo()
            {
                for (int i = 0; i < (int)paramLapper.maxSplit; i++)
                {
                    this.split[i] = "";
                    this.splitAction[i] = "";
                    this.splitActionSet[i] = false;
                    this.MaxLapTime = unitConv.HMSToLong("30.00.00");
                }
                this.lapTimeAction = "";
                this.LapTime = "";
            }
        }
        class trackInfo
        {
            public Double len;
            public System.Collections.Hashtable carTable = new System.Collections.Hashtable();
            public trackInfo()
            {
                this.len = 0;
            }
        }
        System.Collections.Hashtable trackTable = new System.Collections.Hashtable();
        System.Collections.Hashtable carTable = new System.Collections.Hashtable();

        public bool load(string filePath)
        {
            string readLine;
            string currTrack = null;
            string currCar = null;
            int lineCounter = 0;
            string key;
            string val;
            int idxSplit;

            for (int i = 0; i < (int)paramLapper.maxSplit; i++)
                this.splitAction[i] = "";

            if (filePath == "")
                return false; ;
            {
                try
                {
                    using (System.IO.StreamReader sr = new System.IO.StreamReader(filePath))
                    {
                        while (true)
                        {
                            lineCounter++;
                            readLine = sr.ReadLine();
                            if (readLine == null)
                                return true;
                            readLine = readLine.Replace("\t", "").Trim();
                            if (readLine.Length == 0)
                                continue;
                            if (readLine[0] == '#') //skip comments
                                continue;
                            int index = readLine.IndexOf('='); //look for first "="
                            if (index == -1)
                                throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (can not find '=' symbol)", filePath, readLine, lineCounter));
                            key = readLine.Substring(0, index);
                            val = readLine.Substring(index + 1);
                            key = key.ToLower().Trim();
                            val = val.Trim();
                            if (key.IndexOf("laptimeaction") != -1)
                            {
                                if (currTrack == null || currCar == null)
                                {
                                    this.lapTimeAction = val;
                                    continue;
                                }
                                if (!this.trackTable.ContainsKey(currTrack))
                                {
                                    this.trackTable[currTrack] = new trackInfo();
                                }
                                if (!(this.trackTable[currTrack] as trackInfo).carTable.ContainsKey(currCar))
                                {
                                    (this.trackTable[currTrack] as trackInfo).carTable[currCar] = new carInfo();
                                }
                                ((this.trackTable[currTrack] as trackInfo).carTable[currCar] as carInfo).lapTimeAction = val;
                            }
                            else if (key.IndexOf("action") != -1)
                            {
                                key = key.Replace("action", "");
                                idxSplit = int.Parse(key.Substring(5)) - 1;
                                if (idxSplit >= (int)paramLapper.maxSplit)
                                {
                                    throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (idx of split to high)", filePath, readLine, lineCounter));
                                }
                                if (currTrack == null || currCar == null)
                                {
                                    this.splitAction[idxSplit] = val;
                                    continue;
                                }
                                if (!this.trackTable.ContainsKey(currTrack))
                                {
                                    this.trackTable[currTrack] = new trackInfo();
                                }
                                if (!(this.trackTable[currTrack] as trackInfo).carTable.ContainsKey(currCar))
                                {
                                    (this.trackTable[currTrack] as trackInfo).carTable[currCar] = new carInfo();
                                }
                                ((this.trackTable[currTrack] as trackInfo).carTable[currCar] as carInfo).splitAction[idxSplit] = val;
                                ((this.trackTable[currTrack] as trackInfo).carTable[currCar] as carInfo).splitActionSet[idxSplit] = true;
                            }
                            else if (key.IndexOf("split") != -1)
                            {
                                idxSplit = int.Parse(key.Substring(5)) - 1;
                                if (idxSplit >= (int)paramLapper.maxSplit)
                                {
                                    throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (idx of split to high)", filePath, readLine, lineCounter));
                                }
                                if (currTrack == null || currCar == null)
                                    throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (Car or track no set)", filePath, readLine, lineCounter));
                                if (!this.trackTable.ContainsKey(currTrack))
                                {
                                    this.trackTable[currTrack] = new trackInfo();
                                }
                                if (!(this.trackTable[currTrack] as trackInfo).carTable.ContainsKey(currCar))
                                {
                                    (this.trackTable[currTrack] as trackInfo).carTable[currCar] = new carInfo();
                                }
                                // Wrong format time
                                if (unitConv.isTime(val) == false)
                                {
                                    throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (Wrong format Time need m:ss:hh)", filePath, readLine, lineCounter));
                                }
                                ((this.trackTable[currTrack] as trackInfo).carTable[currCar] as carInfo).split[idxSplit] = val;
                            }
                            else
                            {
                                switch (key)
                                {
                                    case "track":
                                        currTrack = val;
                                        break;
                                    case "car":
                                        currCar = val;
                                        break;
                                    case "len":
                                        if (currTrack == null)
                                            throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (Track no set)", filePath, readLine, lineCounter));
                                        val = val.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator);
                                        if (!this.trackTable.ContainsKey(currTrack))
                                            this.trackTable[currTrack] = new trackInfo();
                                        try
                                        {
                                            (this.trackTable[currTrack] as trackInfo).len = double.Parse(val);
                                        }
                                        catch { }
                                        break;
                                    case "maxlaptime":
                                        if (currTrack == null || currCar == null)
                                        {
                                            throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (Track or/and Car no set)", filePath, readLine, lineCounter));
                                        }
                                        if (!this.trackTable.ContainsKey(currTrack))
                                        {
                                            this.trackTable[currTrack] = new trackInfo();
                                        }
                                        if (!(this.trackTable[currTrack] as trackInfo).carTable.ContainsKey(currCar))
                                        {
                                            (this.trackTable[currTrack] as trackInfo).carTable[currCar] = new carInfo();
                                        }
                                        ((this.trackTable[currTrack] as trackInfo).carTable[currCar] as carInfo).MaxLapTime = unitConv.HMSToLong(val);
                                        break;
                                    case "laptime":
                                        if (currTrack == null || currCar == null)
                                        {
                                            throw new System.Exception(string.Format("Corrupted line #{2} ('{1}') in file {0} (Track or/and Car no set)", filePath, readLine, lineCounter));
                                        }
                                        if (!this.trackTable.ContainsKey(currTrack))
                                        {
                                            this.trackTable[currTrack] = new trackInfo();
                                        }
                                        if (!(this.trackTable[currTrack] as trackInfo).carTable.ContainsKey(currCar))
                                        {
                                            (this.trackTable[currTrack] as trackInfo).carTable[currCar] = new carInfo();
                                        }
                                        ((this.trackTable[currTrack] as trackInfo).carTable[currCar] as carInfo).LapTime = val;
                                        break;

                                }
                            }
                        }
                    }
                }
                catch
                {
                    return false;
                }
            }
        }
/*
        public double getLen( string track )
        {
            if (track == "" || track == null )
                return 0;
            if (this.trackTable.ContainsKey(track))
                return (this.trackTable[track] as trackInfo).len;
            else
                return 0;
        }
 */
        public string getSplitAction(string track, string car, int splitNumber, long STime)
        {
            carInfo ci;
            string retVal = "";

            if (track == "" || track == null)
                goto fin;
            if (car == "" || car == null)
                goto fin;
            if (this.trackTable.ContainsKey(track))
            {
                if ((this.trackTable[track] as trackInfo).carTable.ContainsKey(car))
                    ci = ((this.trackTable[track] as trackInfo).carTable[car] as carInfo);
                else
                    goto fin;
            }
            else
                goto fin;
// If no split Set
            if (ci.split[splitNumber - 1] == "")
            {
                goto fin;
            }
//Explode all split test
            string[] arSplit = ci.split[splitNumber - 1].Split(':');
//Explode all action and select the appropriate action
            string[] arSplitAction;
            if (ci.splitActionSet[splitNumber - 1])
                arSplitAction = ci.splitAction[splitNumber - 1].Split(':');
            else
                arSplitAction = this.splitAction[splitNumber - 1].Split(':');
            
            for (int i = 0; i <= arSplit.GetUpperBound(0); i++)
            {
                if (STime <= unitConv.HMSToLong(arSplit[i]))
                {
                    try
                    {
                        retVal = arSplitAction[i];
                        goto fin;
                    }
                    catch { goto fin; }
                }
            }
fin:
//            Console.WriteLine("Temp : " + track + "/" + car + " " + unitConv.LongToHMS( STime ) + " Action : >" + retVal + "<" );

            return retVal;
        }
        public string getLapAction(string track, string car, long STime)
        {
            carInfo ci;
            string retVal = "";

            if (track == "" || track == null)
                goto fin;
            if (car == "" || car == null)
                goto fin;
            if (this.trackTable.ContainsKey(track))
            {
                if ((this.trackTable[track] as trackInfo).carTable.ContainsKey(car))
                    ci = ((this.trackTable[track] as trackInfo).carTable[car] as carInfo);
                else
                    goto fin;
            }
            else
                goto fin;
            // If no split Set
            if (ci.LapTime == "")
            {
                goto fin;
            }
            //Explode all split test
            string[] arLap = ci.LapTime.Split(':');
            //Explode all action and select the appropriate action
            string[] arLapTimeAction;
            if ( ci.lapTimeAction != "" )
                arLapTimeAction = ci.lapTimeAction.Split(':');
            else
                arLapTimeAction = this.lapTimeAction.Split(':');

            for (int i = 0; i <= arLap.GetUpperBound(0); i++)
            {
                if (STime <= unitConv.HMSToLong(arLap[i]))
                {
                    try
                    {
                        retVal = arLapTimeAction[i];
                        goto fin;
                    }
                    catch { goto fin; }
                }
            }
        fin:
//                        Console.WriteLine("Temp : " + track + "/" + car + " " + unitConv.LongToHMS( STime ) + " Action : >" + retVal + "<" );

            return retVal;
        }
        public double getAvgSpeed(string track, long STime)
        {
            double retVal = 0;

            if (track == "" || track == null)
                goto finavg;
            if (this.trackTable.ContainsKey(track))
            {
                try
                {
                    retVal = ((double)(this.trackTable[track] as trackInfo).len * unitConv.HMSToLong("60.00.00") )/ STime;
                    goto finavg;
                }
                catch
                {
                    goto finavg;
                }
            }
        finavg:

            return retVal;
        }
        public long getMaxLapTime(string track, string car)
        {
            long retVal = unitConv.HMSToLong( "30.00.00" );

            if (track == "" || track == null)
                goto finavg;
            if (this.trackTable.ContainsKey(track))
            {
                if ((this.trackTable[track] as trackInfo).carTable.ContainsKey(car))
                {
                    carInfo ci = ((this.trackTable[track] as trackInfo).carTable[car] as carInfo);
                    retVal = ci.MaxLapTime;
                }
            }
        finavg:
//            Console.WriteLine("MaxLapTime : " + track + "/" + car + " " + unitConv.LongToHMS( retVal ));
            return retVal;
        }
    }
}