using System;
using System.Data;
using System.Configuration;
using System.Data.Common;
using System.Web.Configuration;


/// <summary>
/// Zawiera większość funkcji ADO.NET potrzebnych w klasach 
/// dostępu do danych
/// </summary>
public abstract class AbstractDA
{

   /// <summary>
   /// Zwraca wszystkie dane ze źródła danych
   /// </summary>
   public DataTable GetAll()
   {
      string sql = SelectStatement;
      return GetDataTable(sql, null);
   }

   /// <summary>
   /// Definiuje podstawową instrukcję select do pobierania danych
   /// bez warunków.
   /// 
   /// właściwość ta jest implementowana w podklasach konkretnych.
   /// </summary>
   protected abstract string SelectStatement
   {
      get;
   }

   /// <summary>
   /// Tworzy obiekt DbParamteter niezależny od dostawcy
   /// </summary>
   protected DbParameter MakeParameter(string name, object value, DbType paramType)
   {
      DbParameter param = Factory.CreateParameter();
      param.ParameterName = name;
      param.Value = value;
      param.DbType = paramType;
      return param;
   }

   /// <summary>
   /// Zwraca obiekt DataTable wypełniony danymi definiowanymi przez sql i parametry
   /// </summary>
   protected DataTable GetDataTable(string sql, DbParameter[] parameters)
   {
      DataTable dt = null;
      try
      {
         // tworzy obiekt połączenia niezależny od dostawcy
         DbConnection conn = Factory.CreateConnection();
         conn.ConnectionString = ConnectionSetting.ConnectionString;

         // tworzy obiekt adaptera niezależny od dostawcy
         DbDataAdapter adapter = Factory.CreateDataAdapter();

         DbCommand cmd = Factory.CreateCommand();
         cmd.Connection = conn;
         cmd.CommandText = sql;
         adapter.SelectCommand = cmd; ;

         // dodanie parametrów
         if (parameters != null)
         {
            foreach (DbParameter p in parameters)
               adapter.SelectCommand.Parameters.Add(p);
         }

         // tworzenie danych tabeli
         dt = new DataTable();

         // wypełnienie nowej tabeli danymi z adaptera
         adapter.Fill(dt);

      }
      catch (Exception ex)
      {
         // wszystkie błędy będą obsługiwane przez zdefiniowaną metodę
         DataAccessExceptionHandler.HandleException(ex.Message);
      }

      // Zwraca obiekt DataTable 
      return dt;
   }

   /// <summary>
   /// Uruchamia zapytanie SQL nie zwracające danych
   /// </summary>
   protected void RunNonQuery(string sql, DbParameter[] parameters)
   {
      // utworzenie obiektu połączenia niezależnego od dostawcy
      using (DbConnection conn = Factory.CreateConnection())
      {
         conn.ConnectionString = ConnectionSetting.ConnectionString;

         // tworzenie obiektu polecenia niezależnego od dostawcy
         DbCommand cmd = Factory.CreateCommand();
         cmd.Connection = conn;
         cmd.CommandText = sql;

         // dodanie parametrów
         if (parameters != null)
         {
            foreach (DbParameter p in parameters)
               cmd.Parameters.Add(p);
         }

         try
         {
            conn.Open();
            cmd.ExecuteNonQuery();
         }
         catch (Exception ex)
         {
            // wszystkie błędy będą obsługiwane przez zdefiniowaną metodę
            DataAccessExceptionHandler.HandleException(ex.Message);
         }
      }
   }

   /// <summary>
   /// Właściwość prywatna zwracająca ciąg połączenia ustawiony w web.config
   /// </summary>
   private ConnectionStringSettings ConnectionSetting
   {
      get
      {
         return WebConfigurationManager.ConnectionStrings["BookCatalog"];
         
      }
   }

   /// <summary>
   /// Właściwość prywatna zwracająca właściwy obiekt DbProviderFactory
   /// </summary>
   private DbProviderFactory Factory
   {
      get
      {
         string connString = ConnectionSetting.ConnectionString;
         string invariantName = ConnectionSetting.ProviderName;

         // sprawdzenie, czy podana nazwa dostawcy jest obsługiwana
         DataTable providers = DbProviderFactories.GetFactoryClasses();
         DataRow[] foundArray = providers.Select("InvariantName='" + invariantName + "'");
         if (foundArray.Length == 0)
         {
            // wszystkie błędy będą obsługiwane przez zdefiniowaną metodę
            string msg = "[AbstractDA] Nie znaleziony dostawca: " + invariantName;
            DataAccessExceptionHandler.HandleException(msg);
         }

         // pobranie odpowiedniego obiektu factory dostawcy
         return DbProviderFactories.GetFactory(invariantName);
      }
   }
}
