/// <summary>
 /// Libera la información del hecho y sus posibles hijos
 /// </summary>
 /// <param name="hecho"></param>
 private void LiberarHecho(HechoDto hecho)
 {
     if (hecho.DuplicadoCon != null)
     {
         hecho.DuplicadoCon.Clear();
         hecho.DuplicadoCon = null;
     }
     if (hecho.Hechos != null)
     {
         foreach (var hijo in hecho.Hechos)
         {
             if (HechosPorId.ContainsKey(hijo))
             {
                 LiberarHecho(HechosPorId[hijo]);
             }
         }
         hecho.Hechos.Clear();
     }
     if (hecho.NotasAlPie != null)
     {
         hecho.NotasAlPie.Clear();
         hecho.NotasAlPie = null;
     }
     hecho = null;
 }
        /// <summary>
        /// Determina si una tupla está duplicada con otra.
        /// </summary>
        /// <param name="tupla">la tupla que se tomará como referencia.</param>
        /// <param name="tuplaComparar">la tupla que se compara contra la referencia.</param>
        /// <returns>true si la tupla está duplicada con la de referencia. false en cualquier otro caso.</returns>
        bool EsTuplaDuplicada(HechoDto tupla, HechoDto tuplaComparar)
        {
            bool resultado = true;

            if (!tupla.IdConcepto.Equals(tuplaComparar.IdConcepto))
            {
                resultado = false;
            }
            else if (tupla.Hechos.Count != tuplaComparar.Hechos.Count)
            {
                resultado = false;
            }
            else if (tupla.TuplaPadre != null && tuplaComparar.TuplaPadre != null && !tupla.TuplaPadre.Id.Equals(tuplaComparar.TuplaPadre.Id))
            {
                resultado = false;
            }
            else
            {
                foreach (var hecho in tupla.Hechos)
                {
                    if (HechosPorId.ContainsKey(hecho))
                    {
                        var hechoDto = HechosPorId[hecho];

                        bool hechoEquivalenteEncontrado = false;
                        foreach (var hechoComparar in tuplaComparar.Hechos)
                        {
                            var hechoCompararDto = HechosPorId[hechoComparar];
                            if (hechoDto.Tipo == Concept.Tuple && hechoCompararDto.Tipo == Concept.Tuple)
                            {
                                if (this.EsTuplaDuplicada(hechoDto, hechoCompararDto))
                                {
                                    hechoEquivalenteEncontrado = true;
                                    break;
                                }
                            }
                            else if (hechoDto.Tipo == Concept.Item && hechoCompararDto.Tipo == Concept.Item)
                            {
                                if (hechoDto.IdConcepto.Equals(hechoCompararDto.IdConcepto))
                                {
                                    if (hechoDto.IdContexto.Equals(hechoCompararDto.IdContexto) || this.ContextosPorId[hechoDto.IdContexto].EstructuralmenteIgual(this.ContextosPorId[hechoCompararDto.IdContexto]))
                                    {
                                        if (hechoDto.EsNumerico)
                                        {
                                            if (hechoDto.ValorRedondeado == hechoCompararDto.ValorRedondeado)
                                            {
                                                hechoEquivalenteEncontrado = true;
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            if (hechoDto.Valor.Equals(hechoCompararDto.Valor))
                                            {
                                                hechoEquivalenteEncontrado = true;
                                                break;
                                            }
                                        }
                                    }
                                }
                                break;
                            }
                        }
                        if (!hechoEquivalenteEncontrado)
                        {
                            resultado = false;
                            break;
                        }
                    }
                }
            }

            return(resultado);
        }
        /// <summary>
        /// Libera los recursos asociados al documento de instancia
        /// </summary>
        public void Cerrar()
        {
            this.Taxonomia = null;

            if (ContextosPorFecha != null)
            {
                ContextosPorFecha.Clear();
                ContextosPorFecha = null;
            }

            if (EntidadesPorId != null)
            {
                EntidadesPorId.Clear();
                EntidadesPorId = null;
            }

            if (Errores != null)
            {
                Errores.Clear();
                Errores = null;
            }

            if (HechosPorIdContexto != null)
            {
                HechosPorIdContexto.Clear();
                HechosPorIdContexto = null;
            }

            if (HechosPorIdConcepto != null)
            {
                HechosPorIdConcepto.Clear();
                HechosPorIdConcepto = null;
            }

            if (HechosPorIdUnidad != null)
            {
                HechosPorIdUnidad.Clear();
                HechosPorIdUnidad = null;
            }

            if (UnidadesPorId != null)
            {
                UnidadesPorId.Clear();
                UnidadesPorId = null;
            }

            if (ContextosPorId != null)
            {
                foreach (var ctx in ContextosPorId.Values)
                {
                    if (ctx.Entidad != null)
                    {
                        if (ctx.Entidad.ValoresDimension != null)
                        {
                            ctx.Entidad.ValoresDimension.Clear();
                            ctx.Entidad.ValoresDimension = null;
                        }
                        ctx.Entidad = null;
                    }
                    if (ctx.Periodo != null)
                    {
                        ctx.Periodo = null;
                    }
                    if (ctx.ValoresDimension != null)
                    {
                        ctx.ValoresDimension.Clear();
                        ctx.ValoresDimension = null;
                    }
                }
                ContextosPorId.Clear();
                ContextosPorId = null;
            }

            if (HechosPorId != null)
            {
                foreach (var hecho in HechosPorId.Values)
                {
                    LiberarHecho(hecho);
                }
                HechosPorId.Clear();
            }

            if (DtsDocumentoInstancia != null)
            {
                DtsDocumentoInstancia.Clear();
                DtsDocumentoInstancia = null;
            }

            if (estructurasDocumentoInstanciaPorRol != null)
            {
                foreach (var est in estructurasDocumentoInstanciaPorRol.Values)
                {
                    est.Clear();
                }
                estructurasDocumentoInstanciaPorRol.Clear();
            }
        }
        /// <summary>
        /// Crea un nuevo hecho para el concepto enviado, asociándolo al contexto y unidad enviados como parámetro, el
        /// contexto y la unidad son opcionales, también asigna el ID de hecho enviado como parámetro.
        /// Agrega el hecho a los distintos índices del documento
        /// </summary>
        /// <param name="idConcepto">Identificador del concepto para el hecho a crear</param>
        /// <param name="idUnidad">Identificador opcional de la unidad del concepto, obligatorio para datos numéricos</param>
        /// <param name="idContexto">Contexto del hecho, no necesario para tuplas</param>
        /// <param name="idHecho">Identificador opcional del hecho</param>
        /// <returns>El hecho creado</returns>
        public HechoDto CrearHecho(string idConcepto, string idUnidad, string idContexto, string idHecho)
        {
            HechoDto hechoNuevo = null;

            if (String.IsNullOrEmpty(idConcepto) || Taxonomia == null || !Taxonomia.ConceptosPorId.ContainsKey(idConcepto))
            {
                return(null);
            }

            var concepto    = Taxonomia.ConceptosPorId[idConcepto];
            var EsAbstracto = concepto.EsAbstracto != null ? concepto.EsAbstracto.Value : false;

            if (!EsAbstracto)
            {
                if ((concepto.Tipo == Concept.Item && !ContextosPorId.ContainsKey(idContexto)) ||
                    (concepto.EsTipoDatoNumerico && !UnidadesPorId.ContainsKey(idUnidad)))
                {
                    return(null);
                }
                if (idHecho != null && HechosPorId.ContainsKey(idHecho))
                {
                    return(null);
                }
                hechoNuevo = new HechoDto()
                {
                    IdConcepto            = idConcepto,
                    NombreConcepto        = concepto.Nombre,
                    EspacioNombres        = concepto.EspacioNombres,
                    Tipo                  = concepto.Tipo,
                    Id                    = idHecho,
                    CambioValorComparador = false,
                };

                if (concepto.Tipo == Concept.Item)
                {
                    hechoNuevo.EsTupla      = false;
                    hechoNuevo.TipoDato     = concepto.TipoDato;
                    hechoNuevo.TipoDatoXbrl = concepto.TipoDatoXbrl;
                    if (concepto.EsTipoDatoNumerico)
                    {
                        hechoNuevo.EsNumerico = true;
                        hechoNuevo.IdContexto = idContexto;
                        hechoNuevo.Valor      = null;
                        hechoNuevo.IdUnidad   = idUnidad;
                        hechoNuevo.Decimales  = "0";
                    }
                    else
                    {
                        hechoNuevo.NoEsNumerico = true;
                        hechoNuevo.IdContexto   = idContexto;
                        hechoNuevo.Valor        = null;
                    }
                }
                else if (concepto.Tipo == Concept.Tuple)
                {
                    hechoNuevo.EsTupla      = true;
                    hechoNuevo.NoEsNumerico = true;
                }
            }
            return(hechoNuevo);
        }