using System;
using System.Configuration;
using System.Data.SqlClient;
using System.Diagnostics;
namespace ERMX.TE.CFDIValidation.Data
{  /// <summary>
  /// Representa clase base para acceso a datos
  /// </summary>
  public abstract class BaseDataAccess: IDisposable
  {    private readonly Enterprise.USA.Monitor.Tools.EventLogWriter.EventWriter eventWriter = 
      new Enterprise.USA.Monitor.Tools.EventLogWriter.EventWriter();
    
    /// <summary>
    /// Objeto de conexión de base de datos.
    /// </summary>
    private SqlConnection connection;
    /// <summary>
    /// Cadena de conexión a la base de datos
    /// </summary>
    public string StringConnection { get; internal set; }
    /// <summary>
    /// Objeto de transacción con la transacción actual/activa
    /// </summary>
    internal SqlTransaction ActiveTransaction { get; set; }
    /// <summary>
    /// Instancia un acceso a datos
    /// </summary>
    public BaseDataAccess()
    {      this.StringConnection = 
        ConfigurationManager.ConnectionStrings["ConnectionStringTE"].ConnectionString;
    }     protected bool Connect()
    {      bool bolResult = false;
      if (this.connection != null && 
          this.connection.State == System.Data.ConnectionState.Open)
        return true;
      try
      {        if (this.connection == null)
        {          this.connection = new SqlConnection();
          this.connection.ConnectionString = this.StringConnection;
        }
        this.connection.Open();
        bolResult = true;
      }      catch (SqlException ex)
      {        bolResult = false;
        eventWriter.WriteEvent(ex.HResult, EventLogEntryType.Error, ex.Message);
      }       return bolResult;
    }     /// <summary>
    /// Método para crear un comando
    /// </summary>
    /// <returns></returns>
    protected SqlCommand CreateCommand()
    {      SqlCommand command = this.connection.CreateCommand();
      if (this.ActiveTransaction != null)
      {        command.Transaction = this.ActiveTransaction;
      }
      return command;
    }
    /// <summary>
    /// Inicia una transacción en base a la conexion abierta.
    /// Lo que se ejecute luego de esta invocación estará 
    /// dentro de una transacción.
    /// </summary>
    /// <returns>El estado de la trasancción</returns>
    public TransactionState CreateTransaction()
    {
      TransactionState result = TransactionState.TransactionExists;
      if (this.ActiveTransaction == null)
      {
        result = TransactionState.Error;
        if (this.connection == null || 
            this.connection.State != System.Data.ConnectionState.Open)
        {        
          if (!this.Connect())
            return result;
        }         this.ActiveTransaction = this.connection.BeginTransaction();
        result = TransactionState.Succes;
      }       return result;
    }
    /// <summary>
    /// Metodo para confirmar una transacción
    /// </summary>
    public void Commit()
    {
      ActiveTransaction.Commit();
    }
    /// <summary>
    /// Método para deshacer una transacción
    /// </summary>
    public void Rollback()
    {
      ActiveTransaction.Rollback();
    }     /// <summary>
    /// Método para abrir la conexión a base de datos
    /// </summary>
    protected void Open()
    {      this.connection.Open();
    }     /// <summary>
    /// Coloca las llamadas Dispose(true)
    /// </summary>
    public void Dispose()
    {          Dispose(disposing: true);
      GC.SuppressFinalize(this);
    }     /// <summary>
    /// Realiza limpieza de código y se lleva a cabo en Dispose (bool)
    /// </summary>
    /// <param name="disposing"></param>
    public virtual void Dispose(bool disposing)
    {      if (disposing)
      {        if (this.connection != null)
        {          if (this.ActiveTransaction != null)
          {            this.ActiveTransaction.Dispose();
          }           this.connection.Close();
          this.connection.Dispose();
        }
      }
    }
      }
  /// <summary>
  /// Estado de la transaccion.
  /// TransactionExists (2)   -> Ya existe una transacción iniciada.
  /// Succes (1)              -> La transaccion se inicio correctamente.
  /// Error (0)               -> No existe una transacción
  /// </summary>
  public enum TransactionState
  {
    Error = 0,
    Succes = 1,
    TransactionExists = 2
      }
}