from gn2.base.trait import GeneralTrait
from gn2.base import data_set  # import create_dataset

from pprint import pformat as pf

import string
import math
from decimal import Decimal
import random
import sys
import datetime
import os
import collections
import uuid

import numpy as np

import pickle as pickle
import itertools

import simplejson as json

from redis import Redis
Redis = Redis()

from flask import Flask, g

from gn2.base.trait import GeneralTrait
from gn2.base import data_set
from gn2.base import species
from gn2.base import webqtlConfig
from gn2.utility import webqtlUtil, helper_functions, hmac, Plot, Bunch, temp_data
from gn2.utility.redis_tools import get_redis_conn
from gn2.wqflask.database import database_connection
from gn2.wqflask.marker_regression import gemma_mapping, rqtl_mapping, qtlreaper_mapping, plink_mapping
from gn2.wqflask.show_trait.SampleList import SampleList

from gn2.utility.tools import locate, get_setting, locate_ignore_error, GEMMA_COMMAND, PLINK_COMMAND, TEMPDIR
from gn2.utility.external import shell
from gn2.base.webqtlConfig import TMPDIR, GENERATED_TEXT_DIR

Redis = get_redis_conn()

class RunMapping:

    def __init__(self, start_vars, temp_uuid):
        helper_functions.get_species_dataset_trait(self, start_vars)

        # needed to pass temp_uuid to gn1 mapping code (marker_regression_gn1.py)
        self.temp_uuid = temp_uuid

        # ZS: Needed to zoom in or remap temp traits like PCA traits
        if "temp_trait" in start_vars and start_vars['temp_trait'] != "False":
            self.temp_trait = "True"
            self.group = self.dataset.group.name

        self.hash_of_inputs = start_vars['hash_of_inputs']
        self.dataid = start_vars['dataid']

        self.json_data = {}
        self.json_data['lodnames'] = ['lod.hk']

        # ZS: Sometimes a group may have a genofile that only includes a subset of samples
        genofile_samplelist = []
        if 'genofile' in start_vars:
            if start_vars['genofile'] != "":
                self.genofile_string = start_vars['genofile']
                self.dataset.group.genofile = self.genofile_string.split(":")[
                    0]
                genofile_samplelist = get_genofile_samplelist(self.dataset)

        all_samples_ordered = self.dataset.group.all_samples_ordered()

        self.vals = []
        self.samples = []
        self.sample_vals = start_vars['sample_vals']
        self.vals_hash = start_vars['vals_hash']
        sample_val_dict = json.loads(self.sample_vals)
        samples = sample_val_dict.keys()
        if (len(genofile_samplelist) != 0):
            for sample in genofile_samplelist:
                self.samples.append(sample)
                if sample in samples:
                    self.vals.append(sample_val_dict[sample])
                else:
                    self.vals.append("x")
        else:
            for sample in self.dataset.group.samplelist:
                if sample in samples:
                    self.vals.append(sample_val_dict[sample])
                    self.samples.append(sample)

        if 'n_samples' in start_vars:
            self.n_samples = start_vars['n_samples']
        else:
            self.n_samples = len([val for val in self.vals if val != "x"])

        # ZS: Check if genotypes exist in the DB in order to create links for markers

        self.geno_db_exists = geno_db_exists(self.dataset)

        self.mapping_method = start_vars['method']
        if "results_path" in start_vars:
            self.mapping_results_path = start_vars['results_path']
        else:
            mapping_results_filename = "_".join([self.dataset.group.name, self.mapping_method, self.vals_hash]).replace("/", "_")
            self.mapping_results_path = "{}{}.csv".format(
                webqtlConfig.GENERATED_IMAGE_DIR, mapping_results_filename)

        self.pair_scan = False
        self.manhattan_plot = False
        if 'manhattan_plot' in start_vars:
            if start_vars['manhattan_plot'].lower() != "false":
                self.color_scheme = "alternating"
                if "color_scheme" in start_vars:
                    self.color_scheme = start_vars['color_scheme']
                    if self.color_scheme == "single":
                        self.manhattan_single_color = start_vars['manhattan_single_color']
                self.manhattan_plot = True

        self.maf = start_vars['maf']  # Minor allele frequency
        if "use_loco" in start_vars:
            self.use_loco = start_vars['use_loco']
        else:
            self.use_loco = None
        self.suggestive = ""
        self.significant = ""
        if 'transform' in start_vars:
            self.transform = start_vars['transform']
        else:
            self.transform = ""
        self.score_type = "LRS"  # ZS: LRS or LOD
        self.mapping_scale = "physic"
        if "mapping_scale" in start_vars:
            self.mapping_scale = start_vars['mapping_scale']
        self.num_perm = 0
        self.perm_output = []
        self.bootstrap_results = []
        self.covariates = start_vars['covariates'] if "covariates" in start_vars else ""
        self.categorical_vars = []

        # ZS: This is passed to GN1 code for single chr mapping
        self.selected_chr = -1
        if "selected_chr" in start_vars:
            # ZS: Needs to be -1 if showing full map; there's probably a better way to fix this
            if int(start_vars['selected_chr']) != -1:
                self.selected_chr = int(start_vars['selected_chr']) + 1
            else:
                self.selected_chr = int(start_vars['selected_chr'])
        if "startMb" in start_vars:
            self.startMb = start_vars['startMb']
        if "endMb" in start_vars:
            self.endMb = start_vars['endMb']
        if "graphWidth" in start_vars:
            self.graphWidth = start_vars['graphWidth']
        if "lrsMax" in start_vars:
            self.lrsMax = start_vars['lrsMax']
        if "haplotypeAnalystCheck" in start_vars:
            self.haplotypeAnalystCheck = start_vars['haplotypeAnalystCheck']
        if "startMb" in start_vars:  # This is to ensure showGenes, Legend, etc are checked the first time you open the mapping page, since startMb will only not be set during the first load
            if "permCheck" in start_vars:
                self.permCheck = "ON"
            else:
                self.permCheck = False
            self.num_perm = int(start_vars['num_perm'])

            self.LRSCheck = start_vars['LRSCheck']

            if "showSNP" in start_vars:
                self.showSNP = start_vars['showSNP']
            else:
                self.showSNP = False

            if "showHomology" in start_vars:
                self.showHomology = start_vars['showHomology']
            else:
                self.showHomology = False

            if "showGenes" in start_vars:
                self.showGenes = start_vars['showGenes']
            else:
                self.showGenes = False

            if "viewLegend" in start_vars:
                self.viewLegend = start_vars['viewLegend']
            else:
                self.viewLegend = False
        else:
            try:
                if int(start_vars['num_perm']) > 0:
                    self.num_perm = int(start_vars['num_perm'])
            except:
                self.num_perm = 0

            if self.num_perm > 0:
                self.permCheck = "ON"
            else:
                self.permCheck = False
            self.showSNP = "ON"
            self.showGenes = "ON"
            self.viewLegend = "ON"

        # self.dataset.group.get_markers()
        if self.mapping_method == "gemma":
            self.first_run = True
            self.output_files = None
            if 'output_files' in start_vars:
                self.output_files = start_vars['output_files']
            # ZS: check if first run so existing result files can be used if it isn't (for example zooming on a chromosome, etc)
            if 'first_run' in start_vars:
                self.first_run = False
            self.score_type = "-logP"
            self.manhattan_plot = True
            if self.use_loco == "True":
                marker_obs, self.output_files = gemma_mapping.run_gemma(
                    self.this_trait, self.dataset, self.samples, self.vals, self.covariates, self.use_loco, self.maf, self.first_run, self.output_files)
            else:
                marker_obs, self.output_files = gemma_mapping.run_gemma(
                    self.this_trait, self.dataset, self.samples, self.vals, self.covariates, self.use_loco, self.maf, self.first_run, self.output_files)
            results = marker_obs
        elif self.mapping_method == "rqtl_plink":
            results = self.run_rqtl_plink()
        elif self.mapping_method == "rqtl_geno":
            self.perm_strata = []
            if "perm_strata" in start_vars and "categorical_vars" in start_vars:
                self.categorical_vars = start_vars["categorical_vars"].split(
                    ",")
                if len(self.categorical_vars) and start_vars["perm_strata"] == "True":
                    primary_samples = SampleList(dataset=self.dataset,
                                                 sample_names=self.samples,
                                                 this_trait=self.this_trait)

                    self.perm_strata = get_perm_strata(
                        self.this_trait, primary_samples, self.categorical_vars, self.samples)
            self.score_type = "-logP"
            self.control_marker = start_vars['control_marker']
            self.do_control = start_vars['do_control']
            if 'mapmethod_rqtl' in start_vars:
                self.method = start_vars['mapmethod_rqtl']
            else:
                self.method = "em"
            self.model = start_vars['mapmodel_rqtl']
            self.pair_scan = False
            if start_vars['pair_scan'] == "true":
               self.pair_scan = True
            if self.permCheck and self.num_perm > 0:
                self.perm_output, self.suggestive, self.significant, results = rqtl_mapping.run_rqtl(
                    self.this_trait.name, self.vals, self.samples, self.dataset, self.pair_scan, self.mapping_scale, self.model, self.method, self.num_perm, self.perm_strata, self.do_control, self.control_marker, self.manhattan_plot, self.covariates)
            else:
                results = rqtl_mapping.run_rqtl(self.this_trait.name, self.vals, self.samples, self.dataset, self.pair_scan, self.mapping_scale, self.model, self.method,
                                                     self.num_perm, self.perm_strata, self.do_control, self.control_marker, self.manhattan_plot, self.covariates)
        elif self.mapping_method == "reaper":
            if "startMb" in start_vars:  # ZS: Check if first time page loaded, so it can default to ON
                if "additiveCheck" in start_vars:
                    self.additiveCheck = start_vars['additiveCheck']
                else:
                    self.additiveCheck = False

                if "bootCheck" in start_vars:
                    self.bootCheck = "ON"
                else:
                    self.bootCheck = False
                self.num_bootstrap = int(start_vars['num_bootstrap'])
            else:
                self.additiveCheck = "ON"
                try:
                    if int(start_vars['num_bootstrap']) > 0:
                        self.bootCheck = "ON"
                        self.num_bootstrap = int(start_vars['num_bootstrap'])
                    else:
                        self.bootCheck = False
                        self.num_bootstrap = 0
                except:
                    self.bootCheck = False
                    self.num_bootstrap = 0

            self.control_marker = start_vars['control_marker']
            self.do_control = start_vars['do_control']

            self.first_run = True
            self.output_files = None
            # ZS: check if first run so existing result files can be used if it isn't (for example zooming on a chromosome, etc)
            if 'first_run' in start_vars:
                self.first_run = False
                if 'output_files' in start_vars:
                    self.output_files = start_vars['output_files'].split(
                        ",")

            results, self.perm_output, self.suggestive, self.significant, self.bootstrap_results, self.output_files = qtlreaper_mapping.run_reaper(self.this_trait,
                                                                                                                                                    self.dataset,
                                                                                                                                                    self.samples,
                                                                                                                                                    self.vals,
                                                                                                                                                    self.json_data,
                                                                                                                                                    self.num_perm,
                                                                                                                                                    self.bootCheck,
                                                                                                                                                    self.num_bootstrap,
                                                                                                                                                    self.do_control,
                                                                                                                                                    self.control_marker,
                                                                                                                                                    self.manhattan_plot,
                                                                                                                                                    self.first_run,
                                                                                                                                                    self.output_files)
        elif self.mapping_method == "plink":
            self.score_type = "-logP"
            self.manhattan_plot = True
            results = plink_mapping.run_plink(
                self.this_trait, self.dataset, self.species, self.vals, self.maf)
            #results = self.run_plink()

        self.no_results = False
        if len(results) == 0:
            self.no_results = True
        else:
            if self.pair_scan == True:
                self.figure_data = results[0]
                self.table_data = results[1]
            else:
                self.qtl_results = []
                self.results_for_browser = []
                self.annotations_for_browser = []
                highest_chr = 1  # This is needed in order to convert the highest chr to X/Y
                for marker in results:
                    marker['hmac'] = hmac.data_hmac('{}:{}'.format(marker['name'], self.dataset.group.name + "Geno"))
                    if 'Mb' in marker:
                        this_ps = marker['Mb'] * 1000000
                    else:
                        this_ps = marker['cM'] * 1000000

                    browser_marker = dict(
                        chr=str(marker['chr']),
                        rs=marker['name'],
                        ps=this_ps,
                        url="/show_trait?trait_id=" + \
                            marker['name'] + "&dataset=" + \
                        self.dataset.group.name + "Geno"
                    )

                    if self.geno_db_exists == "True":
                        annot_marker = dict(
                            name=str(marker['name']),
                            chr=str(marker['chr']),
                            rs=marker['name'],
                            pos=this_ps,
                            url="/show_trait?trait_id=" + \
                                marker['name'] + "&dataset=" + \
                            self.dataset.group.name + "Geno"
                        )
                    else:
                        annot_marker = dict(
                            name=str(marker['name']),
                            chr=str(marker['chr']),
                            rs=marker['name'],
                            pos=this_ps
                        )

                    if 'lrs_value' in marker and marker['lrs_value'] > 0:
                        browser_marker['p_wald'] = 10**- \
                            (marker['lrs_value'] / 4.61)
                    elif 'lod_score' in marker and marker['lod_score'] > 0:
                        browser_marker['p_wald'] = 10**-(marker['lod_score'])
                    else:
                        browser_marker['p_wald'] = 0

                    self.results_for_browser.append(browser_marker)
                    self.annotations_for_browser.append(annot_marker)
                    if str(marker['chr']) > '0' or str(marker['chr']) == "X" or str(marker['chr']) == "X/Y":
                        if str(marker['chr']) > str(highest_chr) or str(marker['chr']) == "X" or str(marker['chr']) == "X/Y":
                            highest_chr = marker['chr']
                        if ('lod_score' in marker.keys()) or ('lrs_value' in marker.keys()):
                            if 'Mb' in marker.keys():
                                marker['display_pos'] = "Chr" + \
                                    str(marker['chr']) + ": " + \
                                    "{:.6f}".format(marker['Mb'])
                            elif 'cM' in marker.keys():
                                marker['display_pos'] = "Chr" + \
                                    str(marker['chr']) + ": " + \
                                    "{:.3f}".format(marker['cM'])
                            else:
                                marker['display_pos'] = "N/A"
                            self.qtl_results.append(marker)

                total_markers = len(self.qtl_results)
                export_mapping_results(self.dataset, self.this_trait, self.qtl_results, self.mapping_results_path,
                                       self.mapping_method, self.mapping_scale, self.score_type,
                                       self.transform, self.covariates, self.n_samples, self.vals_hash)

                if len(self.qtl_results) > 30000:
                    self.qtl_results = trim_markers_for_figure(
                        self.qtl_results)
                    self.results_for_browser = trim_markers_for_figure(
                        self.results_for_browser)
                    filtered_annotations = []
                    for marker in self.results_for_browser:
                        for annot_marker in self.annotations_for_browser:
                            if annot_marker['rs'] == marker['rs']:
                                filtered_annotations.append(annot_marker)
                                break
                    self.annotations_for_browser = filtered_annotations
                    browser_files = write_input_for_browser(
                        self.dataset, self.results_for_browser, self.annotations_for_browser)
                else:
                    browser_files = write_input_for_browser(
                        self.dataset, self.results_for_browser, self.annotations_for_browser)

                self.trimmed_markers = trim_markers_for_table(results)

                chr_lengths = get_chr_lengths(
                    self.mapping_scale, self.mapping_method, self.dataset, self.qtl_results)

                # ZS: For zooming into genome browser, need to pass chromosome name instead of number
                if self.dataset.group.species == "mouse":
                    if self.selected_chr == 20:
                        this_chr = "X"
                    else:
                        this_chr = str(self.selected_chr)
                elif self.dataset.group.species == "rat":
                    if self.selected_chr == 21:
                        this_chr = "X"
                    else:
                        this_chr = str(self.selected_chr)
                else:
                    if self.selected_chr == 22:
                        this_chr = "X"
                    elif self.selected_chr == 23:
                        this_chr = "Y"
                    else:
                        this_chr = str(self.selected_chr)

                if self.mapping_method != "gemma":
                    if self.score_type == "LRS":
                        significant_for_browser = self.significant / 4.61
                    else:
                        significant_for_browser = self.significant

                    self.js_data = dict(
                        #result_score_type = self.score_type,
                        #this_trait = self.this_trait.name,
                        #data_set = self.dataset.name,
                        #maf = self.maf,
                        #manhattan_plot = self.manhattan_plot,
                        #mapping_scale = self.mapping_scale,
                        #chromosomes = chromosome_mb_lengths,
                        #qtl_results = self.qtl_results,
                        categorical_vars=self.categorical_vars,
                        chr_lengths=chr_lengths,
                        num_perm=self.num_perm,
                        perm_results=self.perm_output,
                        significant=significant_for_browser,
                        browser_files=browser_files,
                        selected_chr=this_chr,
                        total_markers=total_markers
                    )
                else:
                    self.js_data = dict(
                        chr_lengths=chr_lengths,
                        browser_files=browser_files,
                        selected_chr=this_chr,
                        total_markers=total_markers
                    )

    def run_rqtl_plink(self):
        # os.chdir("") never do this inside a webserver!!

        output_filename = webqtlUtil.genRandStr("%s_%s_" % (
            self.dataset.group.name, self.this_trait.name))

        plink_mapping.gen_pheno_txt_file_plink(
            self.this_trait, self.dataset, self.vals, pheno_filename=output_filename)

        rqtl_command = './plink --noweb --ped %s.ped --no-fid --no-parents --no-sex --no-pheno --map %s.map --pheno %s/%s.txt --pheno-name %s --maf %s --missing-phenotype -9999 --out %s%s --assoc ' % (
            self.dataset.group.name, self.dataset.group.name, TMPDIR, plink_output_filename, self.this_trait.name, self.maf, TMPDIR, plink_output_filename)

        os.system(rqtl_command)

        count, p_values = self.parse_rqtl_output(plink_output_filename)

    def identify_empty_samples(self):
        no_val_samples = []
        for sample_count, val in enumerate(self.vals):
            if val == "x":
                no_val_samples.append(sample_count)
        return no_val_samples

    def trim_genotypes(self, genotype_data, no_value_samples):
        trimmed_genotype_data = []
        for marker in genotype_data:
            new_genotypes = []
            for item_count, genotype in enumerate(marker):
                if item_count in no_value_samples:
                    continue
                try:
                    genotype = float(genotype)
                except ValueError:
                    genotype = np.nan
                    pass
                new_genotypes.append(genotype)
            trimmed_genotype_data.append(new_genotypes)
        return trimmed_genotype_data


