# Path: imap_tools/consts.py
# SHORT_MONTH_NAMES = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
# 
# Path: imap_tools/utils.py
# def clean_uids(uid_set: Union[str, Iterable[str]]) -> str:
#     """
#     Prepare set of uid for use in IMAP commands
#     uid RE patterns are not strict and allow invalid combinations, but simple. Example: 2,4:7,9,12:*
#     :param uid_set:
#         str, that is comma separated uids
#         Iterable, that contains str uids
#     :return: str - uids, concatenated by a comma
#     """
#     # str
#     if type(uid_set) is str:
#         if re.search(r'^([\d*:]+,)*[\d*:]+$', uid_set):  # *optimization for already good str
#             return uid_set
#         uid_set = uid_set.split(',')
#     # check uid types
#     for uid in uid_set:
#         if type(uid) is not str:
#             raise TypeError('uid "{}" is not string'.format(str(uid)))
#         if not re.match(r'^[\d*:]+$', uid.strip()):
#             raise TypeError('Wrong uid: "{}"'.format(uid))
#     return ','.join(i.strip() for i in uid_set)
# 
# def quote(value: AnyStr) -> AnyStr:
#     if isinstance(value, str):
#         return '"' + value.replace('\\', '\\\\').replace('"', '\\"') + '"'
#     else:
#         return b'"' + value.replace(b'\\', b'\\\\').replace(b'"', b'\\"') + b'"'


import datetime
import itertools
import functools
from collections import UserString
from typing import Iterable, Optional, Dict, Any, List, Union
from .consts import SHORT_MONTH_NAMES
from .utils import clean_uids, quote
    def _gen_values(self, key: str, value: Any) -> Iterable[Any]:
        """Values generator"""
        # single value
        if key not in self.multi_key_allowed or isinstance(value, str):
            yield value
        else:
            try:
                # multiple values
                for i in value:
                    yield i
            except TypeError:
                # single value
                yield value

    def convert(self) -> List[str]:
        """
        :return: params in IMAP format
        """
        converted = []
        for key, raw_val in sorted(self.params.items(), key=lambda x: x[0]):
            for val in sorted(self._gen_values(key, raw_val)):
                convert_func = getattr(self, 'convert_{}'.format(key), None)
                if not convert_func:
                    raise KeyError('"{}" is an invalid parameter.'.format(key))
                converted.append(convert_func(key, val))
        return converted

    @classmethod
    def format_date(cls, value: datetime.date) -> str:
        """To avoid locale affects"""

# Path: imap_tools/consts.py
# SHORT_MONTH_NAMES = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
# 
# Path: imap_tools/utils.py
# def clean_uids(uid_set: Union[str, Iterable[str]]) -> str:
#     """
#     Prepare set of uid for use in IMAP commands
#     uid RE patterns are not strict and allow invalid combinations, but simple. Example: 2,4:7,9,12:*
#     :param uid_set:
#         str, that is comma separated uids
#         Iterable, that contains str uids
#     :return: str - uids, concatenated by a comma
#     """
#     # str
#     if type(uid_set) is str:
#         if re.search(r'^([\d*:]+,)*[\d*:]+$', uid_set):  # *optimization for already good str
#             return uid_set
#         uid_set = uid_set.split(',')
#     # check uid types
#     for uid in uid_set:
#         if type(uid) is not str:
#             raise TypeError('uid "{}" is not string'.format(str(uid)))
#         if not re.match(r'^[\d*:]+$', uid.strip()):
#             raise TypeError('Wrong uid: "{}"'.format(uid))
#     return ','.join(i.strip() for i in uid_set)
# 
# def quote(value: AnyStr) -> AnyStr:
#     if isinstance(value, str):
#         return '"' + value.replace('\\', '\\\\').replace('"', '\\"') + '"'
#     else:
#         return b'"' + value.replace(b'\\', b'\\\\').replace(b'"', b'\\"') + b'"'


# Path: imap_tools/query.py
import datetime
import itertools
import functools
from collections import UserString
from typing import Iterable, Optional, Dict, Any, List, Union
from .consts import SHORT_MONTH_NAMES
from .utils import clean_uids, quote

    def _gen_values(self, key: str, value: Any) -> Iterable[Any]:
        """Values generator"""
        # single value
        if key not in self.multi_key_allowed or isinstance(value, str):
            yield value
        else:
            try:
                # multiple values
                for i in value:
                    yield i
            except TypeError:
                # single value
                yield value

    def convert(self) -> List[str]:
        """
        :return: params in IMAP format
        """
        converted = []
        for key, raw_val in sorted(self.params.items(), key=lambda x: x[0]):
            for val in sorted(self._gen_values(key, raw_val)):
                convert_func = getattr(self, 'convert_{}'.format(key), None)
                if not convert_func:
                    raise KeyError('"{}" is an invalid parameter.'.format(key))
                converted.append(convert_func(key, val))
        return converted

    @classmethod
    def format_date(cls, value: datetime.date) -> str:
        """To avoid locale affects"""

        return '{}-{}-{}'.format(value.day, SHORT_MONTH_NAMES[value.month - 1], value.year)