using Pervasive.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Common
{
    public static class CommonUtility
    {
        /// <summary>
        /// Cleans up the Database before running the sample
        /// This method is introduced to overcome few shortcomings of SetInitializer DropAndCreateDatabaseAlways
        /// </summary>
        public static void CleanUpDB(IEnumerable<string> DbObjectNames, DbObjectType dbObjectType)
        {
            try
            {
                Console.WriteLine("\tReading connection string from app.config...");
                var document = XDocument.Load(AppDomain.CurrentDomain.FriendlyName + ".config");
                string connectionString = document.Element("configuration")
                    .Element("connectionStrings")
                    .Elements("add")
                    .Select(c => c.Attribute("connectionString").Value).FirstOrDefault();
                if (string.IsNullOrWhiteSpace(connectionString))
                {
                    throw new Exception("Could not read connection string from app.config. Database clean up will not continue");
                }
                Console.WriteLine("\tRead connection string from app.config.\n");

                Console.WriteLine("\tEstablishing connection...");
                PsqlConnection connection = new PsqlConnection(connectionString);
                connection.Open();
                Console.WriteLine("\tConnection established.\n");

                PsqlCommand command = null;

                string objectType = dbObjectType == DbObjectType.Table ? "Table" : "Procedure";

                foreach (string Name in DbObjectNames)
                {
                    try
                    {
                        Console.WriteLine("\tDropping " + objectType + " " + Name + "...");
                        command = new PsqlCommand("DROP " + objectType.ToUpper() + " \"" + Name + "\"");
                        command.Connection = connection;
                        command.ExecuteNonQuery();
                        Console.WriteLine("\t" + objectType + " " + Name + " dropped successfully.\n");
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message.Contains("No such table or object."))
                        {
                            Console.WriteLine("\tTable deletion failed as, it does not exist.\n");
                        }
                        else
                        {
                            ProcessExceptionMessage(ex);
                        }
                    }
                }

                command.Dispose();
                command = null;

                Console.WriteLine("\tClosing connection...");
                connection.Close();
                Console.WriteLine("\tConnection closed.\n");
            }
            catch (Exception ex)
            {
                ProcessExceptionMessage(ex);
            }
        }

        /// <summary>
        /// This check is done to make sure a sample is compelled to be run against a Actian Zen database of given version or higher
        /// </summary>
        /// /// <param name="minDbVersion">Minimum Allowed major version of database</param>
        public static void CheckDatabaseVersion(int minDbVersion)
        {
            try
            {
                Console.WriteLine("\tReading connection string from app.config...");
                var document = XDocument.Load(AppDomain.CurrentDomain.FriendlyName + ".config");
                string connectionString = document.Element("configuration")
                    .Element("connectionStrings")
                    .Elements("add")
                    .Select(c => c.Attribute("connectionString").Value).FirstOrDefault();
                if (string.IsNullOrWhiteSpace(connectionString))
                {
                    throw new Exception("Could not read connection string from app.config. Database clean up will not continue");
                }
                Console.WriteLine("\tRead connection string from app.config.\n");

                Console.WriteLine("\tEstablishing connection...");
                PsqlConnection connection = new PsqlConnection(connectionString);
                connection.Open();
                Console.WriteLine("\tConnection established.\n");

                int serverMainVersion = Convert.ToInt32(connection.ServerVersion.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries)?[0]);

                Console.WriteLine("\tClosing connection...");
                connection.Close();
                Console.WriteLine("\tConnection closed.\n");

                if (serverMainVersion < minDbVersion)
                {
                    throw new Exception("This sample must be run against a Actian Zen database of version v" + minDbVersion + " or higher");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Exception occurred while checking the database version.", ex);
            }
        }

        /// <summary>
        /// Writes Exception messages to console.
        /// If Exception contains inner exception(s) then
        /// logs all inner exception messages to console
        /// </summary>
        /// <param name="ex"></param>
        public static void ProcessExceptionMessage(Exception ex)
        {
            Console.WriteLine("Exception occurred !!!");
            while (ex != null && !String.IsNullOrWhiteSpace(ex.Message))
            {
                Console.Write("-->");
                Console.WriteLine(ex.Message);
                ex = ex.InnerException;
            }

        }
    }
}
