Identify pathways overrepresented in a constructed feature
    according to a user-specified criterion (see `gene_signature_definitions`
    in the parameters list below) for identifying the feature's gene
    signature. Donato et al.'s (2013) algorithm for pathway crosstalk
    correction (removes gene overlap between pathway definitions) is applied to
    the pathway definitions before overrepresentation analysis.
    Here, we refer to it as *overlap-correction*.

    Parameters
    -----------
    feature_weight_vector : pandas.Series(float), shape = n
      A vector containing gene weights
    pathway_definitions : dict(str -> set(str))
      A pathway (key) is defined by a set of genes (value).
    gene_signature_definition : functools.partial callable,
                                returns (set(), set())
      Accepts the `feature_weight_vector` as input. Provide a function to
      distinguish positive and/or negative gene signatures.
      Both a positive & a negative signature may be appropriate if the
      feature's gene weight distribution spans positive and negative values.
      If this is not the case, specify a single gene signature by returning
      one of the sides as an empty set.
    alpha : float (default=0.05)
      Significance level for pathway enrichment.
    correct_all_genes : bool (default=True)
      The overlap correction procedure is applied independently to both
      the gene signature (union of positive and negative signature when
      applicable) _and_ the genes outside of the signature (termed
      *remaining* genes).
      If not `correct_all_genes`, overlap correction is not applied to
      the set of remaining genes.
    metadata : bool (default=False)
      Gather information to store in a MongoDB-backed Flask web application.
      Users can interact with the PathCORE-T-produced network and analyze the
      genes underlying a pair of pathways linked in the network.

    Returns
    -----------
    tup([pandas.DataFrame|None], dict())
    tup[0] : pandas.DataFrame: dataframe of significant pathways
           | None if the gene signature does not contain any genes in the
                  pathway definitions
    tup[1] : if `metadata`:
             {"positive signature": <set() positive gene signature>,
              "negative signature": <set() negative gene signature>,
              "pathway definitions": <dict(str -> set())
                overlap-corrected definitions--only signature genes>}
             else: {}

def pathway_enrichment_with_overlap_correction(feature_weight_vector,
                                               pathway_definitions,
                                               gene_signature_definition,
                                               alpha=0.05,
                                               correct_all_genes=True,
                                               metadata=False):
    """Identify pathways overrepresented in a constructed feature
    according to a user-specified criterion (see `gene_signature_definitions`
    in the parameters list below) for identifying the feature's gene
    signature. Donato et al.'s (2013) algorithm for pathway crosstalk
    correction (removes gene overlap between pathway definitions) is applied to
    the pathway definitions before overrepresentation analysis.
    Here, we refer to it as *overlap-correction*.

    Parameters
    -----------
    feature_weight_vector : pandas.Series(float), shape = n
      A vector containing gene weights
    pathway_definitions : dict(str -> set(str))
      A pathway (key) is defined by a set of genes (value).
    gene_signature_definition : functools.partial callable,
                                returns (set(), set())
      Accepts the `feature_weight_vector` as input. Provide a function to
      distinguish positive and/or negative gene signatures.
      Both a positive & a negative signature may be appropriate if the
      feature's gene weight distribution spans positive and negative values.
      If this is not the case, specify a single gene signature by returning
      one of the sides as an empty set.
    alpha : float (default=0.05)
      Significance level for pathway enrichment.
    correct_all_genes : bool (default=True)
      The overlap correction procedure is applied independently to both
      the gene signature (union of positive and negative signature when
      applicable) _and_ the genes outside of the signature (termed
      *remaining* genes).
      If not `correct_all_genes`, overlap correction is not applied to
      the set of remaining genes.
    metadata : bool (default=False)
      Gather information to store in a MongoDB-backed Flask web application.
      Users can interact with the PathCORE-T-produced network and analyze the
      genes underlying a pair of pathways linked in the network.

    Returns
    -----------
    tup([pandas.DataFrame|None], dict())
    tup[0] : pandas.DataFrame: dataframe of significant pathways
           | None if the gene signature does not contain any genes in the
                  pathway definitions
    tup[1] : if `metadata`:
             {"positive signature": <set() positive gene signature>,
              "negative signature": <set() negative gene signature>,
              "pathway definitions": <dict(str -> set())
                overlap-corrected definitions--only signature genes>}
             else: {}
    """
    genes_in_pathway_definitions = set.union(*pathway_definitions.values())
    positive_gene_signature, negative_gene_signature = \
        gene_signature_definition(feature_weight_vector)
    gene_signature = ((positive_gene_signature | negative_gene_signature) &
                      genes_in_pathway_definitions)
    if not gene_signature:
        return (None, {})

    additional_information = {}
    n_genes = len(feature_weight_vector)

    if metadata:
        additional_information["positive_signature"] = (
          positive_gene_signature & gene_signature)
        additional_information["negative_signature"] = (
          negative_gene_signature & gene_signature)
    corrected_pathway_definitions = crosstalk_correction(
        pathway_definitions,
        gene_set=gene_signature,
        all_genes=correct_all_genes)

    if metadata:
        collect_signature_pathway_definitions = {}
        for pathway, (signature_defn, remaining_defn) in \
                corrected_pathway_definitions.items():
            collect_signature_pathway_definitions[pathway] = signature_defn
        additional_information["pathway_definitions"] = \
            collect_signature_pathway_definitions

    pathway_positive_series = single_side_pathway_enrichment(
        corrected_pathway_definitions, positive_gene_signature, n_genes)
    pathway_negative_series = single_side_pathway_enrichment(
        corrected_pathway_definitions, negative_gene_signature, n_genes)

    pvalue_information = pathway_positive_series.append(
        pathway_negative_series)
    side_information = _pathway_side_information(
        pathway_positive_series, pathway_negative_series,
        pvalue_information.index)
    significant_pathways = _significant_pathways_dataframe(
        pvalue_information, side_information, alpha)
    return significant_pathways, additional_information