using System;
using System.Diagnostics;
using System.Configuration.Install;
using System.Xml ;
using System.Windows.Forms;
using Microsoft.ApplicationBlocks.Data;
using System.Data.SqlClient;

namespace InstallerActions.Install
{
	/// <summary>
	/// Summary description for Database.
	/// </summary>
	public class DataBaseInstaller
	{
		string serverName=null;
		string databaseName =null;
		string userName=null;
		string Password=null;
		bool trustedconnection=false;
		string targetPath=null;
		XmlDocument config=null;
		public const string CONST_DATBASE_PLACEHOLDER ="<<DATABASE_NAME>>";
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="servername">Server name</param>
		/// <param name="databasename">Name of the database to create</param>
		/// <param name="username">The username to login as..</param>
		/// <param name="password">Password for the user</param>
		/// <param name="targetpath">Target directory of installation.</param>
		public DataBaseInstaller(string servername,string databasename,string username,	
			string password,string targetpath)
		{
			this.serverName =servername;
			this.databaseName=databasename;
			this.userName=username;	
			this.Password=password;
			this.targetPath=targetpath;
			//MessageBox.Show("Target path set to: " + this.targetPath.ToString());
			LoadConfigFile();
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="servername">Server name.</param>
		/// <param name="databasename">Name of the database</param>
		/// <param name="targetpath">Target directory of installation.</param>
		public DataBaseInstaller(string servername,string databasename,string targetpath)
		{
			this.serverName =servername;
			this.databaseName=databasename;
			this.trustedconnection=true;
			this.targetPath =targetpath;
			LoadConfigFile();
		}
		/// <summary>
		/// Creates the database..from the InstallationFiles.xml details
		/// </summary>
		/// <returns>true, if suceeds.</returns>
		public bool CreateDataBase()
		{
			string fileName=null;
			//MessageBox.Show("In Create Database Function.");
			try
			{
				//ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
				//processInfo.WindowStyle=ProcessWindowStyle.Normal;

				//Get the name of the file from the assembly's embedded resource.
				if(config !=null)
				{
					fileName = config.SelectSingleNode("configroot/Files/DataBase/Add/File").Attributes["name"].Value;
					//MessageBox.Show("FileName - " + fileName);
				}
				else
				{
					//Customized message..
					throw new InstallException("Configuration for database file creation missing.");
				}

				//Get arguments
				//processInfo.Arguments=GetCommonProcessArguments(fileName,"master");
					
				//EventLog.WriteEntry("DatabaseInstaller",processInfo.Arguments);
				//MessageBox.Show("Calling Populate Database Name");

				//Ajit - Call the function to open connection and execute the script as set of commands
				//This is useful for even a remote installation and does not require SQL Client to be 
				//installed on the machine from where the installation is happening.

				ExecuteScriptAsSQLCommand(fileName);

				//PopulateDatabaseNamePlaceHolder(GetFullPath(fileName));
				//Process osql = Process.Start(processInfo);
				//Wait till it is done...
				//osql.WaitForExit();
				//EventLog.WriteEntry( "DatabaseInstaller","Database created..");
				//osql.Dispose();
				MessageBox.Show("Database Created.");
				return true;
			}
			catch(Exception ex)
			{
				//Customize if required.
				//EventLog.WriteEntry("DatabaseInstaller",ex.Message,EventLogEntryType.Error) ;
				//MessageBox.Show("Will fail here as osql is not found.");
				throw new InstallException(ex.Message);
			}
		}

		/// <summary>
		/// Drops the database
		/// </summary>
		/// <returns>true, if suceeds.</returns>
		public bool DropDataBase()
		{
			string fileName=null;
			try
			{
				//ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
				//processInfo.WindowStyle=ProcessWindowStyle.Normal;
				
				//Get the name of the file from the assembly's embedded resource.
				if(config !=null)
				{
					fileName = config.SelectSingleNode("configroot/Files/DataBase/Remove/File").Attributes["name"].Value;
				}
				else
				{
					throw new InstallException("Configuration for database file creation missing.");
				}
						
				//Get arguments
				//processInfo.Arguments=GetCommonProcessArguments(fileName,"master");

				//EventLog.WriteEntry("DatabaseInstaller",processInfo.Arguments);
				//PopulateDatabaseNamePlaceHolder(GetFullPath(fileName));
				//Process osql = Process.Start(processInfo);
				//osql.WaitForExit();
				//EventLog.WriteEntry("DatabaseInstaller","Dropped database...");
				//osql.Dispose();

				//MessageBox.Show("Calling Drop Database");
				ExecuteScriptAsSQLCommand(fileName);
				MessageBox.Show("Database dropped successfully");
				return true;
			}
			catch(Exception ex)
			{
				//Customize if required.
				//EventLog.WriteEntry("DatabaseInstaller",ex.Message,EventLogEntryType.Error) ;	
				throw new InstallException(ex.Message);
			}	
		}

		/// <summary>
		/// Creates the tables..from the InstallationFiles.xml details
		/// </summary>
		/// <returns>true, if suceeds.</returns>
		public bool GrantPermissions()
		{
			string fileName=null;
			try
			{
				//ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
				//processInfo.WindowStyle=ProcessWindowStyle.Normal;
				
				//Get the name of the file from the assembly's embedded resource.
				if(config !=null)
				{
					fileName = config.SelectSingleNode("configroot/Files/Permissions/File").Attributes["name"].Value;
				}
				else
				{
					throw new InstallException("Configuration for database file creation missing.");
				}
						
				//Get arguments
				//processInfo.Arguments=GetCommonProcessArguments(fileName,"master");

				//EventLog.WriteEntry("DatabaseInstaller",processInfo.Arguments);
				//PopulateDatabaseNamePlaceHolder(GetFullPath(fileName));
				//Process osql = Process.Start(processInfo);
				//osql.WaitForExit();
				//EventLog.WriteEntry("DatabaseInstaller","Dropped database...");
				//osql.Dispose();

				//MessageBox.Show("In Grant Permissions Function.");
				ExecuteScriptAsSQLCommand(fileName);
				MessageBox.Show("Database Permissions successfully granted.");
				//ExecuteScripts("configroot/Files/Permissions/File");
				//EventLog.WriteEntry("DatabaseInstaller","Objects added...");
				return true;
			}
			catch(Exception ex)
			{
				//Customize if required.
				//EventLog.WriteEntry("DatabaseInstaller",ex.Message,EventLogEntryType.Error) ;
				throw new InstallException(ex.Message);
			}	
		}

		/// <summary>
		/// Creates the records..from the InstallationFiles.xml details
		/// </summary>
		/// <returns>true, if suceeds.</returns>
		public bool CreateRecords()
		{
			string fileName=null;
			try
			{
				//ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
				//processInfo.WindowStyle=ProcessWindowStyle.Normal;
				
				//Get the name of the file from the assembly's embedded resource.
				if(config !=null)
				{
					fileName = config.SelectSingleNode("configroot/Files/Data/File").Attributes["name"].Value;
				}
				else
				{
					throw new InstallException("Configuration for database file creation missing.");
				}
						
				//Get arguments
				//processInfo.Arguments=GetCommonProcessArguments(fileName,"master");

				//EventLog.WriteEntry("DatabaseInstaller",processInfo.Arguments);
				//PopulateDatabaseNamePlaceHolder(GetFullPath(fileName));
				//Process osql = Process.Start(processInfo);
				//osql.WaitForExit();
				//EventLog.WriteEntry("DatabaseInstaller","Dropped database...");
				//osql.Dispose();

				//MessageBox.Show("In Create Records Function.");
				ExecuteScriptAsSQLCommand(fileName);
				MessageBox.Show("Initial data loaded successfully.");
				
				//ExecuteScripts("configroot/Files/Data/File");
				//EventLog.WriteEntry("DatabaseInstaller","Records added...");
				return true;
			}
			catch(Exception ex)
			{
				//Customize if required.
				//EventLog.WriteEntry("DatabaseInstaller",ex.Message,EventLogEntryType.Error) ;
				throw new InstallException(ex.Message);
			}	
		}	
		//Get the Complete path of file.
		private string GetFullPath(string fileName)
		{
			//The destination folder for this will be the Install\scripts folder under the
			//installation root...
			//string FullPath = targetPath + @"install\Scripts\" + fileName;
			string FullPath = this.targetPath + fileName;
			return FullPath;
		}
		
		private void LoadConfigFile()
		{
				
			//System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("CustomSteps.Resources.InstallationFiles.xml");
			config=new XmlDocument();
			config.Load(GetFullPath("InstallationFiles.xml"));

			//MessageBox.Show("before loading Configuration XML File...");
			//config.Load(stream);
			//MessageBox.Show("after loading configuration XML file...");
		}

		private string PopulateDatabaseNamePlaceHolder(string fileName)
		{
			//Read the contents...
			System.IO.StreamReader reader = new System.IO.StreamReader(GetFullPath ( fileName ));   
			string content=reader.ReadToEnd();
			reader.Close();
			//MessageBox.Show("Database Name in Populate Database:" + databaseName);
			//MessageBox.Show(content);
			//Replace the placeholder with database name
			content =content.Replace(CONST_DATBASE_PLACEHOLDER,databaseName);
			//Writeback the contents
			string newFileName = "temp_" + fileName ;

			if ( System.IO.File.Exists ( GetFullPath ( newFileName ) ) )
				System.IO.File.Delete ( GetFullPath ( newFileName ) ) ; // end if

			System.IO.StreamWriter writer = new System.IO.StreamWriter(GetFullPath ( newFileName ),false);
			//MessageBox.Show(content);
			writer.Write(content);	
			writer.Flush();
			writer.Close();
			return newFileName ;
			//MessageBox.Show("Called Populate Database Name Place holder successfully.");
		}
		string GetCommonProcessArguments(string fileName, string overridendatabasename)
		{
			//Check for trusted connection...
			if(!trustedconnection)
			{
				/* Arguments configured....
					 *  osql [-S server] [-d use database name]   [-U login id] [-P password]
						[-i inputfile]  [-o outputfile]
					*/
				return " -S " + serverName + " -d " + overridendatabasename +" -U " + userName + " -P " +Password + " -i " + Char.ToString('"') +  GetFullPath(fileName) + Char.ToString('"') + " -o " + Char.ToString('"') + targetPath +  "Log.txt" + Char.ToString('"');  
			}
			else
			{
				/* Arguments configured....
					 *  osql [-S server] [-d use database name]   [-E trusted connection]
						[-i inputfile]  [-o outputfile]
					*/
				return " -S " + serverName + " -d " + overridendatabasename + " -E " + " -i " + Char.ToString('"') +  GetFullPath(fileName) + Char.ToString('"') + " -o " + Char.ToString('"') + targetPath + "Log.txt" + Char.ToString('"');  
			}
		
		}
		/// <summary>
		/// Will look for the list of files as configured and execute the same.
		/// Look for Name attribute used everywhere to make the program generic
		/// </summary>
		/// <param name="Xpath">XPath of the node to look for.</param>
		void ExecuteScripts(string Xpath)
		{
			XmlNodeList objectlist=null;
			ProcessStartInfo processInfo =new ProcessStartInfo("osql.exe");
			processInfo.WindowStyle=ProcessWindowStyle.Normal;

			//Get the name of the file from the assembly's embedded resource.
			if(config !=null)
			{
				objectlist = config.SelectNodes(Xpath);				
			}
			else
			{
				//Customized message..
				throw new InstallException("Configuration for database file creation missing.");
			}

			foreach(XmlNode objectFile in objectlist)
			{
				//Get arguments
				processInfo.Arguments=GetCommonProcessArguments(objectFile.Attributes["name"].Value,databaseName);
				//EventLog.WriteEntry("DatabaseInstaller",processInfo.Arguments);
				Process osql = Process.Start(processInfo);
				//Wait till it is done...
				osql.WaitForExit();
				//EventLog.WriteEntry( "DatabaseInstaller", objectFile.InnerText +" file executed..");
			}
			
			
		}

		private void ExecuteScriptAsSQLCommand(string fileName)
		{
			string connectionstring= "Data Source=" + serverName ;
			connectionstring+= ";Initial Catalog=" + databaseName;

			SqlConnection conn;

			if(userName!=null && userName.ToString().Length!=0)
			{
				//Here you need to test the connection...and proceed.
				conn =new SqlConnection( "Data Source=" + serverName
					+ ";Initial Catalog=master;User Id=" + userName +";Password=" + Password);
				conn.Open();
			
				connectionstring+= ";User ID=" + userName ;
				connectionstring+= ";Password=" + Password ;
			}
			else
			{
				//Here you need to test the connection...and proceed.
				conn =new SqlConnection( "Data Source=" + serverName
					+ ";Initial Catalog=master;trusted_connection=yes");
				conn.Open();
				
				connectionstring+=";Trusted_connection=yes";
			}

			//MessageBox.Show(connectionstring);
			string newFileName = PopulateDatabaseNamePlaceHolder(fileName);
			//Read the contents...
			System.IO.StreamReader reader = new System.IO.StreamReader(GetFullPath(newFileName));   
			//string content=reader.ReadToEnd();
			//reader.Close();
			
			//reader = new System.IO.StreamReader(GetFullPath(fileName));   
			//int testcounter=0;
			string readLine = "";
			string querystring = "";
			while(reader.Peek() >=0)
			{
				readLine = reader.ReadLine();
				// MessageBox.Show(readLine);

				if (readLine.Trim().ToUpper() == "GO")
				{
					//MessageBox.Show("Read Go");					
					// MessageBox.Show("Query String is " + querystring);
					SqlHelper.ExecuteNonQuery(conn, System.Data.CommandType.Text, querystring, null);
					querystring="";
				}
				else
				{
					querystring += readLine + "\n";
				}
				
				//testcounter++;

				//if (testcounter == 30)
				//{
					//break;
				//}

			}
			reader.Close();
					

//			while (content.Length > 0)
//			{
//				//Split the file at GO
//				int whereIsGo = content.IndexOf("GO");
//				//MessageBox.Show(content.Substring(0, whereIsGo));
//				SqlHelper.ExecuteNonQuery(conn, System.Data.CommandType.Text, content.Substring(0, whereIsGo), null);
//				content = content.Substring(whereIsGo + 2).Trim();
//			}
			conn.Close();
			conn.Dispose();
					
		}
	}
}
