//  
//  setOfLapperInstance.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.Threading;
using System.IO;

namespace LapperInstances
{
    public class infoInstance
    {
        public enum autoStartVal
        {
            AUTO_NONE,
            AUTO_STBY,
            AUTO_WORK,
        }
        public string name;
        public string groupId;
        public string ip;
        public int port;
        public string workingDir;
        public string iniFile;
        public autoStartVal autoStart = autoStartVal.AUTO_NONE;
		public string password;
		public string superUsers;
        public int CountInstances;

        public infoInstance(string pname, string pgroupId, string pip, int pport, string pworkingDir, string piniFile, autoStartVal pautoStart, string ppassword, string pSuperUsers)
        {
            this.name = pname;
            this.groupId = pgroupId;
            this.ip = pip;
            this.port = pport;
            this.workingDir = pworkingDir;
            this.iniFile = piniFile;
            this.autoStart = pautoStart;
            this.password = ppassword;
			this.superUsers = pSuperUsers;
        }
    }

    public class setOfLapperInstances
    {
        const int refreshIn = 10;
        //        static System.Timers.Timer timerManageInstances;
        Thread setOfLapperInstanceThread;
        public Hashtable listOfLapperInstance = new Hashtable();
		Hashtable lastListOfLapperInstance = new Hashtable();
		private DateTime LFSServersLastWriteTime = DateTime.Now.AddDays(20);
		GLDebug.Debug myDebug;

        public setOfLapperInstances( GLDebug.Debug pmyDebug )
        {
			myDebug = pmyDebug;
			this.setOfLapperInstanceThread = new Thread(new ThreadStart(this.threadManageInstances));
			this.setOfLapperInstanceThread.Start();
        }
        public void stopAll()
        {
            foreach (DictionaryEntry de in listOfLapperInstance)
            {
                LapperInstance currLFSInstance = (LapperInstance)de.Value;
				currLFSInstance.stopLapperInstance();
                
            }
            setOfLapperInstanceThread.Abort();
			setOfLapperInstanceThread.Join();
        }
		public status getStatus(string idOfInstance)
		{
			Hashtable listOFLFSInstance = getListOfLapperInstanceFromFile();
			if (listOFLFSInstance.ContainsKey(idOfInstance))
			{
				LapperInstance tmp;
				tmp = (LapperInstance)listOfLapperInstance[idOfInstance];
				return tmp.currentStatus;
			}
			return 0;
		}
        
        public infoInstance goWorkMode(string idOfInstance)
		{
			if (listOfLapperInstance.ContainsKey(idOfInstance))
			{
				LapperInstance tmp;
				tmp = (LapperInstance)listOfLapperInstance[idOfInstance];
				tmp.infos.autoStart = infoInstance.autoStartVal.AUTO_WORK;
				return tmp.infos;
			}
			return null;
		}

        public infoInstance gostandbymode(string idOfInstance)
        {
            if (listOfLapperInstance.ContainsKey(idOfInstance))
            {
                LapperInstance tmp;
                tmp = (LapperInstance)listOfLapperInstance[idOfInstance];
                tmp.infos.autoStart = infoInstance.autoStartVal.AUTO_STBY;
                tmp.goStbMode();
                return tmp.infos;
            }
            return null;
        }



        public infoInstance goAutoNoneMode(string idOfInstance)
		{
			if (listOfLapperInstance.ContainsKey(idOfInstance))
			{
				LapperInstance tmp;
				tmp = (LapperInstance)listOfLapperInstance[idOfInstance];
                tmp.infos.autoStart = infoInstance.autoStartVal.AUTO_NONE;
                tmp.goAutoNoneMode();
                return tmp.infos;
			}
			return null;
		}

        public Hashtable getListOfLapperInstanceFromFile()
        {

            Hashtable listOfLapperInstance = new Hashtable();
            string name = "";
            string workingDir = "";
            string iniFile = "";
            string password = "";
            string superUsers = "";

            if (!File.Exists("LFSServers.cfg"))
                throw (new System.Exception("Error: LFSServers.cfg config file do not exist!"));
            {
                StreamReader sr = new StreamReader("LFSServers.cfg");
                while (!sr.EndOfStream)
                {

                    string line = sr.ReadLine();
                    if (line.Trim() == "")
                        continue;
                    if (line[0] == '#')
                        continue;
					if (line.ToLower().IndexOf("remoteport") == 0 || line.ToLower().IndexOf("timeoutscript") == 0)
                        continue;
                    line = line + "|||||";
                    string[] arg = line.Split('|');
                    // Find the password of the LFS Server
                    try
                    {
                        name = arg[0].ToString();
                        workingDir = arg[4].ToString();
                        iniFile = arg[5].ToString();
                        createWorkingDir(workingDir, iniFile);
                        infoInstance.autoStartVal autostart = infoInstance.autoStartVal.AUTO_NONE;
                        if (arg[6].ToLower() == "autostart")                   
                            autostart = infoInstance.autoStartVal.AUTO_STBY;
                        else if (arg[6].ToLower() == "autowork")
                            autostart = infoInstance.autoStartVal.AUTO_WORK;

                        try
                        {
                            LFSLapper.readIni myReadIni = new LFSLapper.readIni(workingDir, iniFile);
                            password = myReadIni.password;
							superUsers = myReadIni.superUsers;
                        }
                        catch
                        {
                            password = "";
							superUsers = "";
                        }

                        // Send error message if there is no password defined
                        if (password == "")
                        {
                            Console.WriteLine("Password not defined for Lapper instance:  " + name + "");
                            Console.WriteLine("Check password in '" + workingDir + "/" + iniFile + "' and restart Lapper");
                            autostart = infoInstance.autoStartVal.AUTO_NONE;
                        }

                        listOfLapperInstance[arg[0]] = new infoInstance(arg[0], arg[1], arg[2], int.Parse(arg[3]), arg[4], arg[5], autostart,password,superUsers);

                    }
                    catch
                    {
                        throw (new System.Exception("Error in LFSServers.cfg file, wrong format"));
                    }
                }
                sr.Close();
            }

            //Count number of instances
            if(listOfLapperInstance.Count > 1)
            {
                Console.Title = "LFSLapper V" + LFSLapper.LFSLapper.getShortVersion(4) + " - Multiple connected servers";
            }
            return listOfLapperInstance;

        } 