def export_mapping_results(dataset, trait, markers, results_path, mapping_method, mapping_scale, score_type, transform, covariates, n_samples, vals_hash):
    if mapping_scale == "physic":
        scale_string = "Mb"
    else:
        scale_string = "cM"
    with open(results_path, "w+") as output_file:
        output_file.write(
            "Time/Date: " + datetime.datetime.now().strftime("%x / %X") + "\n")
        output_file.write(
            "Population: " + dataset.group.species.title() + " " + dataset.group.name + "\n")
        output_file.write("Data Set: " + dataset.fullname + "\n")
        output_file.write("Trait: " + trait.display_name + "\n")
        output_file.write("Trait Hash: " + vals_hash + "\n")
        output_file.write("N Samples: " + str(n_samples) + "\n")
        output_file.write("Mapping Tool: " + str(mapping_method) + "\n")
        if len(transform) > 0:
            transform_text = "Transform - "
            if transform == "qnorm":
                transform_text += "Quantile Normalized"
            elif transform == "log2" or transform == "log10":
                transform_text += transform.capitalize()
            elif transform == "sqrt":
                transform_text += "Square Root"
            elif transform == "zscore":
                transform_text += "Z-Score"
            elif transform == "invert":
                transform_text += "Invert +/-"
            else:
                transform_text = ""
            output_file.write(transform_text + "\n")
        if dataset.type == "ProbeSet":
            if trait.symbol:
                output_file.write("Gene Symbol: " + trait.symbol + "\n")
            output_file.write("Location: " + str(trait.chr) + \
                              " @ " + str(trait.mb) + " Mb\n")
        if len(covariates) > 0:
            output_file.write("Cofactors (dataset - trait):\n")
            for covariate in covariates.split(","):
                trait_name = covariate.split(":")[0]
                dataset_name = covariate.split(":")[1]
                output_file.write(dataset_name + " - " + trait_name + "\n")
        output_file.write("\n")
        output_file.write("Name,Chr,")
        if score_type.lower() == "-logP":
            score_type = "-logP"
        output_file.write(scale_string + "," + score_type)
        if "additive" in list(markers[0].keys()):
            output_file.write(",Additive")
        if "dominance" in list(markers[0].keys()):
            output_file.write(",Dominance")
        output_file.write("\n")
        for i, marker in enumerate(markers):
            output_file.write(marker['name'] + "," + str(marker['chr']) + ",")
            output_file.write(str(marker[scale_string]) + ",")
            if score_type == "-logP":
                output_file.write(str(marker['lod_score']))
            else:
                output_file.write(str(marker['lrs_value']))
            if "additive" in list(marker.keys()):
                output_file.write("," + str(marker['additive']))
            if "dominance" in list(marker.keys()):
                output_file.write("," + str(marker['dominance']))
            if i < (len(markers) - 1):
                output_file.write("\n")


