# Path: src/cutadapt/align.py
# START_WITHIN_SEQ1 = 1
# START_WITHIN_SEQ2 = 2
# STOP_WITHIN_SEQ1 = 4
# STOP_WITHIN_SEQ2 = 8
# SEMIGLOBAL = 15
#     REFERENCE_START = 1  # a prefix of the reference may be skipped at no cost
#     QUERY_START = 2  # a prefix of the query may be skipped at no cost
#     REFERENCE_END = 4  # a suffix of the reference may be skipeed at no cost
#     QUERY_STOP = 8  # a suffix of the query may be skipeed at no cost
#     SEMIGLOBAL = 15  # all of the above
# class EndSkip(IntFlag):
# def edit_distance(s: str, t: str) -> int:
# def hamming_sphere(s: str, k: int) -> Iterator[str]:
# def hamming_environment(s: str, k: int) -> Iterator[Tuple[str, int, int]]:
# def naive_edit_environment(s: str, k: int) -> Iterator[str]:
# def edit_environment(s: str, k: int) -> Iterator[Tuple[str, int, int]]:
# def slow_edit_environment(s: str, k: int) -> Iterator[Tuple[str, int, int]]:


import logging
from enum import IntFlag
from collections import defaultdict
from typing import Optional, Tuple, Sequence, Dict, Any, List, Union
from abc import ABC, abstractmethod
from .align import (
    EndSkip,
    Aligner,
    PrefixComparer,
    SuffixComparer,
    edit_environment,
    hamming_environment,
)
"""
Adapter finding and trimming classes

The ...Adapter classes are responsible for finding adapters.
The ...Match classes trim the reads.
"""


logger = logging.getLogger()


class InvalidCharacter(Exception):
    pass


# TODO remove this enum, this should be within each Adapter class
class Where(IntFlag):
    """
    Aligner flag combinations for all adapter types.

    "REFERENCE" is the adapter sequence, "QUERY" is the read sequence
    """

    BACK = EndSkip.QUERY_START | EndSkip.QUERY_STOP | EndSkip.REFERENCE_END
    FRONT = EndSkip.QUERY_START | EndSkip.QUERY_STOP | EndSkip.REFERENCE_START
    PREFIX = EndSkip.QUERY_STOP
    SUFFIX = EndSkip.QUERY_START
    # Just like FRONT/BACK, but without internal matches

# Path: src/cutadapt/align.py
# START_WITHIN_SEQ1 = 1
# START_WITHIN_SEQ2 = 2
# STOP_WITHIN_SEQ1 = 4
# STOP_WITHIN_SEQ2 = 8
# SEMIGLOBAL = 15
#     REFERENCE_START = 1  # a prefix of the reference may be skipped at no cost
#     QUERY_START = 2  # a prefix of the query may be skipped at no cost
#     REFERENCE_END = 4  # a suffix of the reference may be skipeed at no cost
#     QUERY_STOP = 8  # a suffix of the query may be skipeed at no cost
#     SEMIGLOBAL = 15  # all of the above
# class EndSkip(IntFlag):
# def edit_distance(s: str, t: str) -> int:
# def hamming_sphere(s: str, k: int) -> Iterator[str]:
# def hamming_environment(s: str, k: int) -> Iterator[Tuple[str, int, int]]:
# def naive_edit_environment(s: str, k: int) -> Iterator[str]:
# def edit_environment(s: str, k: int) -> Iterator[Tuple[str, int, int]]:
# def slow_edit_environment(s: str, k: int) -> Iterator[Tuple[str, int, int]]:


# Path: src/cutadapt/adapters.py
import logging
from enum import IntFlag
from collections import defaultdict
from typing import Optional, Tuple, Sequence, Dict, Any, List, Union
from abc import ABC, abstractmethod
from .align import (
    EndSkip,
    Aligner,
    PrefixComparer,
    SuffixComparer,
    edit_environment,
    hamming_environment,
)

"""
Adapter finding and trimming classes

The ...Adapter classes are responsible for finding adapters.
The ...Match classes trim the reads.
"""


logger = logging.getLogger()


class InvalidCharacter(Exception):
    pass


# TODO remove this enum, this should be within each Adapter class
class Where(IntFlag):
    """
    Aligner flag combinations for all adapter types.

    "REFERENCE" is the adapter sequence, "QUERY" is the read sequence
    """

    BACK = EndSkip.QUERY_START | EndSkip.QUERY_STOP | EndSkip.REFERENCE_END
    FRONT = EndSkip.QUERY_START | EndSkip.QUERY_STOP | EndSkip.REFERENCE_START
    PREFIX = EndSkip.QUERY_STOP
    SUFFIX = EndSkip.QUERY_START
    # Just like FRONT/BACK, but without internal matches

    FRONT_NOT_INTERNAL = EndSkip.REFERENCE_START | EndSkip.QUERY_STOP