namespace Generator_Class_BD.Clases.NetCore._2.Negocio.BL
{
    using Generator_Class_BD.Clases.Consultas;
    using Generator_Class_BD.Clases.Transversales;
    using Generator_Class_BD.Clases.Utilitarios;
    using System.Data;
    using System.Globalization;
    using System.Linq;
    using System.Text;
    using System.Threading;

    public class ClaseBL
    {
        internal static void GenerarBL(string vNombreClase, DataSet dsCol, string txtRuta, string TxtSolucion, string autor, string company)
        {
            string vNombreEntidad = "";
            string path = "";

            path = txtRuta + "\\2. Negocio\\" + TxtSolucion + ".Negocio\\Clases\\BL\\" + vNombreClase;

            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            TextInfo textInfo = cultureInfo.TextInfo;
            vNombreEntidad = vNombreClase;

            string vNombreEntidadL = vNombreEntidad.Substring(0, 1).ToLower() + vNombreEntidad.ToString().Substring(1);

            StringBuilder cuerpo = new StringBuilder();
            UtilitariosTransversales.EncabezadoDerechosAutor(vNombreClase + "BL", cuerpo, autor, company);
            cuerpo.AppendFormat("namespace {0}.Negocio.Clases.BL\n", TxtSolucion);
            cuerpo.Append("{\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaSystem + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaSystemCollectionsGeneric + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaSystemThreadingTask + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaDALRepositorioDatos, TxtSolucion) + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaAccionRepositorioIC, TxtSolucion) + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaDTORepositorioIC, TxtSolucion) + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaRecursosIC, TxtSolucion) + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaUtilitariosNetTransaccional + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaUtilitariosNetClasesComunesEntidades + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaUtilitariosNetTransversalesClasesComunesEnumeraciones + "\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t/// <summary>\n");
            cuerpo.Append("\t/// Clase con las acciones de negocio de la entidad " + vNombreEntidad + "\n");
            cuerpo.Append("\t/// </summary>\n");
            cuerpo.AppendFormat("\tpublic class {0}BL : AccesoComunBL, I{0}NegocioAccion\n", vNombreEntidad);
            cuerpo.Append("\t{\n");
            cuerpo.Append("\n");

            cuerpo.Append("\t\t#region ATRIBUTOS\n");

            cuerpo.Append("\t\t/// <summary>\n");
            cuerpo.Append("\t\t/// Objeto para repositorio " + vNombreEntidad + "\n");

            cuerpo.Append("\t\t/// <summary>\n");
            cuerpo.Append("\t\t/// Objeto para acciones " + vNombreEntidad + "\n");
            cuerpo.Append("\t\t/// </summary>\n");
            cuerpo.AppendFormat("\t\tprivate Lazy<I{0}RepositorioAccion> {1}RepositorioAccion;\n\n", vNombreEntidad, Util.PascalACamel(vNombreEntidad));
            cuerpo.Append("\t\t/// <summary>\n");
            cuerpo.Append("\t\t/// Objeto para entidad respuesta\n");
            cuerpo.Append("\t\t/// </summary>\n");
            cuerpo.AppendFormat("\t\tRespuesta<I{0}DTO> respuesta;\n", vNombreEntidad);
            cuerpo.Append("\n");
            cuerpo.Append("\t\t#endregion ATRIBUTOS\n");

            cuerpo.Append("\t\t#region CONSTRUCTORES\n");
            cuerpo.Append("\t\t/// <summary>\n");
            cuerpo.AppendFormat("\t\t/// Inicializa una nueva instancia de la clase {0}BL\n", vNombreEntidad);
            cuerpo.Append("\t\t/// </summary>\n");
            cuerpo.AppendFormat("\t\t/// <param name=\"arg{0}RepositorioAccion\">Acciones entidad {0}</param>\n", vNombreEntidad);
            cuerpo.AppendFormat("\t\tpublic {0}BL(Lazy<I{0}RepositorioAccion> arg{0}RepositorioAccion = null)\n", vNombreEntidad);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\tthis.respuesta = new Respuesta<I{0}DTO>();\n", vNombreEntidad);
            cuerpo.AppendFormat("\t\t\tthis.{0}RepositorioAccion = arg{1}RepositorioAccion ?? new Lazy<I{1}RepositorioAccion>(() => new {1}DAL());\n", Util.PascalACamel(vNombreEntidad), vNombreEntidad);
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t#endregion CONSTRUCTORES\n");

            cuerpo.Append("\t\t#region METODOS PUBLICOS\n");

            UtilitariosTransversales.EncabezadoMetodoConsultarLista(vNombreEntidad, cuerpo, vNombreEntidadL);
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> ConsultarLista{0}Async()\n", vNombreEntidad);
            cuerpo.Append("\t\t{\n");
            cuerpo.Append("\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(\n", vNombreEntidad);
            cuerpo.Append("\t\t\tSystem.Transactions.IsolationLevel.ReadUncommitted,\n");
            cuerpo.Append("\t\t\tasync () =>\n");
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\t respuesta= await this.{1}RepositorioAccion.Value.ConsultarLista{0}Async();\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t\t\t respuesta.Resultado = true;\n");
            cuerpo.Append("\t\t\t\t respuesta.TipoNotificacion = TipoNotificacion.Exitoso;\n");
            cuerpo.Append("\t\t\t\t return respuesta;\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t}\n");

            UtilitariosTransversales.EncabezadoMetodoConsultarLlave(vNombreEntidad, cuerpo, vNombreEntidadL);
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> Consultar{0}LlaveAsync(I{0}DTO {1})\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(\n", vNombreEntidad);
            cuerpo.Append("\t\t\tSystem.Transactions.IsolationLevel.ReadUncommitted,\n");
            cuerpo.Append("\t\t\tasync () =>\n");
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\t respuesta= await this.{1}RepositorioAccion.Value.Consultar{0}LlaveAsync({1});\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t\t\t respuesta.Resultado = true;\n");
            cuerpo.Append("\t\t\t\t respuesta.TipoNotificacion = TipoNotificacion.Exitoso;\n");
            cuerpo.Append("\t\t\t\t return respuesta;\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");

            UtilitariosTransversales.EncabezadoMetodoEditar(vNombreEntidad, cuerpo, vNombreEntidadL);
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> Editar{0}Async(I{0}DTO {1})\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(\n", vNombreEntidad);
            cuerpo.Append("\t\t\tSystem.Transactions.IsolationLevel.ReadUncommitted,\n");
            cuerpo.Append("\t\t\tasync () =>\n");
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\t respuesta= await this.{1}RepositorioAccion.Value.Editar{0}Async({1});\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t\t\t respuesta.Resultado = true;\n");
            cuerpo.Append("\t\t\t\t respuesta.TipoNotificacion = TipoNotificacion.Exitoso;\n");
            cuerpo.Append("\t\t\t\t respuesta.Mensajes.Add(rcsMensajesComunes.MensajeCreacionEdicionExitosa);\n");
            cuerpo.Append("\t\t\t\t return respuesta;\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");
            cuerpo.Append("\n");

            UtilitariosTransversales.EncabezadoMetodoEliminar(vNombreEntidad, cuerpo, vNombreEntidadL);
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> Eliminar{0}Async(I{0}DTO {1})\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(\n", vNombreEntidad);
            cuerpo.Append("\t\t\tSystem.Transactions.IsolationLevel.ReadUncommitted,\n");
            cuerpo.Append("\t\t\tasync () =>\n");
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\t respuesta= await this.{1}RepositorioAccion.Value.Eliminar{0}Async({1});\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t\t\t respuesta.Resultado = true;\n");
            cuerpo.Append("\t\t\t\t respuesta.TipoNotificacion = TipoNotificacion.Exitoso;\n");
            cuerpo.Append("\t\t\t\t respuesta.Mensajes.Add(rcsMensajesComunes.MensajeEntidadEliminadaConExito);\n");
            cuerpo.Append("\t\t\t\t return respuesta;\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");

            UtilitariosTransversales.EncabezadoMetodoGuardar(vNombreEntidad, cuerpo, vNombreEntidadL);
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> Guardar{0}Async(I{0}DTO {1})\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(\n", vNombreEntidad);
            cuerpo.Append("\t\t\tSystem.Transactions.IsolationLevel.ReadUncommitted,\n");
            cuerpo.Append("\t\t\tasync () =>\n");
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\t respuesta= await this.{1}RepositorioAccion.Value.Guardar{0}Async({1});\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t\t\t respuesta.Resultado = true;\n");
            cuerpo.Append("\t\t\t\t respuesta.TipoNotificacion = TipoNotificacion.Exitoso;\n");
            cuerpo.Append("\t\t\t\t respuesta.Mensajes.Add(rcsMensajesComunes.MensajeCreacionEdicionExitosa);\n");
            cuerpo.Append("\t\t\t\t return respuesta;\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");

            UtilitariosTransversales.EncabezadoMetodoGuardarLista(vNombreEntidad, cuerpo, vNombreEntidadL);
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> GuardarLista{0}Async(List<I{0}DTO> lista{0})\n", vNombreEntidad);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(\n", vNombreEntidad);
            cuerpo.Append("\t\t\tSystem.Transactions.IsolationLevel.ReadUncommitted,\n");
            cuerpo.Append("\t\t\tasync () =>\n");
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\t respuesta= await this.{1}RepositorioAccion.Value.GuardarLista{0}Async(lista{0});\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t\t\t respuesta.Resultado = true;\n");
            cuerpo.Append("\t\t\t\t respuesta.TipoNotificacion = TipoNotificacion.Exitoso;\n");
            cuerpo.Append("\t\t\t\t respuesta.Mensajes.Add(rcsMensajesComunes.MensajeCreacionEdicionExitosa);\n");
            cuerpo.Append("\t\t\t\t return respuesta;\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\t\t}\n");

            cuerpo.Append("\t\t#endregion METODOS PUBLICOS\n");

            cuerpo.Append("\t\t#region METODOS PRIVADOS\n");

            cuerpo.Append("\t\t#endregion METODOS PRIVADOS\n");

            cuerpo.Append("\t}\n");
            cuerpo.Append("}\n");

            Util.CrearArchivo(path + "\\" + vNombreClase + "BL.cs", path, cuerpo);
        }

        internal static void GenerarBLConsultas(Consulta consulta, string txtRuta, string TxtSolucion, string autor, string company)
        {
            string vNombreEntidad = "";
            string path = "";

            path = txtRuta + "\\4. Negocio\\" + TxtSolucion + ".Negocio\\Clases\\BL";

            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            TextInfo textInfo = cultureInfo.TextInfo;
            vNombreEntidad = consulta.NombreObjeto;

            string vNombreEntidadL = vNombreEntidad.Substring(0, 1).ToLower() + vNombreEntidad.ToString().Substring(1);

            StringBuilder cuerpo = new StringBuilder();
            UtilitariosTransversales.EncabezadoDerechosAutor(consulta.NombreObjeto + "BL", cuerpo, autor, company);
            cuerpo.AppendFormat("namespace {0}.Negocio.Clases.BL\n", TxtSolucion);
            cuerpo.Append("{\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaSystem + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaSystemCollectionsGeneric + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaSystemLinq + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaBORepositorioNegocio, TxtSolucion) + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaDALRepositorioDatos, TxtSolucion) + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaAccionRepositorioIC, TxtSolucion) + "\n");
            cuerpo.Append("\t" + string.Format(ConstantesComunes.LibreriaDTORepositorioIC, TxtSolucion) + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaUtilitariosTransversalesClasesComunesEnumeraciones + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaUtilitariosTransaccional + "\n");
            cuerpo.Append("\t" + ConstantesComunes.LibreriaUtilitariosClasesComunesEntidades + "\n");
            cuerpo.Append("\n");
            cuerpo.AppendFormat("\tpublic class {0}BL : AccesoComunBL, I{0}Accion, I{0}NegocioAccion\n", vNombreEntidad);
            cuerpo.Append("\t{\n");
            cuerpo.Append("\n");
            cuerpo.AppendFormat("\t\tprivate Lazy<I{0}Accion> Repositorio{0};\n", vNombreEntidad);
            cuerpo.AppendFormat("\t\tprivate Lazy<I{0}RepositorioAccion> {0}RepositorioAccion;\n", vNombreEntidad);
            cuerpo.AppendFormat("\t\tRespuesta<I{0}DTO> Respuesta;\n", vNombreEntidad);
            cuerpo.Append("\n");
            cuerpo.AppendFormat("\t\tpublic {0}BL(Lazy<I{0}Accion> repositorio{0}, Lazy<I{0}RepositorioAccion> {1}RepositorioAccion)\n", vNombreEntidad, Util.PascalACamel(vNombreEntidad));
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\tthis.Respuesta = new Respuesta<I{0}DTO>();\n", vNombreEntidad);
            cuerpo.AppendFormat("\t\t\tRepositorio{0} = repositorio{0};\n", vNombreEntidad);
            cuerpo.AppendFormat("\t\t\t{0}RepositorioAccion = {1}RepositorioAccion;\n", vNombreEntidad, Util.PascalACamel(vNombreEntidad));
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> ConsultarLista{0}Async()\n", vNombreEntidad);
            cuerpo.Append("\t\t{\n");
            cuerpo.Append("\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(System.Transactions.IsolationLevel.ReadUncommitted, async () =>\n", vNombreEntidad);
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\treturn Repositorio{0}.Value.ConsultarLista{0}Async();\n", vNombreEntidad);
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.AppendFormat("\t\tpublic async Task<Respuesta<I{0}DTO>> ConsultarLista{0}PorFiltroAsync(I{0}DTO {1})\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t{\n");
            cuerpo.AppendFormat("\t\t\treturn await this.EjecutarTransaccionBDAsync<Respuesta<I{0}DTO>, {0}BL>(System.Transactions.IsolationLevel.ReadUncommitted, async () =>\n", vNombreEntidad);
            cuerpo.Append("\t\t\t{\n");
            cuerpo.AppendFormat("\t\t\t\treturn await {1}RepositorioAccion.Value.ConsultarLista{0}PorFiltroAsync({1}, ObtenerFiltroCargo({1}));\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\n");
            cuerpo.Append("\t\t\t});\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");

            cuerpo.AppendFormat("\t\tprivate Expression<Func<I{0}DTO, bool>> ObtenerFiltroCargo(I{0}DTO datos{0})\n", vNombreEntidad, vNombreEntidadL);
            cuerpo.Append("\t\t{\n");
            cuerpo.Append("\t\t\t////Se deben modifiar las propiedades del filtro según sea necesario.\n");
            cuerpo.Append("\t\t\t////Si no se incuye el filtro para guid (uniqueidentifi) se debe colocar en el filtro el campo != de default.\n");
            cuerpo.Append("\t\t\t////Para los campos que son nullables se debe colocar el nombre del campo != null.\n");
            cuerpo.Append("\t\t\t////Para los campos que son de tipo string se debe la (siguiente cadena es de ejemplo).\n");
            cuerpo.Append("\t\t\t////!string.IsNullOrEmpty(datosColumnas.DescripcionColumna) ? columna.DescripcionColumna.Contains(datosColumnas.DescripcionColumna) : true.\n");
            cuerpo.Append("\t\t\t////return filtro => \n");
            consulta.ListaTablasRelacionadas.ForEach(tabla =>
            {
                tabla.ListaCampos.ForEach(columna =>
                {
                    if (tabla.ListaCampos.IndexOf(columna) == tabla.ListaCampos.Count() - 1 && consulta.ListaTablasRelacionadas.IndexOf(tabla) == consulta.ListaTablasRelacionadas.Count() - 1)
                    {
                        cuerpo.Append("\t\t\t////(datos" + vNombreEntidad + "." + columna.Alias + " != null ? filtro." + columna.Alias + "== datos" + vNombreEntidad + "." + columna.Alias + " : true); \n");
                    }
                    else
                    {
                        cuerpo.Append("\t\t\t////(datos" + vNombreEntidad + "." + columna.Alias + " != null ? filtro." + columna.Alias + "== datos" + vNombreEntidad + "." + columna.Alias + " : true)&& \n");
                    }
                });
            });
            cuerpo.Append("\t\t\treturn null;\n");
            cuerpo.Append("\t\t}\n");
            cuerpo.Append("\n");
            cuerpo.Append("\t}\n");
            cuerpo.Append("}\n");

            Util.CrearArchivo(path + "\\" + consulta.NombreObjeto + "BL.cs", path, cuerpo);
        }
    }
}