def trim_markers_for_figure(markers):
    if 'p_wald' in list(markers[0].keys()):
        score_type = 'p_wald'
    elif 'lod_score' in list(markers[0].keys()):
        score_type = 'lod_score'
    else:
        score_type = 'lrs_value'

    filtered_markers = []
    low_counter = 0
    med_counter = 0
    high_counter = 0
    for marker in markers:
        if score_type == 'p_wald':
            if marker[score_type] > 0.1:
                if low_counter % 20 == 0:
                    filtered_markers.append(marker)
                low_counter += 1
            elif 0.1 >= marker[score_type] > 0.01:
                if med_counter % 10 == 0:
                    filtered_markers.append(marker)
                med_counter += 1
            elif 0.01 >= marker[score_type] > 0.001:
                if high_counter % 2 == 0:
                    filtered_markers.append(marker)
                high_counter += 1
            else:
                filtered_markers.append(marker)
        elif score_type == 'lod_score':
            if marker[score_type] < 1:
                if low_counter % 20 == 0:
                    filtered_markers.append(marker)
                low_counter += 1
            elif 1 <= marker[score_type] < 2:
                if med_counter % 10 == 0:
                    filtered_markers.append(marker)
                med_counter += 1
            elif 2 <= marker[score_type] <= 3:
                if high_counter % 2 == 0:
                    filtered_markers.append(marker)
                high_counter += 1
            else:
                filtered_markers.append(marker)
        else:
            if marker[score_type] < 4.61:
                if low_counter % 20 == 0:
                    filtered_markers.append(marker)
                low_counter += 1
            elif 4.61 <= marker[score_type] < (2 * 4.61):
                if med_counter % 10 == 0:
                    filtered_markers.append(marker)
                med_counter += 1
            elif (2 * 4.61) <= marker[score_type] <= (3 * 4.61):
                if high_counter % 2 == 0:
                    filtered_markers.append(marker)
                high_counter += 1
            else:
                filtered_markers.append(marker)
    return filtered_markers


