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

import logging
import telnetlib


class TelnetWrapper:
    """
    Telnet based command wrapper for CMaNGOS

    This class interact with a CMaNGOS server by Telnet connection.
    Functions return a boolean statement or formatted data.
    """
    def __init__(self, host: str, port: str, user: str, pwd: str, log_level=logging.INFO):
        # TODO DOC
        logging.basicConfig(filename='../../wrapper.log', level=log_level)
        self.host = host
        self.port = port
        self.user = user
        self.pwd = <PASSWORD>
        self.tn_client = None
        self.open_session()
        self.connect()

    def is_session_open(self):
        """
        Return Telnet session state

        True if session established, False otherwise
        :return: True if the session is opened with the CMaNGOS server
        """
        return self.tn_client is not None and self.tn_client.get_socket()

    def open_session(self):
        """
        Try to open a Telnet session with the CMaNGOS server

        Do nothing if already in a connected state
        """
        logging.info('Try to open a Telnet session on ' + self.host + ':' + self.port)
        if not self.is_session_open():
            self.tn_client = telnetlib.Telnet(host=self.host, port=self.port)
            logging.info('Telnet client connected to ' + self.tn_client.host + ':' + self.tn_client.port)
        else:
            logging.info('Already connected to a Telnet session')

    def connect(self):
        """
        Try to login into CMaNGOS server cli prompt

        Wait for credential questions and answer them with given ones.
        """
        logging.debug('Waiting for username prompt')
        self.tn_client.read_until(b"Username:")
        logging.debug('Sending username : ' + self.user)
        self.tn_client.write(self.user.encode('ascii') + b" \n")
        logging.debug('Waiting for password prompt')
        self.tn_client.read_until(b"Password:")
        logging.debug('Sending password : ' + self.pwd)
        self.tn_client.write(self.pwd.encode('ascii') + b" \n")
        self.wait_cli_prompt()
        logging.info('Successfully connected as ' + self.user)

    def wait_cli_prompt(self):
        """
        Flush data stream before doing a command

        Make sure there is no more data available to read
        """
        logging.debug('Waiting for a ready cli prompt')
        self.tn_client.read_until(b"mangos>", timeout=0.2)
        logging.debug('Sending a newline character')
        self.tn_client.write(b"\n")
        logging.debug('Waiting for a ready cli prompt')
        self.tn_client.read_until(b"mangos>")
        logging.debug('Cli prompt ready')

    def disconnect(self):
        """
        Disconnect from CMaNGOS cli prompt

        Send 'quit' command to disconnect from CMaNGOS cli prompt
        """
        logging.debug('Disconnecting ' + self.user + '; exiting cli prompt')
        self.tn_client.write(b"quit \n")

    def close_session(self):
        """
        Close the Telnet session
        """
        logging.info('Closing Telnet connection to ' + self.host + ':' + self.port)
        self.tn_client.close()

    def close(self):
        """
        Disconnect from CMaNGOS cli prompt and close Telnet session
        """
        self.disconnect()
        self.close_session()

    def execute_command(self, command: str):
        """
        Execute a command into CMaNGOS cli prompt and return the result

        Send command into CMaNGOS cli prompt and read answered data
        :arg command 'str' to execute
        :return: True on success, False otherwise
        """
        self.wait_cli_prompt()
        logging.info('Execute command : ' + command)
        self.tn_client.write(bytes(command, 'UTF-8'))
        result = str(self.tn_client.read_until(b"mangos>")).replace('\\r', '')  # can remove '\r' char here
        logging.debug('Response ' + result)
        return result

