import logging


def map_strains_to_genes_open_filehandles(all_vars):
    """
    all_vars:
        nmeta: Number of metadata columns (?)
    Description:
        First we get the number of preliminary metadata columns
        and call it 'nmeta' and store it.
        Then we create two dicts: 'setFh' and 'setIndex',
        which we both store in all_vars.
        'setFh' (python dict): 
            Maps setName -> list<list<Filehandle, Row num (int)>>
            Goes from setName to a list, whose length is the
            number of poolcount files relating to that set, 
            with each element being a list with two elements:
            the first is the filehandle for that poolcount file,
            the second is the length of that file.
        'setIndex' (python dict):
            Maps setName -> list<Indexes (str)>
            For each setName, if the file we are looking
            at is the first for this set, then we store the list of 
            indexes (all column names after the metadata) in
            this dict. Otherwise, if we've already seen a poolcount
            file for this set, then we compare the existing indeces
            and double check that they match the first one.
            If they don't, then we raise an Exception because
            they should match. We also do a redundant comparison
            to exps SetName which should be removed.
    TD: Eventually might be better to convert this into pandas

    """

    meta = "barcode rcbarcode scaffold strand pos".split(" ")
    nmeta = len(meta)
    all_vars['nmeta'] = nmeta


    # Below is set to list of file handles reading counts for that set
    setFh = {}
    # Below is set to list of count fields, may be more than is in the
    # counts file
    setIndex = {}

    # We create this to have index loc for below keys within files
    x = ["BARCODE", "RCBARCODE", "SCAFFOLD", "STRAND", "POS"]
    for i in range(len(x)):
        all_vars[x[i]] = i

    expected_file_length = None
    for k in all_vars["setFiles"].keys():
        # Below s is setName, filelist is list of poolcount fps related
        s, filelist = k, all_vars["setFiles"][k]
        for f in filelist:

            # This is just to keep track of length of file
            with open(f, "r") as fh:
                file_length = len(fh.read().split("\n"))
                if expected_file_length is None:
                    expected_file_length = file_length
                if file_length != expected_file_length:
                    logging.warning(f"For file {f}, file size doesn't match the first poolcount."
                                    f" {f} filesize: {file_length}. First: {expected_file_length}")
            
            # Note we open files here! Close after writing all.poolcount
            fh = open(f,"r")

            # We read the first line and store it for later.
            first_line = fh.readline()

            # We add the filehandle and file_length to setFh
            if s in setFh:
                setFh[s].append([fh, file_length])
            else:
                setFh[s] = [[fh, file_length]]

            # We use the first line from before
            first_line = first_line.rstrip()

            # Poolcount header:
            fields = first_line.split("\t")
            if not (len(fields) >= 6):
                raise Exception("Too few fields in " + f)
            for i in range(nmeta):
                if not fields[i] == meta[i]:
                    raise Exception(
                        "Expected {} but field is {}".format(meta[i], fields[i])
                    )
            if not (s in setIndex):
                # first file for this set
                index_list = fields[nmeta:]
                # setIndex of setName is mapped to all the indexes
                setIndex[s] = index_list
                # check that all Indexes in @exps for this set are present
                index_dict = {x: 1 for x in index_list}


                for exp in all_vars["setExps"][s]:
                    # Each exp is a hash of Exp file column to value

                    # This just makes sure earlier processes are correct
                    if not exp["SetName"] == s:
                        raise Exception("SetName not what expected")
                    # Here is where we check if indexes align between 
                    # poolcount file and experiments file
                    if not exp["Index"] in index_dict:
                        logging.warning(
                            "WARNING! No field for indx {}".format(exp["Index"])
                            + " in "
                            + all_vars["indir"]
                            + "/"
                            + f
                            + ".poolcount!n"
                        )
            else:
                # Additional file for this set
                # expect is the list of expected indices
                expect = setIndex[s]
                for i in range(len(expect)):
                    field = fields[nmeta + i]
                    if not field == expect[i]:
                        raise Exception(
                            "Expected {} from first ".format(expect[i])
                            + "file but see {} in ".format(field)
                            + all_vars["indir"]
                            + "/"
                            + f
                            + ".poolcount"
                        )

    all_vars["setFh"] = setFh
    all_vars["setIndex"] = setIndex
    all_vars["expected_fl"] = expected_file_length

    return all_vars