<commit_before># -*- coding: utf-8 -*-

"""Provides personal data."""

import hashlib
import re
from string import ascii_letters, digits, punctuation
from typing import Optional, Union

from mimesis.data import (
    BLOOD_GROUPS,
    CALLING_CODES,
    EMAIL_DOMAINS,
    GENDER_SYMBOLS,
    SEXUALITY_SYMBOLS,
    SOCIAL_NETWORKS,
    USERNAMES,
)
from mimesis.enums import Gender, SocialNetwork, TitleType
from mimesis.exceptions import NonEnumerableError
from mimesis.providers.base import BaseDataProvider
from mimesis.random import get_random_item

__all__ = ['Person']


class Person(BaseDataProvider):
    """Class for generating personal data."""

    def __init__(self, *args, **kwargs) -> None:
        """Initialize attributes.

        :param locale: Current locale.
        :param seed: Seed.
        """
        super().__init__(*args, **kwargs)
        self._datafile = 'person.json'
        self.pull(self._datafile)
        self._store = {
            'age': 0,
        }

    class Meta:
        """Class for metadata."""

        name = 'person'

    def age(self, minimum: int = 16, maximum: int = 66) -> int:
        """Get a random integer value.

        :param maximum: Maximum value of age.
        :param minimum: Minimum value of age.
        :return: Random integer.

        :Example:
            23.
        """
        age = self.random.randint(minimum, maximum)
        self._store['age'] = age
        return age

    def work_experience(self, working_start_age: int = 22) -> int:
        """Get a work experience.

        :param working_start_age: Age then person start to work.
        :return: Depend on previous generated age.
        """
        age = self._store['age']
        if age == 0:
            age = self.age()

        return max(age - working_start_age, 0)

    def name(self, gender: Optional[Gender] = None) -> str:
        """Generate a random name.

        :param gender: Gender's enum object.
        :return: Name.

        :Example:
            John.
        """
        key = self._validate_enum(gender, Gender)
        names = self._data['names'].get(key)
        return self.random.choice(names)

    def surname(self, gender: Optional[Gender] = None) -> str:
        """Generate a random surname.

        :param gender: Gender's enum object.
        :return: Surname.

        :Example:
            Smith.
        """
        surnames = self._data['surnames']

        # Surnames separated by gender.
        if isinstance(surnames, dict):
            key = self._validate_enum(gender, Gender)
            surnames = surnames[key]

        return self.random.choice(surnames)

    def last_name(self, gender: Optional[Gender] = None) -> str:
        """Generate a random last name.

        ..note: An alias for self.surname().

        :param gender: Gender's enum object.
        :return: Last name.
        """
        return self.surname(gender)

    def title(self, gender: Optional[Gender] = None,
              title_type: Optional[TitleType] = None) -> str:
        """Generate a random title for name.

        You can generate random prefix or suffix
        for name using this method.

        :param gender: The gender.
        :param title_type: TitleType enum object.
        :return: The title.
        :raises NonEnumerableError: if gender or title_type in incorrect format.

        :Example:
            PhD.
        """
        gender_key = self._validate_enum(gender, Gender)
        title_key = self._validate_enum(title_type, TitleType)

        titles = self._data['title'][gender_key][title_key]
        return self.random.choice(titles)

    def full_name(self, gender: Optional[Gender] = None,
                  reverse: bool = False) -> str:
        """Generate a random full name.

        :param reverse: Return reversed full name.
        :param gender: Gender's enum object.
        :return: Full name.

        :Example:
            <NAME>.
        """
        if gender is None:
            gender = get_random_item(Gender, rnd=self.random)

        if gender and isinstance(gender, Gender):
            gender = gender
        else:
            raise NonEnumerableError(Gender)

        fmt = '{1} {0}' if reverse else '{0} {1}'
        return fmt.format(
            self.name(gender),
            self.surname(gender),
        )

    def username(self, template: Optional[str] = None) -> str:
        """Generate username by template.

        Supported template placeholders: (U, l, d)

        Supported separators: (-, ., _)

        Template must contain at least one "U" or "l" placeholder.

        If template is None one of the following templates is used:
        ('U_d', 'U.d', 'U-d', 'UU-d', 'UU.d', 'UU_d',
        'ld', 'l-d', 'Ud', 'l.d', 'l_d', 'default')

        :param template: Template.
        :return: Username.
        :raises KeyError: If template is not supported.

        :Example:
            Celloid1873
        """
        MIN_DATE = 1800
        MAX_DATE = 2070
        DEFAULT_TEMPLATE = 'l.d'

        templates = ('U_d', 'U.d', 'U-d', 'UU-d', 'UU.d', 'UU_d',
                     'ld', 'l-d', 'Ud', 'l.d', 'l_d', 'default')

        if template is None:
            template = self.random.choice(templates)

        if template == 'default':
            template = DEFAULT_TEMPLATE

        if re.fullmatch(r'[Ul\.\-\_d]*[Ul]+[Ul\.\-\_d]*', template) is None:
            raise KeyError(
                "Template '{}' is not supported.".format(template))

        tags = re.findall(r'[Uld\.\-\_]', template)

        username = ''
        for tag in tags:
            if tag == 'U':
                username += self.random.choice(USERNAMES).capitalize()
            elif tag == 'l':
                username += self.random.choice(USERNAMES)
            elif tag == 'd':
                username += str(self.random.randint(MIN_DATE, MAX_DATE))
            elif tag in '-_.':
                username += tag

        return username

    def password(self, length: int = 8, hashed: bool = False) -> str:
        """Generate a password or hash of password.

        :param length: Length of password.<commit_msg>Change if statement in username()<commit_after># -*- coding: utf-8 -*-

"""Provides personal data."""

import hashlib
import re
from string import ascii_letters, digits, punctuation
from typing import Optional, Union

from mimesis.data import (
    BLOOD_GROUPS,
    CALLING_CODES,
    EMAIL_DOMAINS,
    GENDER_SYMBOLS,
    SEXUALITY_SYMBOLS,
    SOCIAL_NETWORKS,
    USERNAMES,
)
from mimesis.enums import Gender, SocialNetwork, TitleType
from mimesis.exceptions import NonEnumerableError
from mimesis.providers.base import BaseDataProvider
from mimesis.random import get_random_item

__all__ = ['Person']


class Person(BaseDataProvider):
    """Class for generating personal data."""

    def __init__(self, *args, **kwargs) -> None:
        """Initialize attributes.

        :param locale: Current locale.
        :param seed: Seed.
        """
        super().__init__(*args, **kwargs)
        self._datafile = 'person.json'
        self.pull(self._datafile)
        self._store = {
            'age': 0,
        }

    class Meta:
        """Class for metadata."""

        name = 'person'

    def age(self, minimum: int = 16, maximum: int = 66) -> int:
        """Get a random integer value.

        :param maximum: Maximum value of age.
        :param minimum: Minimum value of age.
        :return: Random integer.

        :Example:
            23.
        """
        age = self.random.randint(minimum, maximum)
        self._store['age'] = age
        return age

    def work_experience(self, working_start_age: int = 22) -> int:
        """Get a work experience.

        :param working_start_age: Age then person start to work.
        :return: Depend on previous generated age.
        """
        age = self._store['age']
        if age == 0:
            age = self.age()

        return max(age - working_start_age, 0)

    def name(self, gender: Optional[Gender] = None) -> str:
        """Generate a random name.

        :param gender: Gender's enum object.
        :return: Name.

        :Example:
            John.
        """
        key = self._validate_enum(gender, Gender)
        names = self._data['names'].get(key)
        return self.random.choice(names)

    def surname(self, gender: Optional[Gender] = None) -> str:
        """Generate a random surname.

        :param gender: Gender's enum object.
        :return: Surname.

        :Example:
            Smith.
        """
        surnames = self._data['surnames']

        # Surnames separated by gender.
        if isinstance(surnames, dict):
            key = self._validate_enum(gender, Gender)
            surnames = surnames[key]

        return self.random.choice(surnames)

    def last_name(self, gender: Optional[Gender] = None) -> str:
        """Generate a random last name.

        ..note: An alias for self.surname().

        :param gender: Gender's enum object.
        :return: Last name.
        """
        return self.surname(gender)

    def title(self, gender: Optional[Gender] = None,
              title_type: Optional[TitleType] = None) -> str:
        """Generate a random title for name.

        You can generate random prefix or suffix
        for name using this method.

        :param gender: The gender.
        :param title_type: TitleType enum object.
        :return: The title.
        :raises NonEnumerableError: if gender or title_type in incorrect format.

        :Example:
            PhD.
        """
        gender_key = self._validate_enum(gender, Gender)
        title_key = self._validate_enum(title_type, TitleType)

        titles = self._data['title'][gender_key][title_key]
        return self.random.choice(titles)

    def full_name(self, gender: Optional[Gender] = None,
                  reverse: bool = False) -> str:
        """Generate a random full name.

        :param reverse: Return reversed full name.
        :param gender: Gender's enum object.
        :return: Full name.

        :Example:
            <NAME>.
        """
        if gender is None:
            gender = get_random_item(Gender, rnd=self.random)

        if gender and isinstance(gender, Gender):
            gender = gender
        else:
            raise NonEnumerableError(Gender)

        fmt = '{1} {0}' if reverse else '{0} {1}'
        return fmt.format(
            self.name(gender),
            self.surname(gender),
        )

    def username(self, template: Optional[str] = None) -> str:
        """Generate username by template.

        Supported template placeholders: (U, l, d)

        Supported separators: (-, ., _)

        Template must contain at least one "U" or "l" placeholder.

        If template is None one of the following templates is used:
        ('U_d', 'U.d', 'U-d', 'UU-d', 'UU.d', 'UU_d',
        'ld', 'l-d', 'Ud', 'l.d', 'l_d', 'default')

        :param template: Template.
        :return: Username.
        :raises KeyError: If template is not supported.

        :Example:
            Celloid1873
        """
        MIN_DATE = 1800
        MAX_DATE = 2070
        DEFAULT_TEMPLATE = 'l.d'

        templates = ('U_d', 'U.d', 'U-d', 'UU-d', 'UU.d', 'UU_d',
                     'ld', 'l-d', 'Ud', 'l.d', 'l_d', 'default')

        if template is None:
            template = self.random.choice(templates)

        if template == 'default':
            template = DEFAULT_TEMPLATE

        if not re.fullmatch(r'[Ul\.\-\_d]*[Ul]+[Ul\.\-\_d]*', template):
            raise KeyError(
                "Template '{}' is not supported.".format(template))

        tags = re.findall(r'[Uld\.\-\_]', template)

        username = ''
        for tag in tags:
            if tag == 'U':
                username += self.random.choice(USERNAMES).capitalize()
            elif tag == 'l':
                username += self.random.choice(USERNAMES)
            elif tag == 'd':
                username += str(self.random.randint(MIN_DATE, MAX_DATE))
            elif tag in '-_.':
                username += tag

        return username

    def password(self, length: int = 8, hashed: bool = False) -> str:
        """Generate a password or hash of password.

        :param length: Length of password.
{'fraction_non_alphanumeric': 0.1189470263243419, 'fraction_numerical': 0.004712382190445239, 'mean_word_length': 1.9588942307692307, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5496067', 'n_tokens_mistral': 3719, 'n_tokens_neox': 3486, 'n_words': 1050}