def trim_markers_for_table(markers):
    if 'lod_score' in list(markers[0].keys()):
        sorted_markers = sorted(
            markers, key=lambda k: k['lod_score'], reverse=True)
    else:
        sorted_markers = sorted(
            markers, key=lambda k: k['lrs_value'], reverse=True)

    #ZS: So we end up with a list of just 2000 markers
    if len(sorted_markers) >= 25000:
        trimmed_sorted_markers = sorted_markers[:25000]
        return trimmed_sorted_markers
    else:
        return sorted_markers


def write_input_for_browser(this_dataset, gwas_results, annotations):
    file_base = this_dataset.group.name + "_" + \
        ''.join(random.choice(string.ascii_uppercase + string.digits)
                for _ in range(6))
    gwas_filename = file_base + "_GWAS"
    annot_filename = file_base + "_ANNOT"
    gwas_path = "{}/gn2/".format(TEMPDIR) + gwas_filename
    annot_path = "{}/gn2/".format(TEMPDIR) + annot_filename

    with open(gwas_path + ".json", "w") as gwas_file, open(annot_path + ".json", "w") as annot_file:
        gwas_file.write(json.dumps(gwas_results))
        annot_file.write(json.dumps(annotations))

    return [gwas_filename, annot_filename]


def geno_db_exists(this_dataset):
    geno_db_name = this_dataset.group.name + "Geno"
    try:
        geno_db = data_set.create_dataset(
            dataset_name=geno_db_name, get_samplelist=False)
        return "True"
    except:
        return "False"


