using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.IO;

namespace SingleInstance
{
	/// <summary>
	/// Summary description for SingleApp.
	/// </summary>
	public class SingleApplication
	{
		public SingleApplication()
		{

		}
		/// <summary>
		/// Imports 
		/// </summary>
	
		[DllImport("user32.dll")]
		private static extern int ShowWindow(IntPtr hWnd, int nCmdShow);

		[DllImport("user32.dll")]
		private static extern int SetForegroundWindow(IntPtr hWnd);

		[DllImport("user32.dll")]
		private static extern int IsIconic(IntPtr hWnd);

		/// <summary>
		/// GetCurrentInstanceWindowHandle
		/// </summary>
		/// <returns></returns>
		private static IntPtr GetCurrentInstanceWindowHandle()
		{    
			IntPtr hWnd = IntPtr.Zero;
			Process process = Process.GetCurrentProcess();
			Process[] processes = Process.GetProcessesByName(process.ProcessName);

            //Process[] processes = System.Diagnostics.Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location));
            //int cnt = processes.Length;

            //MessageBox.Show(process.Id.ToString() + " " + process.MainModule.FileName);

			foreach(Process _process in processes)
			{
				// Get the first instance that is not this instance, has the
				// same process name and was started from the same file name
				// and location. Also check that the process has a valid
				// window handle in this session to filter out other user's
				// processes.

                //MessageBox.Show(_process.Id.ToString() + " " + _process.MainWindowHandle.ToString() + " " + _process.MainModule.FileName);

				if (_process.Id != process.Id /*&&
					_process.MainModule.FileName == process.MainModule.FileName &&
					_process.MainWindowHandle != IntPtr.Zero*/)    
				{
                    if (_process.MainWindowHandle == IntPtr.Zero)
                    {
                        //Thread.Sleep(100);
                        //_process.Refresh();
                    }

					hWnd = _process.MainWindowHandle;
 
					break;
				}
			}
			return hWnd;
		}
		/// <summary>
		/// SwitchToCurrentInstance
		/// </summary>
		private static void SwitchToCurrentInstance()
		{    
			IntPtr hWnd = GetCurrentInstanceWindowHandle();
            if (hWnd != IntPtr.Zero)
            {
                // Restore window if minimised. Do not restore if already in
                // normal or maximised window state, since we don't want to
                // change the current state of the window.
                if (IsIconic(hWnd) != 0)
                {
                    ShowWindow(hWnd, SW_RESTORE);
                }

                // Set foreground window.
                SetForegroundWindow(hWnd);
            }
            else
            {
                MessageBox.Show("Warning: an instance of the application is already running, and hiding in the right-bottom tray!\n\nYou can right click the icon, and choose 'Pop out' to bring it up.", "VoIP Recorder");
            }
		}

		/// <summary>
		/// Execute a form base application if another instance already running on
		/// the system activate previous one
		/// </summary>
		/// <param name="frmMain">main form</param>
		/// <returns>true if no previous instance is running</returns>
		public static bool Run(System.Windows.Forms.Form frmMain)
		{
			if(IsAlreadyRunning())
			{
				//set focus on previously running app
				SwitchToCurrentInstance();
				return false;
			}
			Application.Run(frmMain);
			return true;
		}

		/// <summary>
		/// for console base application
		/// </summary>
		/// <returns></returns>
		public static bool Run()
		{
			if(IsAlreadyRunning()) 
			{
				return false;
			}
			return true;
		}

		/// <summary>
		/// check if given exe alread running or not
		/// </summary>
		/// <returns>returns true if already running</returns>
		private static bool IsAlreadyRunning()
		{
			string strLoc = Assembly.GetExecutingAssembly().Location;
			FileSystemInfo fileInfo = new FileInfo(strLoc);
			string sExeName = fileInfo.Name;
			bool bCreatedNew;

			mutex = new Mutex(true, "Global\\"+sExeName, out bCreatedNew);
			if (bCreatedNew)
				mutex.ReleaseMutex();

			return !bCreatedNew;
		}
		
		static Mutex mutex;
		const int SW_RESTORE = 9;
	}
}