            void createWorkingDir(string workingDir, string iniFile )
        {
            if (!Directory.Exists(workingDir))
            {
                CopyDir("defaultfiles/workingdir", ".");
                Directory.Move("workingdir", workingDir);
                File.Delete(workingDir + "/defaultini.ini");
            }
            if( !File.Exists( workingDir + "/" + iniFile ) )
                File.Copy("defaultfiles/workingdir/defaultini.ini", workingDir + "/" + iniFile);
        }
        private void CopyDir(string sourceDir, string destDir)
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDir); 
            if (dir.Exists)
            {
                string realDestDir;
                if (dir.Root.Name != dir.Name)
                {
                    realDestDir = Path.Combine(destDir, dir.Name);
                    if (!Directory.Exists(realDestDir))
                        Directory.CreateDirectory(realDestDir);
                }
                else realDestDir = destDir;
                foreach (string d in Directory.GetDirectories(sourceDir))
                    CopyDir(d, realDestDir);
                foreach (string file in Directory.GetFiles(sourceDir))
                {

                    string fileNameDest = Path.Combine(realDestDir, Path.GetFileName(file));
                    //if (!File.Exists(fileNameDest))

                    File.Copy(file, fileNameDest, true);
                }
            }
        }
        void threadManageInstances()
        {
            System.Globalization.CultureInfo oldCult = System.Threading.Thread.CurrentThread.CurrentCulture;
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
			myDebug.WriteLine("mss", "Start set of instances thread");
			while (true)
			{
				FileInfo f = new FileInfo("LFSServers.cfg");
				if (f.LastWriteTime != LFSServersLastWriteTime)
				{
					LFSServersLastWriteTime = f.LastWriteTime;

					Hashtable newListOfLFSInstance = getListOfLapperInstanceFromFile();
					ArrayList toRemove = new ArrayList();
					// Remove instance deleted in config file
					foreach (DictionaryEntry de in listOfLapperInstance)
					{
						LapperInstance currLFSInstance = (LapperInstance)de.Value;
						//Removed entry from list file
						if (!newListOfLFSInstance.ContainsKey(currLFSInstance.infos.name))
						{
							currLFSInstance.stopLapperInstance();
							toRemove.Add(currLFSInstance.infos.name);
						}
					}
					for (int i = 0; i < toRemove.Count; i++)
						listOfLapperInstance.Remove((string)toRemove[i]);

					// Add new instance in config file
					foreach (DictionaryEntry de in newListOfLFSInstance)
					{
						infoInstance myInfos = (infoInstance)de.Value;
						if (!listOfLapperInstance.ContainsKey(myInfos.name))
							listOfLapperInstance[myInfos.name] = new LapperInstance(myInfos);
					}
					lastListOfLapperInstance = (Hashtable)newListOfLFSInstance.Clone();
				}

				// Find All command from all client
				foreach (DictionaryEntry de in listOfLapperInstance)
				{
					LapperInstance currLFSInstance = (LapperInstance)de.Value;
					if (currLFSInstance.myClient != null)
					{
						try
						{
							string outCmd = (string)currLFSInstance.myClient.outgoingCmdStack.Dequeue();
							sendCmdToGroupOfInstance(currLFSInstance.infos.groupId, outCmd);
						}
						catch
						{
						}
					}
				}

				System.Threading.Thread.CurrentThread.CurrentCulture = oldCult;
				System.Threading.Thread.Sleep(1000);
			}
        }

        public void sendCmdToGroupOfInstance(string group, string cmd)
        {
            foreach (DictionaryEntry de in listOfLapperInstance)
            {
                LapperInstance currLFSInstance = (LapperInstance)de.Value;
                if ( currLFSInstance.myClient != null )
                {
                    if (group == "" || group == currLFSInstance.infos.groupId)
                        currLFSInstance.myClient.incommingCmdStack.Enqueue(cmd);
                }
            }

        }
    }
}
