bool hasAmbiguous(Variant & variant) {

        for (uint allele_idx = 0; allele_idx < variant.numAlls(); allele_idx++) {

            if (hasAmbiguous(variant.allele(allele_idx))) {

                return true;
            }
        }

        return false;
    }
    vector<uint> getCalledAlleleIdxsSorted(Variant & var, const float min_acp) {

        vector<uint> called_allele_idxs;
        
        for (uint allele_idx = 0; allele_idx < var.numAlls(); allele_idx++) {

            if (isAlleleCalled(var.allele(allele_idx), min_acp)) {

                called_allele_idxs.push_back(allele_idx);
            }
        }

        return called_allele_idxs;
    }
    bool hasMissing(Variant & variant) {

        assert(!(variant.allele(0).isMissing()));

        for (uint alt_idx = 0; alt_idx < variant.numAlts(); alt_idx++) {

            if (variant.alt(alt_idx).isMissing()) {

                return true;
            }
        }

        return false;
    }
    vector<uint> getNonZeroProbAlleleIdxsSorted(Variant & var) {

        vector<uint> non_zero_prob_allele_idxs;

        for (uint allele_idx = 0; allele_idx < var.numAlls(); allele_idx++) {

            auto acp_value = var.allele(allele_idx).info().getValue<float>("ACP");

            if (acp_value.second) {

                if (!(Utils::floatCompare(acp_value.first, 0))) {

                    non_zero_prob_allele_idxs.push_back(allele_idx);
                }
            }
        }

        return non_zero_prob_allele_idxs;
    }
