//  
//  insimButton.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.Text;
using System.Timers;
using System.Collections;
using System.Text.RegularExpressions;


namespace ISMB
{
    public enum typExeFunc
    {
        TYPE_BUTTON,
        TYPE_TEXT
    }
    public delegate void executeButtonFunction(typExeFunc typ,LFSLapper.infoPlayer currinfoPlayer, int click, string idButton);

    public class box
    {
        public string id;
        public int secVisible;
		public bool blink = false;
        public bool isCountDownText = false;
        public DateTime VisibleToDateTime;
        public string onClick;
        public executeButtonFunction exeFunc;
        public bool isMultiLineButton = false;
        public ArrayList buttons = new ArrayList();
		public int L;
		public int T;
		public int W;
		public int H;
		public int interligne;
		public int BSTyle;
		public int typeIn;
		public string [] buttonTexts;
		public string caption;
		public int idxRotateText = 0;
		public int nbRotateText = 0;
	}
    public class msgBox
    {
        System.Collections.Hashtable hashMsgBox = new System.Collections.Hashtable();
        public bool[] isUsed = new bool[255];
        private InSim.Connect IC;
        private const int startClickID = 0;
        private const int endClickID = 240;

        public msgBox(InSim.Connect varIC)
        {
            this.IC = varIC;
        }
        public void create(string id, int UCID, int P_L, int P_T, int P_W, int P_H, int interligne, int secVisible, int P_TypeIn, int P_BSTyle, string P_caption, string P_buttonText)
        {
            create(id, UCID, P_L, P_T, P_W, P_H, interligne, secVisible, P_TypeIn, P_BSTyle, P_caption, P_buttonText,"",null);
        }
        public void create(string id, int UCID, int P_L, int P_T, int P_W, int P_H, int interligne, int secVisible, int P_TypeIn, int P_BSTyle, string P_caption, string P_buttonText, string P_onClick)
        {
            create(id, UCID, P_L, P_T, P_W, P_H, interligne, secVisible, P_TypeIn, P_BSTyle, P_caption, P_buttonText, P_onClick, null);
        }
        public void create(string id, int UCID, int P_L, int P_T, int P_W, int P_H, int interligne, int secVisible, int P_TypeIn, int P_BSTyle, string P_caption, string P_buttonText, executeButtonFunction P_exeFunc)
        {
            create(id, UCID, P_L, P_T, P_W, P_H, interligne, secVisible, P_TypeIn, P_BSTyle, P_caption, P_buttonText, "", P_exeFunc );
        }
        public void create(string id, int UCID, int P_L, int P_T, int P_W, int P_H, int interligne, int secVisible, int P_TypeIn, int P_BSTyle, string P_caption, string P_buttonText, string P_onClick, executeButtonFunction P_exeFunc)
        {

//            interligne = P_H;

            box currBox;
            if ( !hashMsgBox.ContainsKey(id) ){
				hashMsgBox[id] = new box();
	            currBox = (box)hashMsgBox[id];
			}
			currBox = (box)hashMsgBox[id];
			currBox.id = id;
            currBox.secVisible = secVisible;
            currBox.onClick = P_onClick.Replace('"',' ').Trim();
            currBox.exeFunc = P_exeFunc;
//            Console.WriteLine(currBox.onClick);
			// Overlap 8 ISM standard for blink usage. 8 is clicked button, determined by P_onClick here
			if ( ( P_BSTyle & 8 ) != 0 )
				currBox.blink = true;
			if (P_onClick != "")
				P_BSTyle = P_BSTyle | 8;
			if (P_exeFunc != null)
				P_BSTyle = P_BSTyle | 8;
			if (currBox.secVisible != -1)
                currBox.VisibleToDateTime = DateTime.Now.AddSeconds((double)secVisible-1);
            if (P_buttonText.IndexOf("%cpt%") != -1)
            {
                currBox.isCountDownText = true;
            }
			currBox.BSTyle = P_BSTyle;
			currBox.L = P_L;
			currBox.T = P_T;
			currBox.W = P_W;
			currBox.H = P_H;
			currBox.interligne = interligne;

			currBox.buttonTexts = P_buttonText.Split(new string[] { "%at%" }, StringSplitOptions.None);
			currBox.nbRotateText = currBox.buttonTexts.Length;
			currBox.idxRotateText = 0;
			currBox.typeIn = P_TypeIn;
			currBox.caption = P_caption;
			updateLibel(UCID, currBox);
        }
		private void updateLibel(int UCID, box currBox)
		{
			for (int i = 0; i < currBox.buttons.Count; i++)
				(currBox.buttons[i] as oneButton).toRemove = true;

			string[] splitStr = currBox.buttonTexts[currBox.idxRotateText].Split(new string[] { "%nl%" }, StringSplitOptions.None );
            if (splitStr.Length > 1)
            {
                currBox.isMultiLineButton = true;
                // Ajout du fond
				if ((currBox.BSTyle & 0x37) != 0)
                {
					int clickID = nextFreeButton(currBox);
					if( clickID != -1 ){
						oneButton butt = new oneButton(IC, clickID, currBox.L, currBox.T, currBox.W, (currBox.interligne * (splitStr.Length - 1)) + currBox.H, currBox.secVisible, currBox.typeIn, currBox.BSTyle, currBox.caption, "");
                        currBox.buttons.Add(butt);
                    }
                }
                for (int j = 0; j < splitStr.Length; j++)
                {
                    string str = splitStr[j];
					int clickID = nextFreeButton(currBox);
					if( clickID != -1 ){
						oneButton butt = new oneButton(IC, clickID, currBox.L, currBox.T + (j * currBox.interligne), currBox.W, currBox.H, currBox.secVisible, currBox.typeIn, currBox.BSTyle & 0xCF, currBox.caption, str);
						currBox.buttons.Add(butt);
                    }
                }
            }
            else
            {
                currBox.isMultiLineButton = false;
                string str = splitStr[0];
				int clickID = nextFreeButton(currBox);
				if( clickID != -1 ){
					oneButton butt = new oneButton(IC, clickID, currBox.L, currBox.T, currBox.W, currBox.H, currBox.secVisible, currBox.typeIn, currBox.BSTyle, currBox.caption, str);
					currBox.buttons.Add(butt);
                }
			}			
			removeNotUsedButton(UCID,currBox);
		}
		private void removeNotUsedButton(int UCID,box currBox)
		{
			for (int i = currBox.buttons.Count-1; i >= 0; i--)
			{
				if( (currBox.buttons[i] as oneButton).toRemove ){
					isUsed[(currBox.buttons[i] as oneButton).clickID] = false;
					oneButton ob = (oneButton)(currBox.buttons[i]);
					ob.hide(UCID);
					currBox.buttons.RemoveAt(i);
				}
			}
		}
		private int nextFreeButton(box currBox)
		{
			for (int i = 0; i < currBox.buttons.Count; i++)
			{
				if ((currBox.buttons[i] as oneButton).toRemove)
				{
					int clickID = (currBox.buttons[i] as oneButton).clickID;
					currBox.buttons.RemoveAt(i);
					return clickID;
				}
			}
			for (int i = startClickID; i < endClickID; i++)
			{
				if (!isUsed[i])
				{
					isUsed[i] = true;
					return i;
				}
			}
			return -1;
		}
		public void update(string id, int UCID, string P_buttonText)
        {

            if (!hashMsgBox.ContainsKey(id))
            {
                return;
            }
            box currBox = (box)hashMsgBox[id];
            string[] splitStr = P_buttonText.Split('&');
            if (splitStr.Length > 1 && currBox.isMultiLineButton )
            {
                // Ajout du fond
                for (int j = 0; j < splitStr.Length; j++)
                {
                    string str = splitStr[j];
                    int nbText = currBox.buttons.Count - 1;
                    for (int i = 1; i < nbText; i++)
                    {
                        if( i > splitStr.Length )
                            (currBox.buttons[i] as oneButton).buttonText = "";
                        else
                            (currBox.buttons[i] as oneButton).buttonText = splitStr[i-1];
                    }
                }
            }
            else
            {
                string str = splitStr[0];
                (currBox.buttons[0] as oneButton).buttonText = str;
            }
        }
        public executeButtonFunction doActionBC(int clickID, int UCID)
        {
            foreach (DictionaryEntry de in hashMsgBox)
            {
                box currBox = (box)de.Value;
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    if (ob.clickID == clickID)
                    {
                        return currBox.exeFunc;
                    }
                }
            }
            return null;
        }
        public string doAction(int clickID, int UCID)
        {
            foreach (DictionaryEntry de in hashMsgBox)
            {
                box currBox = (box)de.Value;
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    if (ob.clickID == clickID)
                    {
                        return currBox.onClick;
                    }
                }
            }
            return "";
        }
        public string getId(int clickID, int UCID)
        {
            foreach (DictionaryEntry de in hashMsgBox)
            {
                box currBox = (box)de.Value;
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    if (ob.clickID == clickID)
                    {
                        return currBox.id;
                    }
                }
            }
            return "";
        }
        public void UpdateLT(string id, int L, int T)
        {
            if (hashMsgBox.ContainsKey(id))
            {
                try
                {
                    oneButton ob = (oneButton)(hashMsgBox[id] as box).buttons[0];
                    ob.L = L;
                    ob.T = T;
                }
                catch
                {
                    
                }
            }
        }
        public void show(string id, int UCID)
        {
//            Console.WriteLine("Affichage de " + id + "/" + UCID);
            if (hashMsgBox.ContainsKey(id))
            {
                box currBox = (box)hashMsgBox[id];
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    ob.show( UCID );
                }
            }
        }
        public void hide(string id, int UCID)
        {
            if (hashMsgBox.ContainsKey(id))
            {
                box currBox = (box)hashMsgBox[id];
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    ob.hide( UCID );
                }
            }
        }
        public void doCountDown(string id, int UCID)
        {
            if (hashMsgBox.ContainsKey(id))
            {
                box currBox = (box)hashMsgBox[id];
                TimeSpan tp = currBox.VisibleToDateTime - DateTime.Now;
                int nbSec = (int)tp.TotalSeconds+1;
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    if (ob.isCountDownText && ob.lastCountDown != nbSec )
                    {
                        ob.buttonText = ob.origButtonText.Replace("%cpt%", nbSec.ToString());
                        ob.updateText(UCID);
                    }
                }
            }
        }
		public void doBlink(string id, int UCID, bool blinkVisible )
		{
			//            Console.WriteLine("Effacement de " + id + "/" + UCID);
			if (hashMsgBox.ContainsKey(id))
			{
				if( !blinkVisible )
					this.hide(id, UCID);
				else
					this.show(id, UCID);
			}
		}
		public void delete(string id, int UCID)
        {
//            Console.WriteLine("Effacement de " + id + "/" + UCID);
            if (hashMsgBox.ContainsKey(id))
            {

                box currBox = (box)hashMsgBox[id];

                this.hide(id, UCID);
                for (int i = 0; i < currBox.buttons.Count; i++)
                {
                    isUsed[(currBox.buttons[i] as oneButton).clickID] = false;
                    oneButton ob = (oneButton)(currBox.buttons[i]);
                    ob.hide(UCID);
                }
                hashMsgBox.Remove(id);
            }
        }
        public void loopButton( LFSLapper.infoPlayer currInfoPlayer , Configurator.lexConfigurator newCfg, bool blinkVisible )
        {
            bool flagRem;
//            Console.WriteLine("");
            while (true)
            {
                flagRem = false;
                foreach (DictionaryEntry de in hashMsgBox)
                {
                    box currBox = (box)de.Value;
					if (currBox.nbRotateText != 1)
					{
						currBox.idxRotateText += 1;
						if (currBox.idxRotateText + 1 > currBox.nbRotateText)
							currBox.idxRotateText = 0;
						updateLibel(currInfoPlayer.UCID, currBox);
						this.show(currBox.id, currInfoPlayer.UCID);
					}
					if( currBox.blink )
						this.doBlink(currBox.id, currInfoPlayer.UCID, blinkVisible);
                    if (currBox.secVisible != -1)
                    {
                        if( currBox.isCountDownText )
                            this.doCountDown(currBox.id, currInfoPlayer.UCID);
                        if (DateTime.Now >= currBox.VisibleToDateTime)
                        {
                            this.delete(currBox.id, currInfoPlayer.UCID);
                            flagRem = true;
                            if (currBox.onClick != "")
                            {
                                string[] par = new string[2];
                                par[0] = "1"; // Simulate a Left click
                                par[1] = currBox.id; // Simulate a Left click
                                newCfg.executeFunction(currBox.onClick, currInfoPlayer, par);
                                break;
                            }
                            if (currBox.exeFunc != null)
                            {
                                currBox.exeFunc( typExeFunc.TYPE_BUTTON, currInfoPlayer, 1, currBox.id);
                                break;
                            }
                            break;
                        }
                    }
                }
                if (!flagRem)
                    break;
            }

        }
        public string[] listOfbutton()
        {
            ArrayList lob = new ArrayList();
            foreach (DictionaryEntry de in hashMsgBox)
                lob.Add((de.Value as box).id );
            return (string[])lob.ToArray(typeof(string));         
        }
        public void deleteAllButton( LFSLapper.infoPlayer currInfoPlayer , Configurator.lexConfigurator newCfg )
        {
            bool flagRem;
//            Console.WriteLine("");
            while (true)
            {
                flagRem = false;
                foreach (DictionaryEntry de in hashMsgBox)
                {
                    box currBox = (box)de.Value;

                    this.delete(currBox.id, currInfoPlayer.UCID);
                    flagRem = true;
                    break;
                }
                if (!flagRem)
                    break;
            }

        }

    }
    class oneButton
    {
        InSim.Connect insimConnection;
        static int sendedButton = 0;

        public int T = 0;
        public int L = 0;
        public int W = 10;
        public int H = 30;
        public int nbBlink = -1;
        public int clickID = -1;
        bool isShowed = false;
        public bool isCountDownText = false;
        public int lastCountDown = 0;
        public int BStyle = (int)InSim.BTN_style.ISB_LIGHT;
        public int TypeIn = 0;
        public string origButtonText = "Not initialised";
        public string buttonText = "Not initialised";
        public string oldButtonText = "Not initialised";
        public string caption = "Not initialised";
		public bool toRemove = false;
        InSim.Encoder myEncoder = new InSim.Encoder();

        
        public oneButton( InSim.Connect IC, int id, int P_L, int P_T, int P_W, int P_H, int secVisible, int P_TypeIn, int P_BSTyle, string P_caption, string P_buttonText )
        {
            this.L = P_L;
            this.T = P_T;
            this.W = P_W;
            this.H = P_H;
            this.TypeIn = P_TypeIn;
            this.BStyle = P_BSTyle;
            this.caption = P_caption;
            this.origButtonText = P_buttonText;
            this.buttonText = P_buttonText;
            this.insimConnection = IC;
            this.isShowed = false;
            this.clickID = id;
			this.toRemove = false;
            if (P_buttonText.IndexOf("%cpt%") != -1 && secVisible != -1)
            {
                this.isCountDownText = true;
                this.lastCountDown = secVisible;
                this.buttonText = this.buttonText.Replace("%cpt%", secVisible.ToString());
            }


        }
        public void updateText( int UCID )
        {
            if (this.oldButtonText != this.buttonText || this.isShowed == false)
            {
                this.oldButtonText = this.buttonText;
                this.show( UCID );
            }
        }
        public void show(int P_UCID)
        {
            this.lshow(P_UCID);
            this.isShowed = true;
        }
        void lshow(int P_UCID)
        {
            if (sendedButton % 30 == 0)
            {
                sendedButton = 0;
                System.Threading.Thread.Sleep(100);
            }
            sendedButton++;
            byte[] btn = myEncoder.BTN(1, this.L, this.T, this.W, this.H, P_UCID, this.clickID, this.BStyle, this.TypeIn, this.caption, this.buttonText);
            insimConnection.Send(btn, btn.Length);
        }
        public void lhide(int P_UCID)
        {
            if (this.isShowed)
            {
                System.Threading.Thread.Sleep(1);
                byte[] bfn = myEncoder.BFN(0, 0, P_UCID, this.clickID);
                insimConnection.Send(bfn, bfn.Length);
            }
        }
        public void hide(int P_UCID)
        {
            this.lhide(P_UCID);
            this.isShowed = false;
        }
    }
}
