import csv


def read_gene_sets_tidycsv(gs_locator, context=None):
    """
    Read & parse the Tidy CSV format, applying validation checks for mandatory
    values, and de-duping rules.

    Format is a four-column CSV, with a mandatory header row, and optional "#" prefixed
    comments.  Format:

        gene_set_name, gene_set_description, gene_symbol, gene_description

    gene_set_name must be non-null; others are optional.

    Returns: a dictionary of the shape (values in angle-brackets vary):

        {
            <string, a gene set name>: {
                "geneset_name": <string, a gene set name>,
                "geneset_description": <a string or None>,
                "genes": [
                    {
                        "gene_symbol": <string, a gene symbol or name>,
                        "gene_description": <a string or None>
                    },
                    ...
                ]
            },
            ...
        }
    """

    class myDialect(csv.excel):
        skipinitialspace = False

    gene_sets = {}
    with gs_locator.local_handle() as fname:
        header_read = False
        with open(fname, newline="") as f:
            reader = csv.reader(f, dialect=myDialect())
            for row in reader:
                if len(row) <= 3 or not header_read:
                    header_read = True
                    continue

                geneset_description, geneset_name, diffExp = row[:3]
                x = "//;;//" if (diffExp=="TRUE" or diffExp == "True" or diffExp == "true") else ""
                geneset_description+=x
                gene_symbols = row[3:]
                try:
                    gene_symbols = gene_symbols[:gene_symbols.index("")]
                except:
                    pass
                
                if geneset_description in gene_sets:
                    gs = gene_sets[geneset_description]
                else:
                    gs = gene_sets[geneset_description] = {}
                
                if geneset_name in gs:
                    gene_symbols = list(set(gene_symbols).union(gs[geneset_name]))

                gs[geneset_name] = gene_symbols


    return gene_sets