# Account commands -----------------------------------------------------------------------------------------------------

    def get_online_accounts(self):
        """
        Get currently online accounts

        :return: currently connected account as a dict
        """
        accounts = {}
        result = self.execute_command('account onlinelist \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

    def account_get_characters(self, username: str):
        """
        Get account characters as a list

        :param username: account name
        :return: account characters as a dict
        """
        characters = {}
        result = self.execute_command('account characters ' + username + ' \n')
        result = result.split('\\n')[3:-2]
        for character in result:
            (guid, char_name, char_race, char_class, char_level) = character[1:-1].split("|")
            characters[guid.strip()] = {
                'guid': guid.strip(),
                'name': char_name.strip(),
                'race': char_race.strip(),
                'class': char_class.strip(),
                'level': char_level.strip()
            }
        return characters

    def account_create(self, username: str, password: str):
        """
        Create a new account with a login and a password

        :param username: new account login
        :param password: new account password
        :return: True on success, False otherwise
        """
        result = self.execute_command('account create ' + username + ' ' + password + ' \n')
        return 'Account with this name already exist' not in result

    def account_set_password(self, username: str, password: str):
        """
        Replace an account password with a new one

        :param username: account login
        :param password: new account password
        :return: True on success, False otherwise
        """
        result = self.execute_command('account set password ' + username + ' ' + password + ' ' + password + ' \n')
        return 'The password was changed' in result

    def account_set_addon(self, username: str, addon: int):
        """
        Set expansion access to an account

        :param username: account login
        :param addon: expansion id (0, 1, 2 ...)
        :return: True on success, False otherwise
        """
        if addon < 0:
            return False  # wrong value
        result = self.execute_command('account set addon ' + username + ' ' + str(addon) + ' \n')
        return 'has been granted ' + str(addon) + ' expansion rights.' in result

    def account_set_gm_level(self, username: str, gm_level: int):
        """
        Set account permission level

        :param username: account login
        :param gm_level: gm level (0: player, 1: modo, 2: gm, 3: admin)
        :return: True on success, False otherwise
        """
        if gm_level < 0 or gm_level > 3:
            return False  # wrong value
        result = self.execute_command('account set gmlevel ' + username + ' ' + str(gm_level) + ' \n')
        return 'You change security level of account ' in result

    def account_delete(self, username: str):
        """
        Delete an account

        :param username: account login
        :return: True on success, False otherwise
        """
        result = self.execute_command('account delete ' + username + ' \n')
        return 'Account deleted:' in result

    def account_search_from_email(self, user_email: str, limit: int = 100):
        """
        Search in accounts corresponding email (or fragment)

        :param user_email: account email (or a fragment) to search from
        :param limit: result number limit
        :return: found accounts as a map
        """
        accounts = {}
        result = self.execute_command('lookup account email ' + user_email + ' ' + str(limit) + ' \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

    def account_search_from_name(self, username: str, limit: int = 100):
        """
        Search in accounts corresponding login (or fragment)

        :param username: account login (or a fragment) to search from
        :param limit: result number limit
        :return: found accounts as a map
        """
        accounts = {}
        result = self.execute_command('lookup account name ' + username + ' ' + str(limit) + ' \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

    def account_search_from_ip(self, ip_addr: str, limit: int = 100):
        """
        Search in accounts corresponding last used ip address (or fragment)

        :param ip_addr: account last used ip address (or a fragment) to search from
        :param limit: result number limit
        :return: found accounts as a map
        """
        accounts = {}
        result = self.execute_command('lookup account ip ' + ip_addr + ' ' + str(limit) + ' \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

# Achievement commands -------------------------------------------------------------------------------------------------

    def achievement_details(self, achievement_id: int):
        """
        Get details about an achievement

        :param achievement_id: the achievement id
        :return: details about the acvhievement
        """
        result = self.execute_command('achievement ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_search(self, achievement_name: str):
        """
        Search in achievements with a name (or a fragment)

        :param achievement_name: name to lookup (or a fragment)
        :return: list of achievement results
        """
        result = self.execute_command('lookup achievement ' + achievement_name + ' \n')
        return result  # TODO

    def achievement_state(self, character: str, achievement_id: int):
        # TODO DOC
        result = self.execute_command('achievement ' + character + ' ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_set_complete(self, character: str, achievement_id: int):
        # TODO DOC
        result = self.execute_command('achievement add ' + character + ' ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_remove(self, character: str, achievement_id: int):
        # TODO DOC
        result = self.execute_command('achievement remove ' + character + ' ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_criteria_set_complete_progress(self, character: str, criteria_id: int):
        # TODO DOC
        result = self.execute_command('achievement criteria add ' + character + ' ' + str(criteria_id) + ' \n')
        return result  # TODO

    def achievement_criteria_add_progress(self, character: str, criteria_id: int, change: int):
        # TODO DOC
        result = self.execute_command('achievement criteria add ' + character +
                                      ' ' + str(criteria_id) + ' ' + str(change) + ' \n')
        return result  # TODO

    def achievement_criteria_reset_progress(self, character: str, criteria_id: int):
        # TODO DOC
        result = self.execute_command('achievement criteria remove ' + character + ' ' + str(criteria_id) + ' \n')
        return result  # TODO

    def achievement_criteria_reduce_progress(self, character: str, criteria_id: int, change: int):
        # TODO DOC
        result = self.execute_command('achievement criteria remove ' + character +
                                      ' ' + str(criteria_id) + ' ' + str(change) + ' \n')
        return result  # TODO

# AHBot commands -------------------------------------------------------------------------------------------------------

    def ahbot_reload_conf(self):
        """
        Reload AHBot configuration

        :return: True if success, False otherwise
        """
        result = self.execute_command('ahbot reload \n')
        return 'All config are reloaded from ahbot configuration file.' in result

    def ahbot_status(self, detailled: bool = False):
        # TODO DOC
        command = 'ahbot status '
        if detailled:
            command += 'all '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def ahbot_reset_auction(self, force_all_rebuild: bool = False):
        # TODO DOC
        command = 'ahbot rebuild '
        if force_all_rebuild:
            command += 'all '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def ahbot_set_all_quota(self, grey_items: int, white_items: int, green_items: int,
                            blue_items: int, purple_items: int, orange_items: int, yellow_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount ' + str(grey_items) + ' ' + str(white_items) +
                                      ' ' + str(green_items) + ' ' + str(blue_items) + ' ' + str(purple_items) +
                                      ' ' + str(orange_items) + ' ' + str(yellow_items) + ' \n')
        return result  # TODO

    def ahbot_set_grey_quota(self, grey_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount grey ' + str(grey_items) + ' \n')
        return result  # TODO

    def ahbot_set_white_quota(self, white_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount white ' + str(white_items) + ' \n')
        return result  # TODO

    def ahbot_set_green_quota(self, green_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount green ' + str(green_items) + ' \n')
        return result  # TODO

    def ahbot_set_blue_quota(self, blue_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount blue ' + str(blue_items) + ' \n')
        return result  # TODO

    def ahbot_set_purple_quota(self, purple_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount purple ' + str(purple_items) + ' \n')
        return result  # TODO

    def ahbot_set_orange_quota(self, orange_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount orange ' + str(orange_items) + ' \n')
        return result  # TODO

    def ahbot_set_yellow_quota(self, yellow_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount yellow ' + str(yellow_items) + ' \n')
        return result  # TODO

    def ahbot_set_ratios(self, alliance_ratio: int, horde_ratio: int, neutral_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio ' + str(alliance_ratio) +
                                      ' ' + str(horde_ratio) + ' ' + str(neutral_ratio) + ' \n')
        return result  # TODO

    def ahbot_set_alliance_ratio(self, alliance_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio alliance ' + str(alliance_ratio) + ' \n')
        return result  # TODO

    def ahbot_set_horde_ratio(self, horde_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio horde ' + str(horde_ratio) + ' \n')
        return result  # TODO

    def ahbot_set_neutral_ratio(self, neutral_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio neutral ' + str(neutral_ratio) + ' \n')
        return result  # TODO

# Auction commands -----------------------------------------------------------------------------------------------------

    def auction_show_alliance(self):
        # TODO DOC
        result = self.execute_command('auction alliance \n')
        return result  # TODO

    def auction_show_horde(self):
        # TODO DOC
        result = self.execute_command('auction horde \n')
        return result  # TODO

    def auction_show_goblin(self):
        # TODO DOC
        result = self.execute_command('auction goblin \n')
        return result  # TODO

    def auction_add_item_alliance(self, item_id: int, item_count: int = 1, min_bid: int = 1, buy_out: int = None,
                                  long_duration: bool = False, very_long_duration: bool = False):
        # TODO DOC
        command = 'auction item alliance ' + str(item_id) + ':' + str(item_count) + ' '
        if buy_out:
            command += str(min_bid) + ' ' + str(buy_out) + ' '
        if long_duration:
            if very_long_duration:
                command += 'very'
            command += 'long'
        else:
            command += 'short'
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def auction_add_item_horde(self, item_id: int, item_count: int = 1, min_bid: int = 1, buy_out: int = None,
                               long_duration: bool = False, very_long_duration: bool = False):
        # TODO DOC
        command = 'auction item horde ' + str(item_id) + ':' + str(item_count) + ' '
        if buy_out:
            command += str(min_bid) + ' ' + str(buy_out) + ' '
        if long_duration:
            if very_long_duration:
                command += 'very'
            command += 'long'
        else:
            command += 'short'
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def auction_add_item_goblin(self, item_id: int, item_count: int = 1, min_bid: int = 1, buy_out: int = None,
                                long_duration: bool = False, very_long_duration: bool = False):
        # TODO DOC
        command = 'auction item goblin ' + str(item_id) + ':' + str(item_count) + ' '
        if buy_out:
            command += str(min_bid) + ' ' + str(buy_out) + ' '
        if long_duration:
            if very_long_duration:
                command += 'very'
            command += 'long'
        else:
            command += 'short'
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

# Ban commands ---------------------------------------------------------------------------------------------------------

    def ban_account(self, username: str, reason: str, bantime: str = '-1'):
        # TODO DOC
        result = self.execute_command('ban account ' + username + ' ' + bantime + ' ' + reason + ' \n')
        return result  # TODO

    def ban_character(self, character: str, reason: str, bantime: str = '-1'):
        # TODO DOC
        result = self.execute_command('ban character ' + character + ' ' + bantime + ' ' + reason + ' \n')
        return result  # TODO

    def ban_ip(self, ip_addr: str, reason: str, bantime: str = '-1'):
        # TODO DOC
        result = self.execute_command('ban ip ' + ip_addr + ' ' + bantime + ' ' + reason + ' \n')
        return result  # TODO

    def ban_info_account(self, username: str):
        # TODO DOC
        result = self.execute_command('baninfo account ' + username + ' \n')
        return result  # TODO

    def ban_info_character(self, character: str):
        # TODO DOC
        result = self.execute_command('baninfo character ' + character + ' \n')
        return result  # TODO

    def ban_info_ip(self, ip_addr: str):
        # TODO DOC
        result = self.execute_command('baninfo ip ' + ip_addr + ' \n')
        return result  # TODO

    def ban_list_account(self):
        # TODO DOC
        result = self.execute_command('banlist account \n')
        return result  # TODO

    def ban_list_character(self):
        # TODO DOC
        result = self.execute_command('banlist character \n')
        return result  # TODO

    def ban_list_ip(self):
        # TODO DOC
        result = self.execute_command('banlist ip \n')
        return result  # TODO

    def ban_list_search_account(self, username: str):
        # TODO DOC
        result = self.execute_command('banlist account ' + username + ' \n')
        return result  # TODO

    def ban_list_search_character(self, character: str):
        # TODO DOC
        result = self.execute_command('banlist character ' + character + ' \n')
        return result  # TODO

    def ban_list_search_ip(self, ip_addr: str):
        # TODO DOC
        result = self.execute_command('banlist ip ' + ip_addr + ' \n')
        return result  # TODO

    def unban_account(self, username: str):
        # TODO DOC
        result = self.execute_command('unban account ' + username + ' \n')
        return result  # TODO

    def unban_character(self, character: str):
        # TODO DOC
        result = self.execute_command('unban character ' + character + ' \n')
        return result  # TODO

    def unban_ip(self, ip_addr: str):
        # TODO DOC
        result = self.execute_command('unban ip ' + ip_addr + ' \n')
        return result  # TODO

# Character commands ---------------------------------------------------------------------------------------------------

    def character_get_infos(self, character: str):
        result = self.execute_command('pinfo ' + character + ' \n')
        return result  # TODO

    def character_achievements(self, character: str):
        # TODO DOC
        result = self.execute_command('character achievements ' + character + ' \n')
        return result  # TODO

    def character_customize_at_next_login(self, character: str):
        # TODO DOC
        result = self.execute_command('character customize ' + character + ' \n')
        return result  # TODO

    def character_rename_at_next_login(self, character: str):
        # TODO DOC
        result = self.execute_command('character rename ' + character + ' \n')
        return result  # TODO

    def character_delete(self, character: str):
        # TODO DOC
        result = self.execute_command('character erase ' + character + ' \n')
        return ') deleted' in result

    def character_get_reputation(self, character: str):
        # TODO DOC
        result = self.execute_command('character reputation ' + character + ' \n')
        return result  # TODO

    def character_get_titles(self, character: str):
        # TODO DOC
        result = self.execute_command('character titles ' + character + ' \n')
        return result  # TODO

    def character_stop_combat(self, character: str):
        # TODO DOC
        result = self.execute_command('combatstop ' + character + ' \n')
        return result  # TODO

    def character_set_level(self, character: str, level: int = 0):
        # TODO DOC
        result = self.execute_command('character level ' + character + ' ' + str(level) + ' \n')
        return result  # TODO

    def character_levelup(self, character: str, level: int = 1):
        # TODO DOC
        result = self.execute_command('levelup ' + character + ' ' + str(level) + ' \n')
        return result  # TODO

    def character_mute(self, character: str, duration: int = 1):
        # TODO DOC
        result = self.execute_command('mute ' + character + ' ' + str(duration) + ' \n')
        return result  # TODO

    def character_unmute(self, character: str):
        # TODO DOC
        result = self.execute_command('unmute ' + character + ' \n')
        return result  # TODO

    def character_recall(self, character: str):
        # TODO DOC
        result = self.execute_command('recall ' + character + ' \n')
        return result  # TODO

    def character_restore_deleted(self, character: str, new_name: str = '', account: str = ''):
        # TODO DOC
        result = self.execute_command('character deleted restore ' + character +
                                      ' ' + new_name + ' ' + account + ' \n')
        return result  # TODO

    def character_delete_deleted(self, character: str):
        # TODO DOC
        result = self.execute_command('character deleted delete ' + character + ' \n')
        return result  # TODO

    def character_delete_deleted_old(self):
        # TODO DOC
        result = self.execute_command('character deleted old \n')
        return result  # TODO

    def character_delete_deleted_older_than(self, days: int):
        # TODO DOC
        result = self.execute_command('character deleted old ' + str(days) + ' \n')
        return result  # TODO

    def character_deleted_list(self):
        # TODO DOC
        result = self.execute_command('character deleted list \n')
        return result  # TODO

    def character_search_deleted_list(self, character: str):
        # TODO DOC
        result = self.execute_command('character deleted list ' + character + ' \n')
        return result  # TODO

    def character_search_from_name(self, character: str, limit: int = 100):
        # TODO DOC
        result = self.execute_command('lookup player account ' + character + ' ' + str(limit) + ' \n')
        return result  # TODO

    def character_search_from_email(self, email: str, limit: int = 100):
        # TODO DOC
        result = self.execute_command('lookup player email ' + email + ' ' + str(limit) + ' \n')
        return result  # TODO

    def character_search_from_ip(self, ip_addr: str, limit: int = 100):
        # TODO DOC
        result = self.execute_command('lookup player ip ' + ip_addr + ' ' + str(limit) + ' \n')
        return result  # TODO

    def character_reset_achievements(self, character: str):
        # TODO DOC
        result = self.execute_command('reset achievements ' + character + ' \n')
        return result  # TODO

    def character_reset_honor(self, character: str):
        # TODO DOC
        result = self.execute_command('reset honor ' + character + ' \n')
        return result  # TODO

    def character_reset_level(self, character: str):
        # TODO DOC
        result = self.execute_command('reset level ' + character + ' \n')
        return result  # TODO

    def character_reset_specs(self, character: str):
        # TODO DOC
        result = self.execute_command('reset specs ' + character + ' \n')
        return result  # TODO

    def character_reset_spells(self, character: str):
        # TODO DOC
        result = self.execute_command('reset spells ' + character + ' \n')
        return result  # TODO

    def character_reset_stats(self, character: str):
        # TODO DOC
        result = self.execute_command('reset stats ' + character + ' \n')
        return result  # TODO

    def character_reset_talents(self, character: str):
        # TODO DOC
        result = self.execute_command('reset talents ' + character + ' \n')
        return result  # TODO

    def character_all_reset_spells(self):
        # TODO DOC
        result = self.execute_command('reset all spells \n')
        return result  # TODO

    def character_all_reset_talents(self):
        # TODO DOC
        result = self.execute_command('reset all talents \n')
        return result  # TODO

# Debug commands -------------------------------------------------------------------------------------------------------

    def debug_toggle_arenas(self):
        # TODO DOC
        result = self.execute_command('debug arena \n')
        return result  # TODO

    def debug_toggle_battlegrounds(self):
        # TODO DOC
        result = self.execute_command('debug bg \n')
        return result  # TODO

    def debug_show_spell_coefs(self, spell_id: int):
        # TODO DOC
        result = self.execute_command('debug spellcoefs ' + str(spell_id) + ' \n')
        return result  # TODO

    def debug_mod_spells(self, spell_mask_bit_index: int, spell_mod_op: int, value: int, pct: bool = False):
        # TODO DOC
        command = 'debug spellmods '
        if pct:
            command += 'pct '
        else:
            command += 'flat '
        command += str(spell_mask_bit_index) + ' ' + str(spell_mod_op) + ' ' + str(value) + ' \n'
        result = self.execute_command(command)
        return result  # TODO

# Ticket commands ------------------------------------------------------------------------------------------------------

    def ticket_delete_all(self):
        # TODO DOC
        result = self.execute_command('delticket all \n')
        return result  # TODO

    def ticket_delete(self, ticket_id: int):
        # TODO DOC
        result = self.execute_command('delticket ' + str(ticket_id) + ' \n')
        return result  # TODO

    def ticket_delete_from_character(self, character: str):
        # TODO DOC
        result = self.execute_command('delticket ' + character + ' \n')
        return result  # TODO

    def ticket_gm_show_new_directly(self, activated: bool = True):
        # TODO DOC
        command = 'ticket '
        if activated:
            command += 'on'
        else:
            command += 'off '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def ticket_show(self, ticket_id: int):
        # TODO DOC
        result = self.execute_command('ticket ' + str(ticket_id) + ' \n')
        return result  # TODO

    def ticket_show_from_character(self, character: str):
        # TODO DOC
        result = self.execute_command('ticket ' + character + ' \n')
        return result  # TODO

    def ticket_respond(self, ticket_id: int, response: str):
        # TODO DOC
        result = self.execute_command('ticket respond ' + str(ticket_id) + ' ' + response + ' \n')
        return result  # TODO

    def ticket_respond_from_character(self, character: str, response: str):
        # TODO DOC
        result = self.execute_command('ticket respond ' + character + ' ' + response + ' \n')
        return result  # TODO

# Event commands -------------------------------------------------------------------------------------------------------

    def event_get_details(self, event_id: int):
        # TODO DOC
        result = self.execute_command('event ' + str(event_id) + ' \n')
        return result  # TODO

    def event_list(self):
        # TODO DOC
        result = self.execute_command('event list \n')
        return result  # TODO

    def event_start(self, event_id: int):
        # TODO DOC
        result = self.execute_command('event start ' + str(event_id) + ' \n')
        return result  # TODO

    def event_stop(self, event_id: int):
        # TODO DOC
        result = self.execute_command('event stop ' + str(event_id) + ' \n')
        return result  # TODO

    def event_search(self, event_name: str):
        # TODO DOC
        result = self.execute_command('lookup event ' + str(event_name) + ' \n')
        return result  # TODO

# Guild commands -------------------------------------------------------------------------------------------------------

    def guild_create(self, guild_name: str, guild_leader: str = ''):
        # TODO DOC
        result = self.execute_command('guild create "' + guild_name + '" ' + guild_leader + ' \n')
        return result  # TODO

    def guild_delete(self, guild_name: str):
        # TODO DOC
        result = self.execute_command('guild delete "' + guild_name + '" \n')
        return result  # TODO

    def guild_invite(self, character: str, guild_name: str):
        # TODO DOC
        result = self.execute_command('guild invite ' + character + ' "' + guild_name + '" \n')
        return result  # TODO

    def guild_character_set_rank(self, character: str, rank: int):
        # TODO DOC
        result = self.execute_command('guild rank ' + character + ' ' + str(rank) + ' \n')
        return result  # TODO

    def guild_uninvite(self, character: str):
        # TODO DOC
        result = self.execute_command('guild uninvite ' + character + ' \n')
        return result  # TODO

# Honor commands -------------------------------------------------------------------------------------------------------

    def honor_reset(self, character: str):
        # TODO DOC
        result = self.execute_command('reset honor ' + character + ' \n')
        return result  # TODO

# Learn commands -------------------------------------------------------------------------------------------------------

    def learn_all_default(self, character: str):
        # TODO DOC
        result = self.execute_command('learn all_default ' + character + ' \n')
        return result  # TODO

    def learn_all_for_gm(self):
        # TODO DOC
        result = self.execute_command('learn all_gm \n')
        return result  # TODO

# Lookup commands ------------------------------------------------------------------------------------------------------

    def area_search(self, area_name: str):
        # TODO DOC
        result = self.execute_command('lookup area ' + area_name + ' \n')
        return result  # TODO

    def creature_search(self, creature_name: str):
        # TODO DOC
        result = self.execute_command('lookup creature ' + creature_name + ' \n')
        return result  # TODO

    def currency_search(self, currency_name: str):
        # TODO DOC
        result = self.execute_command('lookup currency ' + currency_name + ' \n')
        return result  # TODO

    def faction_search(self, faction_name: str):
        # TODO DOC
        result = self.execute_command('lookup faction ' + faction_name + ' \n')
        return result  # TODO

    def item_search(self, item_name: str):
        # TODO DOC
        result = self.execute_command('lookup item ' + item_name + ' \n')
        return result  # TODO

    def itemset_search(self, item_name: str):
        # TODO DOC
        result = self.execute_command('lookup itemset ' + item_name + ' \n')
        return result  # TODO

    def object_search(self, object_name: str):
        # TODO DOC
        result = self.execute_command('lookup object ' + object_name + ' \n')
        return result  # TODO

    def pool_search(self, pool_desc: str):
        # TODO DOC
        result = self.execute_command('lookup pool ' + pool_desc + ' \n')
        return result  # TODO

    def quest_search(self, quest_name: str):
        # TODO DOC
        result = self.execute_command('lookup quest ' + quest_name + ' \n')
        return result  # TODO

    def skill_search(self, skill_name: str):
        # TODO DOC
        result = self.execute_command('lookup skill ' + skill_name + ' \n')
        return result  # TODO

    def spell_search(self, spell_name: str):
        # TODO DOC
        result = self.execute_command('lookup spell ' + spell_name + ' \n')
        return result  # TODO

    def taxinode_search(self, taxinode_name: str):
        # TODO DOC
        result = self.execute_command('lookup taxinode ' + taxinode_name + ' \n')
        return result  # TODO

    def tele_search(self, tele_name: str):
        # TODO DOC
        result = self.execute_command('lookup tele ' + tele_name + ' \n')
        return result  # TODO

    def title_search(self, title_name: str):
        # TODO DOC
        result = self.execute_command('lookup title ' + title_name + ' \n')
        return result  # TODO

# NPC commands ---------------------------------------------------------------------------------------------------------

    def npc_show_ai_infos(self):
        # TODO DOC
        result = self.execute_command('npc aiinfo \n')
        return result  # TODO

    def npc_delete(self, npc_id: int):
        # TODO DOC
        result = self.execute_command('npc delete ' + str(npc_id) + ' \n')
        return result  # TODO

    def npc_set_move_type(self, npc_id: int, stay: bool = False, random: bool = False,  delete_waypoints: bool = False):
        # TODO DOC
        command = 'npc setmovetype ' + str(npc_id) + ' '
        if stay:
            command += 'stay '
        elif random:
            command += 'random '
        else:
            command += 'way '
        if not delete_waypoints:
            command += 'NODEL '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

# Dump commands ------------------------------------------------------------------------------------------------------

    def dump_character_import(self, dump_file: str, account_name: str, new_id: int, character_name: str):
        """
        Import a character from a dump file

        :param dump_file: file name to import from
        :param account_name: account to import into
        :param new_id: new id for the imported character
        :param character_name: name for the imported character<commit_msg>wip doc<commit_after># -*- coding: utf-8 -*-

import logging
import telnetlib


class TelnetWrapper:
    """
    Telnet based command wrapper for CMaNGOS

    This class interact with a CMaNGOS server by Telnet connection.
    Functions return a boolean statement or formatted data.
    """
    def __init__(self, host: str, port: str, user: str, pwd: str, log_level=logging.INFO):
        # TODO DOC
        logging.basicConfig(filename='../../wrapper.log', level=log_level)
        self.host = host
        self.port = port
        self.user = user
        self.pwd = <PASSWORD>
        self.tn_client = None
        self.open_session()
        self.connect()

    def is_session_open(self):
        """
        Return Telnet session state

        True if session established, False otherwise
        :return: True if the session is opened with the CMaNGOS server
        """
        return self.tn_client is not None and self.tn_client.get_socket()

    def open_session(self):
        """
        Try to open a Telnet session with the CMaNGOS server

        Do nothing if already in a connected state
        """
        logging.info('Try to open a Telnet session on ' + self.host + ':' + self.port)
        if not self.is_session_open():
            self.tn_client = telnetlib.Telnet(host=self.host, port=self.port)
            logging.info('Telnet client connected to ' + self.tn_client.host + ':' + self.tn_client.port)
        else:
            logging.info('Already connected to a Telnet session')

    def connect(self):
        """
        Try to login into CMaNGOS server cli prompt

        Wait for credential questions and answer them with given ones.
        """
        logging.debug('Waiting for username prompt')
        self.tn_client.read_until(b"Username:")
        logging.debug('Sending username : ' + self.user)
        self.tn_client.write(self.user.encode('ascii') + b" \n")
        logging.debug('Waiting for password prompt')
        self.tn_client.read_until(b"Password:")
        logging.debug('Sending password : ' + self.pwd)
        self.tn_client.write(self.pwd.encode('ascii') + b" \n")
        self.wait_cli_prompt()
        logging.info('Successfully connected as ' + self.user)

    def wait_cli_prompt(self):
        """
        Flush data stream before doing a command

        Make sure there is no more data available to read
        """
        logging.debug('Waiting for a ready cli prompt')
        self.tn_client.read_until(b"mangos>", timeout=0.2)
        logging.debug('Sending a newline character')
        self.tn_client.write(b"\n")
        logging.debug('Waiting for a ready cli prompt')
        self.tn_client.read_until(b"mangos>")
        logging.debug('Cli prompt ready')

    def disconnect(self):
        """
        Disconnect from CMaNGOS cli prompt

        Send 'quit' command to disconnect from CMaNGOS cli prompt
        """
        logging.debug('Disconnecting ' + self.user + '; exiting cli prompt')
        self.tn_client.write(b"quit \n")

    def close_session(self):
        """
        Close the Telnet session
        """
        logging.info('Closing Telnet connection to ' + self.host + ':' + self.port)
        self.tn_client.close()

    def close(self):
        """
        Disconnect from CMaNGOS cli prompt and close Telnet session
        """
        self.disconnect()
        self.close_session()

    def execute_command(self, command: str):
        """
        Execute a command into CMaNGOS cli prompt and return the result

        Send command into CMaNGOS cli prompt and read answered data
        :arg command 'str' to execute
        :return: True on success, False otherwise
        """
        self.wait_cli_prompt()
        logging.info('Execute command : ' + command)
        self.tn_client.write(bytes(command, 'UTF-8'))
        result = str(self.tn_client.read_until(b"mangos>")).replace('\\r', '')  # can remove '\r' char here
        logging.debug('Response ' + result)
        return result

# Account commands -----------------------------------------------------------------------------------------------------

    def get_online_accounts(self):
        """
        Get currently online accounts

        :return: currently connected account as a dict
        """
        accounts = {}
        result = self.execute_command('account onlinelist \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

    def account_get_characters(self, username: str):
        """
        Get account characters as a list

        :param username: account name
        :return: account characters as a dict
        """
        characters = {}
        result = self.execute_command('account characters ' + username + ' \n')
        result = result.split('\\n')[3:-2]
        for character in result:
            (guid, char_name, char_race, char_class, char_level) = character[1:-1].split("|")
            characters[guid.strip()] = {
                'guid': guid.strip(),
                'name': char_name.strip(),
                'race': char_race.strip(),
                'class': char_class.strip(),
                'level': char_level.strip()
            }
        return characters

    def account_create(self, username: str, password: str):
        """
        Create a new account with a login and a password

        :param username: new account login
        :param password: new account password
        :return: True on success, False otherwise
        """
        result = self.execute_command('account create ' + username + ' ' + password + ' \n')
        return 'Account with this name already exist' not in result

    def account_set_password(self, username: str, password: str):
        """
        Replace an account password with a new one

        :param username: account login
        :param password: new account password
        :return: True on success, False otherwise
        """
        result = self.execute_command('account set password ' + username + ' ' + password + ' ' + password + ' \n')
        return 'The password was changed' in result

    def account_set_addon(self, username: str, addon: int):
        """
        Set expansion access to an account

        :param username: account login
        :param addon: expansion id (0, 1, 2 ...)
        :return: True on success, False otherwise
        """
        if addon < 0:
            return False  # wrong value
        result = self.execute_command('account set addon ' + username + ' ' + str(addon) + ' \n')
        return 'has been granted ' + str(addon) + ' expansion rights.' in result

    def account_set_gm_level(self, username: str, gm_level: int):
        """
        Set account permission level

        :param username: account login
        :param gm_level: gm level (0: player, 1: modo, 2: gm, 3: admin)
        :return: True on success, False otherwise
        """
        if gm_level < 0 or gm_level > 3:
            return False  # wrong value
        result = self.execute_command('account set gmlevel ' + username + ' ' + str(gm_level) + ' \n')
        return 'You change security level of account ' in result

    def account_delete(self, username: str):
        """
        Delete an account

        :param username: account login
        :return: True on success, False otherwise
        """
        result = self.execute_command('account delete ' + username + ' \n')
        return 'Account deleted:' in result

    def account_search_from_email(self, user_email: str, limit: int = 100):
        """
        Search in accounts corresponding email (or fragment)

        :param user_email: account email (or a fragment) to search from
        :param limit: result number limit
        :return: found accounts as a map
        """
        accounts = {}
        result = self.execute_command('lookup account email ' + user_email + ' ' + str(limit) + ' \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

    def account_search_from_name(self, username: str, limit: int = 100):
        """
        Search in accounts corresponding login (or fragment)

        :param username: account login (or a fragment) to search from
        :param limit: result number limit
        :return: found accounts as a map
        """
        accounts = {}
        result = self.execute_command('lookup account name ' + username + ' ' + str(limit) + ' \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

    def account_search_from_ip(self, ip_addr: str, limit: int = 100):
        """
        Search in accounts corresponding last used ip address (or fragment)

        :param ip_addr: account last used ip address (or a fragment) to search from
        :param limit: result number limit
        :return: found accounts as a map
        """
        accounts = {}
        result = self.execute_command('lookup account ip ' + ip_addr + ' ' + str(limit) + ' \n')
        result = result.split('\\n')[3:-2]
        for account in result:
            (account_id, username, character, ip, gm, expansion) = account[1:-1].split("|")
            accounts[account_id.strip()] = {
                'id': account_id.strip(),
                'username': username.strip(),
                'character': character.strip(),
                'ip': ip.strip(),
                'gm': gm.strip(),
                'expansion': expansion.strip()
            }
        return accounts

# Achievement commands -------------------------------------------------------------------------------------------------

    def achievement_details(self, achievement_id: int):
        """
        Get details about an achievement

        :param achievement_id: the achievement id
        :return: details about the acvhievement
        """
        result = self.execute_command('achievement ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_search(self, achievement_name: str):
        """
        Search in achievements with a name (or a fragment)

        :param achievement_name: name to lookup (or a fragment)
        :return: list of achievement results
        """
        result = self.execute_command('lookup achievement ' + achievement_name + ' \n')
        return result  # TODO

    def achievement_state(self, character: str, achievement_id: int):
        # TODO DOC
        result = self.execute_command('achievement ' + character + ' ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_set_complete(self, character: str, achievement_id: int):
        # TODO DOC
        result = self.execute_command('achievement add ' + character + ' ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_remove(self, character: str, achievement_id: int):
        # TODO DOC
        result = self.execute_command('achievement remove ' + character + ' ' + str(achievement_id) + ' \n')
        return result  # TODO

    def achievement_criteria_set_complete_progress(self, character: str, criteria_id: int):
        # TODO DOC
        result = self.execute_command('achievement criteria add ' + character + ' ' + str(criteria_id) + ' \n')
        return result  # TODO

    def achievement_criteria_add_progress(self, character: str, criteria_id: int, change: int):
        # TODO DOC
        result = self.execute_command('achievement criteria add ' + character +
                                      ' ' + str(criteria_id) + ' ' + str(change) + ' \n')
        return result  # TODO

    def achievement_criteria_reset_progress(self, character: str, criteria_id: int):
        # TODO DOC
        result = self.execute_command('achievement criteria remove ' + character + ' ' + str(criteria_id) + ' \n')
        return result  # TODO

    def achievement_criteria_reduce_progress(self, character: str, criteria_id: int, change: int):
        # TODO DOC
        result = self.execute_command('achievement criteria remove ' + character +
                                      ' ' + str(criteria_id) + ' ' + str(change) + ' \n')
        return result  # TODO

# AHBot commands -------------------------------------------------------------------------------------------------------

    def ahbot_reload_conf(self):
        """
        Reload AHBot configuration

        :return: True if success, False otherwise
        """
        result = self.execute_command('ahbot reload \n')
        return 'All config are reloaded from ahbot configuration file.' in result

    def ahbot_status(self, detailled: bool = False):
        # TODO DOC
        command = 'ahbot status '
        if detailled:
            command += 'all '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def ahbot_reset_auction(self, force_all_rebuild: bool = False):
        # TODO DOC
        command = 'ahbot rebuild '
        if force_all_rebuild:
            command += 'all '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def ahbot_set_all_quota(self, grey_items: int, white_items: int, green_items: int,
                            blue_items: int, purple_items: int, orange_items: int, yellow_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount ' + str(grey_items) + ' ' + str(white_items) +
                                      ' ' + str(green_items) + ' ' + str(blue_items) + ' ' + str(purple_items) +
                                      ' ' + str(orange_items) + ' ' + str(yellow_items) + ' \n')
        return result  # TODO

    def ahbot_set_grey_quota(self, grey_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount grey ' + str(grey_items) + ' \n')
        return result  # TODO

    def ahbot_set_white_quota(self, white_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount white ' + str(white_items) + ' \n')
        return result  # TODO

    def ahbot_set_green_quota(self, green_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount green ' + str(green_items) + ' \n')
        return result  # TODO

    def ahbot_set_blue_quota(self, blue_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount blue ' + str(blue_items) + ' \n')
        return result  # TODO

    def ahbot_set_purple_quota(self, purple_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount purple ' + str(purple_items) + ' \n')
        return result  # TODO

    def ahbot_set_orange_quota(self, orange_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount orange ' + str(orange_items) + ' \n')
        return result  # TODO

    def ahbot_set_yellow_quota(self, yellow_items: int):
        # TODO DOC
        result = self.execute_command('ahbot items amount yellow ' + str(yellow_items) + ' \n')
        return result  # TODO

    def ahbot_set_ratios(self, alliance_ratio: int, horde_ratio: int, neutral_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio ' + str(alliance_ratio) +
                                      ' ' + str(horde_ratio) + ' ' + str(neutral_ratio) + ' \n')
        return result  # TODO

    def ahbot_set_alliance_ratio(self, alliance_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio alliance ' + str(alliance_ratio) + ' \n')
        return result  # TODO

    def ahbot_set_horde_ratio(self, horde_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio horde ' + str(horde_ratio) + ' \n')
        return result  # TODO

    def ahbot_set_neutral_ratio(self, neutral_ratio: int):
        # TODO DOC
        result = self.execute_command('ahbot items ratio neutral ' + str(neutral_ratio) + ' \n')
        return result  # TODO

# Auction commands -----------------------------------------------------------------------------------------------------

    def auction_show_alliance(self):
        # TODO DOC
        result = self.execute_command('auction alliance \n')
        return result  # TODO

    def auction_show_horde(self):
        # TODO DOC
        result = self.execute_command('auction horde \n')
        return result  # TODO

    def auction_show_goblin(self):
        # TODO DOC
        result = self.execute_command('auction goblin \n')
        return result  # TODO

    def auction_add_item_alliance(self, item_id: int, item_count: int = 1, min_bid: int = 1, buy_out: int = None,
                                  long_duration: bool = False, very_long_duration: bool = False):
        # TODO DOC
        command = 'auction item alliance ' + str(item_id) + ':' + str(item_count) + ' '
        if buy_out:
            command += str(min_bid) + ' ' + str(buy_out) + ' '
        if long_duration:
            if very_long_duration:
                command += 'very'
            command += 'long'
        else:
            command += 'short'
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def auction_add_item_horde(self, item_id: int, item_count: int = 1, min_bid: int = 1, buy_out: int = None,
                               long_duration: bool = False, very_long_duration: bool = False):
        # TODO DOC
        command = 'auction item horde ' + str(item_id) + ':' + str(item_count) + ' '
        if buy_out:
            command += str(min_bid) + ' ' + str(buy_out) + ' '
        if long_duration:
            if very_long_duration:
                command += 'very'
            command += 'long'
        else:
            command += 'short'
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def auction_add_item_goblin(self, item_id: int, item_count: int = 1, min_bid: int = 1, buy_out: int = None,
                                long_duration: bool = False, very_long_duration: bool = False):
        # TODO DOC
        command = 'auction item goblin ' + str(item_id) + ':' + str(item_count) + ' '
        if buy_out:
            command += str(min_bid) + ' ' + str(buy_out) + ' '
        if long_duration:
            if very_long_duration:
                command += 'very'
            command += 'long'
        else:
            command += 'short'
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

# Ban commands ---------------------------------------------------------------------------------------------------------

    def ban_account(self, username: str, reason: str, bantime: str = '-1'):
        # TODO DOC
        result = self.execute_command('ban account ' + username + ' ' + bantime + ' ' + reason + ' \n')
        return result  # TODO

    def ban_character(self, character: str, reason: str, bantime: str = '-1'):
        # TODO DOC
        result = self.execute_command('ban character ' + character + ' ' + bantime + ' ' + reason + ' \n')
        return result  # TODO

    def ban_ip(self, ip_addr: str, reason: str, bantime: str = '-1'):
        # TODO DOC
        result = self.execute_command('ban ip ' + ip_addr + ' ' + bantime + ' ' + reason + ' \n')
        return result  # TODO

    def ban_info_account(self, username: str):
        # TODO DOC
        result = self.execute_command('baninfo account ' + username + ' \n')
        return result  # TODO

    def ban_info_character(self, character: str):
        # TODO DOC
        result = self.execute_command('baninfo character ' + character + ' \n')
        return result  # TODO

    def ban_info_ip(self, ip_addr: str):
        # TODO DOC
        result = self.execute_command('baninfo ip ' + ip_addr + ' \n')
        return result  # TODO

    def ban_list_account(self):
        # TODO DOC
        result = self.execute_command('banlist account \n')
        return result  # TODO

    def ban_list_character(self):
        # TODO DOC
        result = self.execute_command('banlist character \n')
        return result  # TODO

    def ban_list_ip(self):
        # TODO DOC
        result = self.execute_command('banlist ip \n')
        return result  # TODO

    def ban_list_search_account(self, username: str):
        # TODO DOC
        result = self.execute_command('banlist account ' + username + ' \n')
        return result  # TODO

    def ban_list_search_character(self, character: str):
        # TODO DOC
        result = self.execute_command('banlist character ' + character + ' \n')
        return result  # TODO

    def ban_list_search_ip(self, ip_addr: str):
        # TODO DOC
        result = self.execute_command('banlist ip ' + ip_addr + ' \n')
        return result  # TODO

    def unban_account(self, username: str):
        # TODO DOC
        result = self.execute_command('unban account ' + username + ' \n')
        return result  # TODO

    def unban_character(self, character: str):
        # TODO DOC
        result = self.execute_command('unban character ' + character + ' \n')
        return result  # TODO

    def unban_ip(self, ip_addr: str):
        # TODO DOC
        result = self.execute_command('unban ip ' + ip_addr + ' \n')
        return result  # TODO

# Character commands ---------------------------------------------------------------------------------------------------

    def character_get_infos(self, character: str):
        result = self.execute_command('pinfo ' + character + ' \n')
        return result  # TODO

    def character_achievements(self, character: str):
        # TODO DOC
        result = self.execute_command('character achievements ' + character + ' \n')
        return result  # TODO

    def character_customize_at_next_login(self, character: str):
        # TODO DOC
        result = self.execute_command('character customize ' + character + ' \n')
        return result  # TODO

    def character_rename_at_next_login(self, character: str):
        # TODO DOC
        result = self.execute_command('character rename ' + character + ' \n')
        return result  # TODO

    def character_delete(self, character: str):
        # TODO DOC
        result = self.execute_command('character erase ' + character + ' \n')
        return ') deleted' in result

    def character_get_reputation(self, character: str):
        # TODO DOC
        result = self.execute_command('character reputation ' + character + ' \n')
        return result  # TODO

    def character_get_titles(self, character: str):
        # TODO DOC
        result = self.execute_command('character titles ' + character + ' \n')
        return result  # TODO

    def character_stop_combat(self, character: str):
        # TODO DOC
        result = self.execute_command('combatstop ' + character + ' \n')
        return result  # TODO

    def character_set_level(self, character: str, level: int = 0):
        # TODO DOC
        result = self.execute_command('character level ' + character + ' ' + str(level) + ' \n')
        return result  # TODO

    def character_levelup(self, character: str, level: int = 1):
        # TODO DOC
        result = self.execute_command('levelup ' + character + ' ' + str(level) + ' \n')
        return result  # TODO

    def character_mute(self, character: str, duration: int = 1):
        # TODO DOC
        result = self.execute_command('mute ' + character + ' ' + str(duration) + ' \n')
        return result  # TODO

    def character_unmute(self, character: str):
        # TODO DOC
        result = self.execute_command('unmute ' + character + ' \n')
        return result  # TODO

    def character_recall(self, character: str):
        # TODO DOC
        result = self.execute_command('recall ' + character + ' \n')
        return result  # TODO

    def character_restore_deleted(self, character: str, new_name: str = '', account: str = ''):
        # TODO DOC
        result = self.execute_command('character deleted restore ' + character +
                                      ' ' + new_name + ' ' + account + ' \n')
        return result  # TODO

    def character_delete_deleted(self, character: str):
        # TODO DOC
        result = self.execute_command('character deleted delete ' + character + ' \n')
        return result  # TODO

    def character_delete_deleted_old(self):
        # TODO DOC
        result = self.execute_command('character deleted old \n')
        return result  # TODO

    def character_delete_deleted_older_than(self, days: int):
        # TODO DOC
        result = self.execute_command('character deleted old ' + str(days) + ' \n')
        return result  # TODO

    def character_deleted_list(self):
        # TODO DOC
        result = self.execute_command('character deleted list \n')
        return result  # TODO

    def character_search_deleted_list(self, character: str):
        # TODO DOC
        result = self.execute_command('character deleted list ' + character + ' \n')
        return result  # TODO

    def character_search_from_name(self, character: str, limit: int = 100):
        # TODO DOC
        result = self.execute_command('lookup player account ' + character + ' ' + str(limit) + ' \n')
        return result  # TODO

    def character_search_from_email(self, email: str, limit: int = 100):
        # TODO DOC
        result = self.execute_command('lookup player email ' + email + ' ' + str(limit) + ' \n')
        return result  # TODO

    def character_search_from_ip(self, ip_addr: str, limit: int = 100):
        # TODO DOC
        result = self.execute_command('lookup player ip ' + ip_addr + ' ' + str(limit) + ' \n')
        return result  # TODO

    def character_reset_achievements(self, character: str):
        # TODO DOC
        result = self.execute_command('reset achievements ' + character + ' \n')
        return result  # TODO

    def character_reset_honor(self, character: str):
        # TODO DOC
        result = self.execute_command('reset honor ' + character + ' \n')
        return result  # TODO

    def character_reset_level(self, character: str):
        # TODO DOC
        result = self.execute_command('reset level ' + character + ' \n')
        return result  # TODO

    def character_reset_specs(self, character: str):
        # TODO DOC
        result = self.execute_command('reset specs ' + character + ' \n')
        return result  # TODO

    def character_reset_spells(self, character: str):
        # TODO DOC
        result = self.execute_command('reset spells ' + character + ' \n')
        return result  # TODO

    def character_reset_stats(self, character: str):
        # TODO DOC
        result = self.execute_command('reset stats ' + character + ' \n')
        return result  # TODO

    def character_reset_talents(self, character: str):
        # TODO DOC
        result = self.execute_command('reset talents ' + character + ' \n')
        return result  # TODO

    def character_all_reset_spells(self):
        # TODO DOC
        result = self.execute_command('reset all spells \n')
        return result  # TODO

    def character_all_reset_talents(self):
        # TODO DOC
        result = self.execute_command('reset all talents \n')
        return result  # TODO

# Debug commands -------------------------------------------------------------------------------------------------------

    def debug_toggle_arenas(self):
        # TODO DOC
        result = self.execute_command('debug arena \n')
        return result  # TODO

    def debug_toggle_battlegrounds(self):
        # TODO DOC
        result = self.execute_command('debug bg \n')
        return result  # TODO

    def debug_show_spell_coefs(self, spell_id: int):
        # TODO DOC
        result = self.execute_command('debug spellcoefs ' + str(spell_id) + ' \n')
        return result  # TODO

    def debug_mod_spells(self, spell_mask_bit_index: int, spell_mod_op: int, value: int, pct: bool = False):
        # TODO DOC
        command = 'debug spellmods '
        if pct:
            command += 'pct '
        else:
            command += 'flat '
        command += str(spell_mask_bit_index) + ' ' + str(spell_mod_op) + ' ' + str(value) + ' \n'
        result = self.execute_command(command)
        return result  # TODO

# Ticket commands ------------------------------------------------------------------------------------------------------

    def ticket_delete_all(self):
        # TODO DOC
        result = self.execute_command('delticket all \n')
        return result  # TODO

    def ticket_delete(self, ticket_id: int):
        # TODO DOC
        result = self.execute_command('delticket ' + str(ticket_id) + ' \n')
        return result  # TODO

    def ticket_delete_from_character(self, character: str):
        # TODO DOC
        result = self.execute_command('delticket ' + character + ' \n')
        return result  # TODO

    def ticket_gm_show_new_directly(self, activated: bool = True):
        # TODO DOC
        command = 'ticket '
        if activated:
            command += 'on'
        else:
            command += 'off '
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

    def ticket_show(self, ticket_id: int):
        # TODO DOC
        result = self.execute_command('ticket ' + str(ticket_id) + ' \n')
        return result  # TODO

    def ticket_show_from_character(self, character: str):
        # TODO DOC
        result = self.execute_command('ticket ' + character + ' \n')
        return result  # TODO

    def ticket_respond(self, ticket_id: int, response: str):
        # TODO DOC
        result = self.execute_command('ticket respond ' + str(ticket_id) + ' ' + response + ' \n')
        return result  # TODO

    def ticket_respond_from_character(self, character: str, response: str):
        # TODO DOC
        result = self.execute_command('ticket respond ' + character + ' ' + response + ' \n')
        return result  # TODO

# Event commands -------------------------------------------------------------------------------------------------------

    def event_get_details(self, event_id: int):
        # TODO DOC
        result = self.execute_command('event ' + str(event_id) + ' \n')
        return result  # TODO

    def event_list(self):
        # TODO DOC
        result = self.execute_command('event list \n')
        return result  # TODO

    def event_start(self, event_id: int):
        # TODO DOC
        result = self.execute_command('event start ' + str(event_id) + ' \n')
        return result  # TODO

    def event_stop(self, event_id: int):
        # TODO DOC
        result = self.execute_command('event stop ' + str(event_id) + ' \n')
        return result  # TODO

    def event_search(self, event_name: str):
        # TODO DOC
        result = self.execute_command('lookup event ' + str(event_name) + ' \n')
        return result  # TODO

# Guild commands -------------------------------------------------------------------------------------------------------

    def guild_create(self, guild_name: str, guild_leader: str = ''):
        # TODO DOC
        result = self.execute_command('guild create "' + guild_name + '" ' + guild_leader + ' \n')
        return result  # TODO

    def guild_delete(self, guild_name: str):
        # TODO DOC
        result = self.execute_command('guild delete "' + guild_name + '" \n')
        return result  # TODO

    def guild_invite(self, character: str, guild_name: str):
        # TODO DOC
        result = self.execute_command('guild invite ' + character + ' "' + guild_name + '" \n')
        return result  # TODO

    def guild_character_set_rank(self, character: str, rank: int):
        # TODO DOC
        result = self.execute_command('guild rank ' + character + ' ' + str(rank) + ' \n')
        return result  # TODO

    def guild_uninvite(self, character: str):
        # TODO DOC
        result = self.execute_command('guild uninvite ' + character + ' \n')
        return result  # TODO

# Honor commands -------------------------------------------------------------------------------------------------------

    def honor_reset(self, character: str):
        # TODO DOC
        result = self.execute_command('reset honor ' + character + ' \n')
        return result  # TODO

# Learn commands -------------------------------------------------------------------------------------------------------

    def learn_all_default(self, character: str):
        """
        Make a character all its spells learned (race, class and rewards).

        :param character: target character
        :return: True on success, False otherwise
        """
        result = self.execute_command('learn all_default ' + character + ' \n')
        return result  # TODO

    def learn_all_for_gm(self):
        """
        Make all Game Masters all their spells learned (race, class and rewards).

        :return: True on success, False otherwise
        """
        result = self.execute_command('learn all_gm \n')
        return result  # TODO

# Lookup commands ------------------------------------------------------------------------------------------------------

    def area_search(self, area_name: str):
        # TODO DOC
        result = self.execute_command('lookup area ' + area_name + ' \n')
        return result  # TODO

    def creature_search(self, creature_name: str):
        # TODO DOC
        result = self.execute_command('lookup creature ' + creature_name + ' \n')
        return result  # TODO

    def currency_search(self, currency_name: str):
        # TODO DOC
        result = self.execute_command('lookup currency ' + currency_name + ' \n')
        return result  # TODO

    def faction_search(self, faction_name: str):
        # TODO DOC
        result = self.execute_command('lookup faction ' + faction_name + ' \n')
        return result  # TODO

    def item_search(self, item_name: str):
        # TODO DOC
        result = self.execute_command('lookup item ' + item_name + ' \n')
        return result  # TODO

    def itemset_search(self, item_name: str):
        # TODO DOC
        result = self.execute_command('lookup itemset ' + item_name + ' \n')
        return result  # TODO

    def object_search(self, object_name: str):
        # TODO DOC
        result = self.execute_command('lookup object ' + object_name + ' \n')
        return result  # TODO

    def pool_search(self, pool_desc: str):
        # TODO DOC
        result = self.execute_command('lookup pool ' + pool_desc + ' \n')
        return result  # TODO

    def quest_search(self, quest_name: str):
        # TODO DOC
        result = self.execute_command('lookup quest ' + quest_name + ' \n')
        return result  # TODO

    def skill_search(self, skill_name: str):
        # TODO DOC
        result = self.execute_command('lookup skill ' + skill_name + ' \n')
        return result  # TODO

    def spell_search(self, spell_name: str):
        # TODO DOC
        result = self.execute_command('lookup spell ' + spell_name + ' \n')
        return result  # TODO

    def taxinode_search(self, taxinode_name: str):
        # TODO DOC
        result = self.execute_command('lookup taxinode ' + taxinode_name + ' \n')
        return result  # TODO

    def tele_search(self, tele_name: str):
        # TODO DOC
        result = self.execute_command('lookup tele ' + tele_name + ' \n')
        return result  # TODO

    def title_search(self, title_name: str):
        # TODO DOC
        result = self.execute_command('lookup title ' + title_name + ' \n')
        return result  # TODO

# NPC commands ---------------------------------------------------------------------------------------------------------

    def npc_show_ai_infos(self):
        """
        Get NPC AI and scripts informations.

        :return: NPC AI and scripts informations
        """
        result = self.execute_command('npc aiinfo \n')
        return result  # TODO

    def npc_delete(self, npc_id: int):
        """
        Delete a NPC.

        :param npc_id: NPC id to delete
        :return: True on success, False otherwise
        """
        result = self.execute_command('npc delete ' + str(npc_id) + ' \n')
        return result  # TODO

    def npc_set_move_type(self, npc_id: int, stay: bool = False, random: bool = False,  delete_waypoints: bool = False):
        """
        Modify movements from a NPC.

        :param npc_id: target NPC id
        :param stay: make NPC static
        :param random: make NPC movements random
        :param delete_waypoints: want to delete NPC waypoints ?
        :return: True on success, False otherwise
        """
        command = 'npc setmovetype ' + str(npc_id) + ' '
        if stay:
            command += 'stay '  # static
        elif random:
            command += 'random '  # random movement
        else:
            command += 'way '  # follow its waypoints
        if not delete_waypoints:  # don't delete waypoint
            command += 'NODEL '  # keep waypoint
        command += ' \n'
        result = self.execute_command(command)
        return result  # TODO

# Dump commands ------------------------------------------------------------------------------------------------------

    def dump_character_import(self, dump_file: str, account_name: str, new_id: int, character_name: str):
        """
        Import a character from a dump file

        :param dump_file: file name to import from
        :param account_name: account to import into
        :param new_id: new id for the imported character
        :param character_name: name for the imported character
{'fraction_non_alphanumeric': 0.14254508575069239, 'fraction_numerical': 0.0016643045677358958, 'mean_word_length': 1.932697807435653, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3840483', 'n_tokens_mistral': 21532, 'n_tokens_neox': 20685, 'n_words': 5933}