Trio::Trio(Variant & cur_var, const TrioInfo & trio_info) {

    father = cur_var.getSample(trio_info.father);
    mother = cur_var.getSample(trio_info.mother);
    child = cur_var.getSample(trio_info.child);

    is_filtered = ((father.callStatus() == Sample::CallStatus::Missing) or (mother.callStatus() == Sample::CallStatus::Missing) or (child.callStatus() == Sample::CallStatus::Missing));
    is_diploid = ((father.ploidy() == Sample::Ploidy::Diploid) and (mother.ploidy() == Sample::Ploidy::Diploid) and (child.ploidy() == Sample::Ploidy::Diploid));

    assert((father.ploidy() != Sample::Ploidy::Zeroploid) or (mother.ploidy() != Sample::Ploidy::Zeroploid) or (child.ploidy() != Sample::Ploidy::Zeroploid));

    is_informative = true;
    is_concordant = false;
    is_exclusively_child_heterozygote = true;
    is_parents_bi_allelelic_heterozygote = false;    
    is_reference_call = true;
    has_called_missing = false;

    if (!is_filtered) {

        auto father_genotype = father.genotypeEstimate();
        auto mother_genotype = mother.genotypeEstimate();
        auto child_genotype = child.genotypeEstimate();

        bool first_child_allele_in_father = false;
        bool second_child_allele_in_father = false;
        bool first_child_allele_in_mother = false;
        bool second_child_allele_in_mother = false;

        if (child_genotype.size() > 0) {

            assert(child.ploidy() != Sample::Ploidy::Zeroploid);

            first_child_allele_in_father = (find(father_genotype.begin(), father_genotype.end(), child_genotype.front()) != father_genotype.end());
            second_child_allele_in_father = (find(father_genotype.begin(), father_genotype.end(), child_genotype.back()) != father_genotype.end());
            first_child_allele_in_mother = (find(mother_genotype.begin(), mother_genotype.end(), child_genotype.front()) != mother_genotype.end());
            second_child_allele_in_mother = (find(mother_genotype.begin(), mother_genotype.end(), child_genotype.back()) != mother_genotype.end());
        }

        if (cur_var.chrom() == "chrX") {

            if (!is_diploid) {

                assert(father.ploidy() == Sample::Ploidy::Haploid);            
                assert(father_genotype.size() == 1);

                assert(mother.ploidy() == Sample::Ploidy::Diploid);
                assert(mother_genotype.size() == 2);

                if (child.ploidy() == Sample::Ploidy::Diploid) {

                    assert(child_genotype.size() == 2);

                    is_concordant = ((first_child_allele_in_father and second_child_allele_in_mother) or (second_child_allele_in_father and first_child_allele_in_mother));

                } else {

                    assert(child.ploidy() == Sample::Ploidy::Haploid);
                    assert(child_genotype.size() == 1);

                    assert(first_child_allele_in_mother == second_child_allele_in_mother);
                    
                    is_concordant = first_child_allele_in_mother;
                }

            } else {
                
                is_informative = false;
                is_concordant = false;
            }

        } else if (cur_var.chrom() == "chrY") {

            if (!is_diploid) {

                assert(father.ploidy() == Sample::Ploidy::Haploid);            
                assert(father_genotype.size() == 1);

                assert(mother.ploidy() == Sample::Ploidy::Zeroploid);
                assert(mother_genotype.size() == 0);

                assert(!first_child_allele_in_mother and !second_child_allele_in_mother);
                assert(first_child_allele_in_father == second_child_allele_in_father);

                if (child.ploidy() == Sample::Ploidy::Haploid) {

                    assert(child_genotype.size() == 1);
                    
                    is_concordant = first_child_allele_in_father;

                } else {

                    assert(child.ploidy() == Sample::Ploidy::Zeroploid);
                    assert(child_genotype.size() == 0);

                    assert(!first_child_allele_in_father);

                    is_informative = false;
                    is_concordant = false;
                }

            } else {

                is_informative = false;
                is_concordant = false;               
            }

        } else {

            assert(is_diploid);
            
            assert(father_genotype.size() == 2);
            assert(mother_genotype.size() == 2);
            assert(child_genotype.size() == 2);

            is_concordant = ((first_child_allele_in_father and second_child_allele_in_mother) or (second_child_allele_in_father and first_child_allele_in_mother));

            if (cur_var.numAlls() == 2) {

                if ((father_genotype.front() != father_genotype.back()) and (mother_genotype.front() != mother_genotype.back())) {

                    is_parents_bi_allelelic_heterozygote = true;
                }
            }
        }

        if (child.ploidy() != Sample::Ploidy::Diploid) {

            is_exclusively_child_heterozygote = false;

        } else if ((father.ploidy() == Sample::Ploidy::Zeroploid) or (mother.ploidy() == Sample::Ploidy::Zeroploid)) {

            is_exclusively_child_heterozygote = false;

        } else if ((father_genotype.front() != father_genotype.back()) or (mother_genotype.front() != mother_genotype.back())) {

            is_exclusively_child_heterozygote = false;

        } else if (child_genotype.front() == child_genotype.back()) {
        
            is_exclusively_child_heterozygote = false;
        }

        auto all_called_alleles = father_genotype;
        all_called_alleles.insert(all_called_alleles.end(), mother_genotype.begin(), mother_genotype.end());
        all_called_alleles.insert(all_called_alleles.end(), child_genotype.begin(), child_genotype.end());

        assert(all_called_alleles.size() > 0);

        for (auto &allele_idx: all_called_alleles) {

            if (cur_var.allele(allele_idx).isMissing()) {

                has_called_missing = true;
            } 

            if (allele_idx > 0) {

                is_reference_call = false;
            }           
        }

        de_novo_event.first = false;

        if (is_diploid and !is_concordant and is_exclusively_child_heterozygote and !has_called_missing) {

            uint ancestral_allele_idx = 0;
            uint de_novo_allele_idx = 0;

            if ((!first_child_allele_in_father and !first_child_allele_in_mother) and (second_child_allele_in_father or second_child_allele_in_mother)) {

                de_novo_allele_idx = child_genotype.front();

            } else if ((!second_child_allele_in_father and !second_child_allele_in_mother) and (first_child_allele_in_father or first_child_allele_in_mother)) {

                de_novo_allele_idx = child_genotype.back();
            }

            if (de_novo_allele_idx == father_genotype.front()) {

                ancestral_allele_idx = mother_genotype.front();

            } else {

                ancestral_allele_idx = father_genotype.front();
            }

            if (de_novo_allele_idx > 0) {

                assert(de_novo_allele_idx != ancestral_allele_idx);

                de_novo_event.first = true;
                
                de_novo_event.second.child_id = trio_info.child;
                de_novo_event.second.ancestral_allele_idx = ancestral_allele_idx;
                de_novo_event.second.de_novo_allele_idx = de_novo_allele_idx;
            }
        }
    }
}