def get_chr_lengths(mapping_scale, mapping_method, dataset, qtl_results):
    chr_lengths = []
    if mapping_scale == "physic":
        with database_connection(get_setting("SQL_URI")) as conn, conn.cursor() as db_cursor:
            for i, the_chr in enumerate(dataset.species.chromosomes.chromosomes(db_cursor)):
                this_chr = {
                    "chr": dataset.species.chromosomes.chromosomes(db_cursor)[the_chr].name,
                    "size": str(dataset.species.chromosomes.chromosomes(db_cursor)[the_chr].length)
                }
                chr_lengths.append(this_chr)
    else:
        this_chr = 1
        highest_pos = 0
        for i, result in enumerate(qtl_results):
            chr_as_num = 0
            try:
                chr_as_num = int(result['chr'])
            except:
                chr_as_num = 20
            if chr_as_num > this_chr or i == (len(qtl_results) - 1):
                if i == (len(qtl_results) - 1):
                    if mapping_method == "reaper":
                        highest_pos = float(result['cM']) * 1000000
                    else:
                        highest_pos = float(result['Mb']) * 1000000
                    chr_lengths.append(
                        {"chr": str(this_chr), "size": str(highest_pos)})
                else:
                    chr_lengths.append(
                        {"chr": str(this_chr), "size": str(highest_pos)})
                    this_chr = chr_as_num
            else:
                if mapping_method == "reaper":
                    if float(result['cM']) > highest_pos:
                        highest_pos = float(result['cM']) * 1000000
                else:
                    if float(result['Mb']) > highest_pos:
                        highest_pos = float(result['Mb']) * 1000000

    return chr_lengths


def get_genofile_samplelist(dataset):
    genofile_samplelist = []

    genofile_json = dataset.group.get_genofiles()
    for genofile in genofile_json:
        if genofile['location'] == dataset.group.genofile and 'sample_list' in genofile:
            genofile_samplelist = genofile['sample_list']

    return genofile_samplelist


def get_perm_strata(this_trait, sample_list, categorical_vars, used_samples):
    perm_strata_strings = []
    for sample in used_samples:
        if sample in list(sample_list.sample_attribute_values.keys()):
            combined_string = ""
            for var in categorical_vars:
                if var in sample_list.sample_attribute_values[sample]:
                    combined_string += str(
                        sample_list.sample_attribute_values[sample][var])
                else:
                    combined_string += "NA"
        else:
            combined_string = "NA"

        perm_strata_strings.append(combined_string)

    d = dict([(y, x + 1)
              for x, y in enumerate(sorted(set(perm_strata_strings)))])
    list_to_numbers = [d[x] for x in perm_strata_strings]
    perm_strata = list_to_numbers

    return perm_strata
