import os
import json
from pokemongo_bot.base_task import BaseTask
from pokemongo_bot.human_behaviour import sleep
from pokemongo_bot.inventory import pokemons, Pokemon, Attack

import re


DEFAULT_IGNORE_FAVORITES = False
DEFAULT_GOOD_ATTACK_THRESHOLD = 0.7
DEFAULT_TEMPLATE = '{name}'

MAXIMUM_NICKNAME_LENGTH = 12


class NicknamePokemon(BaseTask):
    SUPPORTED_TASK_API_VERSION = 1

    """
    Nickname user pokemons according to the specified template


    PARAMETERS:

    dont_nickname_favorite (default: False)
        Prevents renaming of favorited pokemons

    good_attack_threshold (default: 0.7)
        Threshold for perfection of the attack in it's type (0.0-1.0)
         after which attack will be treated as good.
        Used for {fast_attack_char}, {charged_attack_char}, {attack_code}
         templates

    nickname_template (default: '{name}')
        Template for nickname generation.
        Empty template or any resulting in the simple pokemon name
         (e.g. '', '{name}', ...) will revert all pokemon to their original
         names (as if they had no nickname).

        Niantic imposes a 12-character limit on all pokemon nicknames, so
         any new nickname will be truncated to 12 characters if over that limit.
        Thus, it is up to the user to exercise judgment on what template will
         best suit their need with this constraint in mind.

        You can use full force of the Python [Format String syntax](https://docs.python.org/2.7/library/string.html#formatstrings)
        For example, using `{name:.8s}` causes the Pokemon name to never take up
         more than 8 characters in the nickname. This would help guarantee that
         a template like `{name:.8s}_{iv_pct}` never goes over the 12-character
         limit.


    **NOTE:** If you experience frequent `Pokemon not found` error messages,
     this is because the inventory cache has not been updated after a pokemon
     was released. This can be remedied by placing the `NicknamePokemon` task
     above the `TransferPokemon` task in your `config.json` file.


    EXAMPLE CONFIG:
    {
      "type": "NicknamePokemon",
      "config": {
        "enabled": true,
        "dont_nickname_favorite": false,
        "good_attack_threshold": 0.7,
        "nickname_template": "{iv_pct}_{iv_ads}"
      }
    }


    SUPPORTED PATTERN KEYS:

    {name}  Pokemon name      (e.g. Articuno)
    {id}    Pokemon ID/Number (1-151)
    {cp}    Combat Points     (10-4145)

    # Individial Values
    {iv_attack}  Individial Attack (0-15) of the current specific pokemon
    {iv_defense} Individial Defense (0-15) of the current specific pokemon
    {iv_stamina} Individial Stamina (0-15) of the current specific pokemon
    {iv_ads}     Joined IV values (e.g. 4/12/9)
    {iv_sum}     Sum of the Individial Values (0-45)
    {iv_pct}     IV perfection (in 000-100 format - 3 chars)
    {iv_pct2}    IV perfection (in 00-99 format - 2 chars)
                    So 99 is best (it's a 100% perfection)
    {iv_pct1}    IV perfection (in 0-9 format - 1 char)
    {iv_ads_hex} Joined IV values in HEX (e.g. 4C9)

    # Basic Values of the pokemon (identical for all of one kind)
    {base_attack}   Basic Attack (40-284) of the current pokemon kind
    {base_defense}  Basic Defense (54-242) of the current pokemon kind
    {base_stamina}  Basic Stamina (20-500) of the current pokemon kind
    {base_ads}      Joined Basic Values (e.g. 125/93/314)

    # Final Values of the pokemon (Base Values + Individial Values)
    {attack}        Basic Attack + Individial Attack
    {defense}       Basic Defense + Individial Defense
    {stamina}       Basic Stamina + Individial Stamina
    {sum_ads}       Joined Final Values (e.g. 129/97/321)

    # IV CP perfection - it's a kind of IV perfection percent
    #  but calculated using weight of each IV in its contribution
    #  to CP of the best evolution of current pokemon.
    # So it tends to be more accurate than simple IV perfection.
    {ivcp_pct}      IV CP perfection (in 000-100 format - 3 chars)
    {ivcp_pct2}     IV CP perfection (in 00-99 format - 2 chars)
                        So 99 is best (it's a 100% perfection)
    {ivcp_pct1}     IV CP perfection (in 0-9 format - 1 char)

    # Character codes for fast/charged attack types.
    # If attack is good character is uppecased, otherwise lowercased.
    # Use 'good_attack_threshold' option for customization
    #
    # It's an effective way to represent type with one character.
    #   If first char of the type name is unique - use it,
    #    in other case suitable substitute used
    #
    # Type codes:
    #   Bug: 'B'
    #   Dark: 'K'
    #   Dragon: 'D'
    #   Electric: 'E'
    #   Fairy: 'Y'
    #   Fighting: 'T'
    #   Fire: 'F'
    #   Flying: 'L'
    #   Ghost: 'H'
    #   Grass: 'A'
    #   Ground: 'G'
    #   Ice: 'I'
    #   Normal: 'N'
    #   Poison: 'P'
    #   Psychic: 'C'
    #   Rock: 'R'
    #   Steel: 'S'
    #   Water: 'W'
    #
    {fast_attack_char}      One character code for fast attack type
                                (e.g. 'F' for good Fire or 's' for bad
                                Steel attack)
    {charged_attack_char}   One character code for charged attack type
                                (e.g. 'n' for bad Normal or 'I' for good
                                Ice attack)
    {attack_code}           Joined 2 character code for both attacks
                                (e.g. 'Lh' for pokemon with good Flying
                                and weak Ghost attacks)

    # Moveset perfection percents for attack and for defense
    #  Calculated for current pokemon only, not between all pokemons
    #  So perfect moveset can be weak if pokemon is weak (e.g. Caterpie)
    {attack_pct}   Moveset perfection for attack (in 000-100 format - 3 chars)
    {defense_pct}  Moveset perfection for defense (in 000-100 format - 3 chars)
    {attack_pct2}  Moveset perfection for attack (in 00-99 format - 2 chars)
    {defense_pct2} Moveset perfection for defense (in 00-99 format - 2 chars)
    {attack_pct1}  Moveset perfection for attack (in 0-9 format - 1 char)
    {defense_pct1} Moveset perfection for defense (in 0-9 format - 1 char)

    # Special case: pokemon object.
    # You can access any available pokemon info via it.
    # Examples:
    #   '{pokemon.ivcp:.2%}'             ->  '47.00%'
    #   '{pokemon.fast_attack}'          ->  'Wing Attack'
    #   '{pokemon.fast_attack.type}'     ->  'Flying'
    #   '{pokemon.fast_attack.dps:.2f}'  ->  '10.91'
    #   '{pokemon.fast_attack.dps:.0f}'  ->  '11'
    #   '{pokemon.charged_attack}'       ->  'Ominous Wind'
    {pokemon}   Pokemon instance (see inventory.py for class sources)


    EXAMPLES:

    1. "nickname_template": "{ivcp_pct}_{iv_pct}_{iv_ads}"

    Golbat with IV (attack: 9, defense: 4 and stamina: 8) will result in:
     '48_46_9/4/8'

    2. "nickname_template": "{attack_code}{attack_pct1}{defense_pct1}{ivcp_pct1}{name}"

    Same Golbat (with attacks Wing Attack & Ominous Wind) will have nickname:
     'Lh474Golbat'

    See /tests/nickname_test.py for more examples.
    """

    # noinspection PyAttributeOutsideInit
    def initialize(self):
        self.ignore_favorites = self.config.get(
            'dont_nickname_favorite', DEFAULT_IGNORE_FAVORITES)
        self.good_attack_threshold = self.config.get(
            'good_attack_threshold', DEFAULT_GOOD_ATTACK_THRESHOLD)
        self.template = self.config.get(
            'nickname_template', DEFAULT_TEMPLATE)

        self.translate = None
        locale = self.config.get('locale', 'en')
        if locale != 'en':
            fn = 'data/locales/{}.json'.format(locale)
            if os.path.isfile(fn):
                self.translate = json.load(open(fn))

    def work(self):
        """
        Iterate over all user pokemons and nickname if needed
        """
        for pokemon in pokemons().all():  # type: Pokemon
            if not pokemon.is_favorite or not self.ignore_favorites:
                self._nickname_pokemon(pokemon)

    def _localize(self, string):
        if self.translate and string in self.translate:
            return self.translate[string]
        else:
            return string

    def _nickname_pokemon(self, pokemon):
        # type: (Pokemon) -> None
        """
        Nicknaming process
        """

        # We need id of the specific pokemon unstance to be able to rename it
        instance_id = pokemon.id
        if not instance_id:
            self.emit_event(
                'api_error',
                formatted='Failed to get pokemon name, will not rename.'
            )
            return

        # Generate new nickname
        old_nickname = pokemon.nickname
        try:
            new_nickname = self._generate_new_nickname(pokemon, self.template)
        except KeyError as bad_key:
            self.emit_event(
                'config_error',
                formatted="Unable to nickname {} due to bad template ({})"
                          .format(old_nickname, bad_key)
            )
            return

        # Skip if pokemon is already well named
        if pokemon.nickname_raw == new_nickname:
            return

        # Send request
        response = self.bot.api.nickname_pokemon(
            pokemon_id=instance_id, nickname=new_nickname)
        sleep(1.2)  # wait a bit after request

        # Check result
        try:
            result = reduce(dict.__getitem__, ["responses", "NICKNAME_POKEMON"],
                            response)['result']
        except KeyError:
            self.emit_event(
                'api_error',
                formatted='Attempt to nickname received bad response from server.'
            )
            return

        # Nickname unset
        if result == 0:
            self.emit_event(
                'unset_pokemon_nickname',
                formatted="Pokemon {old_name} nickname unset.",
                data={'old_name': old_nickname}
            )
            pokemon.update_nickname(new_nickname)
        elif result == 1:
            self.emit_event(
                'rename_pokemon',
                formatted="Pokemon {old_name} renamed to {current_name}",
                data={'old_name': old_nickname, 'current_name': new_nickname}
            )
            pokemon.update_nickname(new_nickname)
        elif result == 2:
            self.emit_event(
                'pokemon_nickname_invalid',
                formatted="Nickname {nickname} is invalid",
                data={'nickname': new_nickname}
            )
        else:
            self.emit_event(
                'api_error',
                formatted='Attempt to nickname received unexpected result'
                          ' from server ({}).'.format(result)
            )

    def _generate_new_nickname(self, pokemon, template):
        # type: (Pokemon, string) -> string
        """
        New nickname generation
        """

        # Filter template
        # only convert the keys to lowercase, leaving the format specifier alone
        template = re.sub(r"{[\w_\d]*", lambda x:x.group(0).lower(), template).strip()

        # Individial Values of the current specific pokemon (different for each)
        iv_attack = pokemon.iv_attack
        iv_defense = pokemon.iv_defense
        iv_stamina = pokemon.iv_stamina
        iv_list = [iv_attack, iv_defense, iv_stamina]
        iv_sum = sum(iv_list)
        iv_pct = iv_sum / 45.0

        # Basic Values of the pokemon (identical for all of one kind)
        base_attack = pokemon.static.base_attack
        base_defense = pokemon.static.base_defense
        base_stamina = pokemon.static.base_stamina

        # Final Values of the pokemon
        attack = base_attack + iv_attack
        defense = base_defense + iv_defense
        stamina = base_stamina + iv_stamina

        # One character codes for fast/charged attack types
        # If attack is good then character is uppecased, otherwise lowercased
        fast_attack_char = self.attack_char(pokemon.fast_attack)
        charged_attack_char = self.attack_char(pokemon.charged_attack)
        # 2 characters code for both attacks of the pokemon
        attack_code = fast_attack_char + charged_attack_char

        moveset = pokemon.moveset

        pokemon.name = self._localize(pokemon.name)

        #
        # Generate new nickname
        #
        new_name = template.format(
            # Pokemon
            pokemon=pokemon,
            # Pokemon name
            name=pokemon.name,
            # Pokemon ID/Number
            id=int(pokemon.pokemon_id),
            # Combat Points
            cp=int(pokemon.cp),

            # Individial Values of the current specific pokemon
            iv_attack=iv_attack,
            iv_defense=iv_defense,
            iv_stamina=iv_stamina,
            # Joined IV values like: 4/12/9
            iv_ads='/'.join(map(str, iv_list)),
            # Joined IV values in HEX like: 4C9
            iv_ads_hex = ''.join(map(lambda x: format(x, 'X'), iv_list)),
            # Sum of the Individial Values
            iv_sum=iv_sum,
            # IV perfection (in 000-100 format - 3 chars)
            iv_pct="{:03.0f}".format(iv_pct * 100),
            # IV perfection (in 00-99 format - 2 chars)
            #  99 is best (it's a 100% perfection)
            iv_pct2="{:02.0f}".format(iv_pct * 99),
            # IV perfection (in 0-9 format - 1 char)
            #  9 is best (it's a 100% perfection)
            iv_pct1=int(round(iv_pct * 9)),

            # Basic Values of the pokemon (identical for all of one kind)
            base_attack=base_attack,
            base_defense=base_defense,
            base_stamina=base_stamina,
            # Joined Base Values like: 125/93/314
            base_ads='/'.join(map(str, [base_attack, base_defense, base_stamina])),

            # Final Values of the pokemon (Base Values + Individial Values)
            attack=attack,
            defense=defense,
            stamina=stamina,
            # Joined Final Values like: 129/97/321
            sum_ads='/'.join(map(str, [attack, defense, stamina])),

            # IV CP perfection (in 000-100 format - 3 chars)
            # It's a kind of IV perfection percent but calculated
            #  using weight of each IV in its contribution to CP of the best
            #  evolution of current pokemon
            # So it tends to be more accurate than simple IV perfection
            ivcp_pct="{:03.0f}".format(pokemon.ivcp * 100),
            # IV CP perfection (in 00-99 format - 2 chars)
            ivcp_pct2="{:02.0f}".format(pokemon.ivcp * 99),
            # IV CP perfection (in 0-9 format - 1 char)
            ivcp_pct1=int(round(pokemon.ivcp * 9)),

            # One character code for fast attack type
            # If attack is good character is uppecased, otherwise lowercased
            fast_attack_char=fast_attack_char,
            # One character code for charged attack type
            charged_attack_char=charged_attack_char,
            # 2 characters code for both attacks of the pokemon
            attack_code=attack_code,

            # Moveset perfection for attack and for defense (in 000-100 format)
            #  Calculated for current pokemon only, not between all pokemons
            #  So perfect moveset can be weak if pokemon is weak (e.g. Caterpie)
            attack_pct="{:03.0f}".format(moveset.attack_perfection * 100),
            defense_pct="{:03.0f}".format(moveset.defense_perfection * 100),

            # Moveset perfection (in 00-99 format - 2 chars)
            attack_pct2="{:02.0f}".format(moveset.attack_perfection * 99),
            defense_pct2="{:02.0f}".format(moveset.defense_perfection * 99),

            # Moveset perfection (in 0-9 format - 1 char)
            attack_pct1=int(round(moveset.attack_perfection * 9)),
            defense_pct1=int(round(moveset.defense_perfection * 9)),
        )

        # Use empty result for unsetting nickname
        # So original pokemon name will be shown to user
        if new_name == pokemon.name:
            new_name = ''

        # 12 is a max allowed length for the nickname
        return new_name[:MAXIMUM_NICKNAME_LENGTH]

    def attack_char(self, attack):
        # type: (Attack) -> string
        """
        One character code for attack type
        If attack is good then character is uppecased, otherwise lowercased

        Type codes:

        Bug: 'B'
        Dark: 'K'
        Dragon: 'D'
        Electric: 'E'
        Fairy: 'Y'
        Fighting: 'T'
        Fire: 'F'
        Flying: 'L'
        Ghost: 'H'
        Grass: 'A'
        Ground: 'G'
        Ice: 'I'
        Normal: 'N'
        Poison: 'P'
        Psychic: 'C'
        Rock: 'R'
        Steel: 'S'
        Water: 'W'

        it's an effective way to represent type with one character
        if first char is unique - use it, in other case suitable substitute used
        """
        char = attack.type.as_one_char.upper()
        if attack.rate_in_type < self.good_attack_threshold:
            char = char.lower()
        return char

pokemongo_bot/cell_workers/nickname_pokemon.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import json
from pokemongo_bot.base_task import BaseTask
from pokemongo_bot.human_behaviour import sleep
from pokemongo_bot.inventory import pokemons, Pokemon, Attack

import re


DEFAULT_IGNORE_FAVORITES = False
DEFAULT_GOOD_ATTACK_THRESHOLD = 0.7
DEFAULT_TEMPLATE = '{name}'

MAXIMUM_NICKNAME_LENGTH = 12


class NicknamePokemon(BaseTask):
    SUPPORTED_TASK_API_VERSION = 1

    """
    Nickname user pokemons according to the specified template


    PARAMETERS:

    dont_nickname_favorite (default: False)
        Prevents renaming of favorited pokemons

    good_attack_threshold (default: 0.7)
        Threshold for perfection of the attack in it's type (0.0-1.0)
         after which attack will be treated as good.
        Used for {fast_attack_char}, {charged_attack_char}, {attack_code}
         templates

    nickname_template (default: '{name}')
        Template for nickname generation.
        Empty template or any resulting in the simple pokemon name
         (e.g. '', '{name}', ...) will revert all pokemon to their original
         names (as if they had no nickname).

        Niantic imposes a 12-character limit on all pokemon nicknames, so
         any new nickname will be truncated to 12 characters if over that limit.
        Thus, it is up to the user to exercise judgment on what template will
         best suit their need with this constraint in mind.

        You can use full force of the Python [Format String syntax](https://docs.python.org/2.7/library/string.html#formatstrings)
        For example, using `{name:.8s}` causes the Pokemon name to never take up
         more than 8 characters in the nickname. This would help guarantee that
         a template like `{name:.8s}_{iv_pct}` never goes over the 12-character
         limit.


    **NOTE:** If you experience frequent `Pokemon not found` error messages,
     this is because the inventory cache has not been updated after a pokemon
     was released. This can be remedied by placing the `NicknamePokemon` task
     above the `TransferPokemon` task in your `config.json` file.


    EXAMPLE CONFIG:
    {
      "type": "NicknamePokemon",
      "config": {
        "enabled": true,
        "dont_nickname_favorite": false,
        "good_attack_threshold": 0.7,
        "nickname_template": "{iv_pct}_{iv_ads}"
      }
    }


    SUPPORTED PATTERN KEYS:

    {name}  Pokemon name      (e.g. Articuno)
    {id}    Pokemon ID/Number (1-151)
    {cp}    Combat Points     (10-4145)

    # Individial Values
    {iv_attack}  Individial Attack (0-15) of the current specific pokemon
    {iv_defense} Individial Defense (0-15) of the current specific pokemon
    {iv_stamina} Individial Stamina (0-15) of the current specific pokemon
    {iv_ads}     Joined IV values (e.g. 4/12/9)
    {iv_sum}     Sum of the Individial Values (0-45)
    {iv_pct}     IV perfection (in 000-100 format - 3 chars)
    {iv_pct2}    IV perfection (in 00-99 format - 2 chars)
                    So 99 is best (it's a 100% perfection)
    {iv_pct1}    IV perfection (in 0-9 format - 1 char)
    {iv_ads_hex} Joined IV values in HEX (e.g. 4C9)

    # Basic Values of the pokemon (identical for all of one kind)
    {base_attack}   Basic Attack (40-284) of the current pokemon kind
    {base_defense}  Basic Defense (54-242) of the current pokemon kind
    {base_stamina}  Basic Stamina (20-500) of the current pokemon kind
    {base_ads}      Joined Basic Values (e.g. 125/93/314)

    # Final Values of the pokemon (Base Values + Individial Values)
    {attack}        Basic Attack + Individial Attack
    {defense}       Basic Defense + Individial Defense
    {stamina}       Basic Stamina + Individial Stamina
    {sum_ads}       Joined Final Values (e.g. 129/97/321)

    # IV CP perfection - it's a kind of IV perfection percent
    #  but calculated using weight of each IV in its contribution
    #  to CP of the best evolution of current pokemon.
    # So it tends to be more accurate than simple IV perfection.
    {ivcp_pct}      IV CP perfection (in 000-100 format - 3 chars)
    {ivcp_pct2}     IV CP perfection (in 00-99 format - 2 chars)
                        So 99 is best (it's a 100% perfection)
    {ivcp_pct1}     IV CP perfection (in 0-9 format - 1 char)

    # Character codes for fast/charged attack types.
    # If attack is good character is uppecased, otherwise lowercased.
    # Use 'good_attack_threshold' option for customization
    #
    # It's an effective way to represent type with one character.
    #   If first char of the type name is unique - use it,
    #    in other case suitable substitute used
    #
    # Type codes:
    #   Bug: 'B'
    #   Dark: 'K'
    #   Dragon: 'D'
    #   Electric: 'E'
    #   Fairy: 'Y'
    #   Fighting: 'T'
    #   Fire: 'F'
    #   Flying: 'L'
    #   Ghost: 'H'
    #   Grass: 'A'
    #   Ground: 'G'
    #   Ice: 'I'
    #   Normal: 'N'
    #   Poison: 'P'
    #   Psychic: 'C'
    #   Rock: 'R'
    #   Steel: 'S'
    #   Water: 'W'
    #
    {fast_attack_char}      One character code for fast attack type
                                (e.g. 'F' for good Fire or 's' for bad
                                Steel attack)
    {charged_attack_char}   One character code for charged attack type
                                (e.g. 'n' for bad Normal or 'I' for good
                                Ice attack)
    {attack_code}           Joined 2 character code for both attacks
                                (e.g. 'Lh' for pokemon with good Flying
                                and weak Ghost attacks)

    # Moveset perfection percents for attack and for defense
    #  Calculated for current pokemon only, not between all pokemons
    #  So perfect moveset can be weak if pokemon is weak (e.g. Caterpie)
    {attack_pct}   Moveset perfection for attack (in 000-100 format - 3 chars)
    {defense_pct}  Moveset perfection for defense (in 000-100 format - 3 chars)
    {attack_pct2}  Moveset perfection for attack (in 00-99 format - 2 chars)
    {defense_pct2} Moveset perfection for defense (in 00-99 format - 2 chars)
    {attack_pct1}  Moveset perfection for attack (in 0-9 format - 1 char)
    {defense_pct1} Moveset perfection for defense (in 0-9 format - 1 char)

    # Special case: pokemon object.
    # You can access any available pokemon info via it.
    # Examples:
    #   '{pokemon.ivcp:.2%}'             ->  '47.00%'
    #   '{pokemon.fast_attack}'          ->  'Wing Attack'
    #   '{pokemon.fast_attack.type}'     ->  'Flying'
    #   '{pokemon.fast_attack.dps:.2f}'  ->  '10.91'
    #   '{pokemon.fast_attack.dps:.0f}'  ->  '11'
    #   '{pokemon.charged_attack}'       ->  'Ominous Wind'
    {pokemon}   Pokemon instance (see inventory.py for class sources)


    EXAMPLES:

    1. "nickname_template": "{ivcp_pct}_{iv_pct}_{iv_ads}"

    Golbat with IV (attack: 9, defense: 4 and stamina: 8) will result in:
     '48_46_9/4/8'

    2. "nickname_template": "{attack_code}{attack_pct1}{defense_pct1}{ivcp_pct1}{name}"

    Same Golbat (with attacks Wing Attack & Ominous Wind) will have nickname:
     'Lh474Golbat'

    See /tests/nickname_test.py for more examples.
    """

    # noinspection PyAttributeOutsideInit
    def initialize(self):
        self.ignore_favorites = self.config.get(
            'dont_nickname_favorite', DEFAULT_IGNORE_FAVORITES)
        self.good_attack_threshold = self.config.get(
            'good_attack_threshold', DEFAULT_GOOD_ATTACK_THRESHOLD)
        self.template = self.config.get(
            'nickname_template', DEFAULT_TEMPLATE)

        self.translate = None
        locale = self.config.get('locale', 'en')
        if locale != 'en':
            fn = 'data/locales/{}.json'.format(locale)
            if os.path.isfile(fn):
                self.translate = json.load(open(fn))

    def work(self):
        """
        Iterate over all user pokemons and nickname if needed
        """
        for pokemon in pokemons().all():  # type: Pokemon
            if not pokemon.is_favorite or not self.ignore_favorites:
                self._nickname_pokemon(pokemon)

    def _localize(self, string):
        if self.translate and string in self.translate:
            return self.translate[string]
        else:
            return string

    def _nickname_pokemon(self, pokemon):
        # type: (Pokemon) -> None
        """
        Nicknaming process
        """

        # We need id of the specific pokemon unstance to be able to rename it
        instance_id = pokemon.id
        if not instance_id:
            self.emit_event(
                'api_error',
                formatted='Failed to get pokemon name, will not rename.'
            )
            return

        # Generate new nickname
        old_nickname = pokemon.nickname
        try:
            new_nickname = self._generate_new_nickname(pokemon, self.template)
        except KeyError as bad_key:
            self.emit_event(
                'config_error',
                formatted="Unable to nickname {} due to bad template ({})"
                          .format(old_nickname, bad_key)
            )
            return

        # Skip if pokemon is already well named
        if pokemon.nickname_raw == new_nickname:
            return

        # Send request
        response = self.bot.api.nickname_pokemon(
            pokemon_id=instance_id, nickname=new_nickname)
        sleep(1.2)  # wait a bit after request

        # Check result
        try:
            result = reduce(dict.__getitem__, ["responses", "NICKNAME_POKEMON"],
                            response)['result']
        except KeyError:
            self.emit_event(
                'api_error',
                formatted='Attempt to nickname received bad response from server.'
            )
            return

        # Nickname unset
        if result == 0:
            self.emit_event(
                'unset_pokemon_nickname',
                formatted="Pokemon {old_name} nickname unset.",
                data={'old_name': old_nickname}
            )
            pokemon.update_nickname(new_nickname)
        elif result == 1:
            self.emit_event(
                'rename_pokemon',
                formatted="Pokemon {old_name} renamed to {current_name}",
                data={'old_name': old_nickname, 'current_name': new_nickname}
            )
            pokemon.update_nickname(new_nickname)
        elif result == 2:
            self.emit_event(
                'pokemon_nickname_invalid',
                formatted="Nickname {nickname} is invalid",
                data={'nickname': new_nickname}
            )
        else:
            self.emit_event(
                'api_error',
                formatted='Attempt to nickname received unexpected result'
                          ' from server ({}).'.format(result)
            )

    def _generate_new_nickname(self, pokemon, template):
        # type: (Pokemon, string) -> string
        """
        New nickname generation
        """

        # Filter template
        # only convert the keys to lowercase, leaving the format specifier alone
        template = re.sub(r"{[\w_\d]*", lambda x:x.group(0).lower(), template).strip()

        # Individial Values of the current specific pokemon (different for each)
        iv_attack = pokemon.iv_attack
        iv_defense = pokemon.iv_defense
        iv_stamina = pokemon.iv_stamina
        iv_list = [iv_attack, iv_defense, iv_stamina]
        iv_sum = sum(iv_list)
        iv_pct = iv_sum / 45.0

        # Basic Values of the pokemon (identical for all of one kind)
        base_attack = pokemon.static.base_attack
        base_defense = pokemon.static.base_defense
        base_stamina = pokemon.static.base_stamina

        # Final Values of the pokemon
        attack = base_attack + iv_attack
        defense = base_defense + iv_defense
        stamina = base_stamina + iv_stamina

        # One character codes for fast/charged attack types
        # If attack is good then character is uppecased, otherwise lowercased
        fast_attack_char = self.attack_char(pokemon.fast_attack)
        charged_attack_char = self.attack_char(pokemon.charged_attack)
        # 2 characters code for both attacks of the pokemon
        attack_code = fast_attack_char + charged_attack_char

        moveset = pokemon.moveset

        pokemon.name = self._localize(pokemon.name)

        #
        # Generate new nickname
        #
        new_name = template.format(
            # Pokemon
            pokemon=pokemon,
            # Pokemon name
            name=pokemon.name,
            # Pokemon ID/Number
            id=int(pokemon.pokemon_id),
            # Combat Points
            cp=int(pokemon.cp),

            # Individial Values of the current specific pokemon
            iv_attack=iv_attack,
            iv_defense=iv_defense,
            iv_stamina=iv_stamina,
            # Joined IV values like: 4/12/9
            iv_ads='/'.join(map(str, iv_list)),
            # Joined IV values in HEX like: 4C9
            iv_ads_hex = ''.join(map(lambda x: format(x, 'X'), iv_list)),
            # Sum of the Individial Values
            iv_sum=iv_sum,
            # IV perfection (in 000-100 format - 3 chars)
            iv_pct="{:03.0f}".format(iv_pct * 100),
            # IV perfection (in 00-99 format - 2 chars)
            #  99 is best (it's a 100% perfection)
            iv_pct2="{:02.0f}".format(iv_pct * 99),
            # IV perfection (in 0-9 format - 1 char)
            #  9 is best (it's a 100% perfection)
            iv_pct1=int(round(iv_pct * 9)),

            # Basic Values of the pokemon (identical for all of one kind)
            base_attack=base_attack,
            base_defense=base_defense,
            base_stamina=base_stamina,
            # Joined Base Values like: 125/93/314
            base_ads='/'.join(map(str, [base_attack, base_defense, base_stamina])),

            # Final Values of the pokemon (Base Values + Individial Values)
            attack=attack,
            defense=defense,
            stamina=stamina,
            # Joined Final Values like: 129/97/321
            sum_ads='/'.join(map(str, [attack, defense, stamina])),

            # IV CP perfection (in 000-100 format - 3 chars)
            # It's a kind of IV perfection percent but calculated
            #  using weight of each IV in its contribution to CP of the best
            #  evolution of current pokemon
            # So it tends to be more accurate than simple IV perfection
            ivcp_pct="{:03.0f}".format(pokemon.ivcp * 100),
            # IV CP perfection (in 00-99 format - 2 chars)
            ivcp_pct2="{:02.0f}".format(pokemon.ivcp * 99),
            # IV CP perfection (in 0-9 format - 1 char)
            ivcp_pct1=int(round(pokemon.ivcp * 9)),

            # One character code for fast attack type
            # If attack is good character is uppecased, otherwise lowercased
            fast_attack_char=fast_attack_char,
            # One character code for charged attack type
            charged_attack_char=charged_attack_char,
            # 2 characters code for both attacks of the pokemon
            attack_code=attack_code,

            # Moveset perfection for attack and for defense (in 000-100 format)
            #  Calculated for current pokemon only, not between all pokemons
            #  So perfect moveset can be weak if pokemon is weak (e.g. Caterpie)
            attack_pct="{:03.0f}".format(moveset.attack_perfection * 100),
            defense_pct="{:03.0f}".format(moveset.defense_perfection * 100),

            # Moveset perfection (in 00-99 format - 2 chars)
            attack_pct2="{:02.0f}".format(moveset.attack_perfection * 99),
            defense_pct2="{:02.0f}".format(moveset.defense_perfection * 99),

            # Moveset perfection (in 0-9 format - 1 char)
            attack_pct1=int(round(moveset.attack_perfection * 9)),
            defense_pct1=int(round(moveset.defense_perfection * 9)),
        )

        # Use empty result for unsetting nickname
        # So original pokemon name will be shown to user
        if new_name == pokemon.name:
            new_name = ''

        # 12 is a max allowed length for the nickname
        return new_name[:MAXIMUM_NICKNAME_LENGTH]

    def attack_char(self, attack):
        # type: (Attack) -> string
        """
        One character code for attack type
        If attack is good then character is uppecased, otherwise lowercased

        Type codes:

        Bug: 'B'
        Dark: 'K'
        Dragon: 'D'
        Electric: 'E'
        Fairy: 'Y'
        Fighting: 'T'
        Fire: 'F'
        Flying: 'L'
        Ghost: 'H'
        Grass: 'A'
        Ground: 'G'
        Ice: 'I'
        Normal: 'N'
        Poison: 'P'
        Psychic: 'C'
        Rock: 'R'
        Steel: 'S'
        Water: 'W'

        it's an effective way to represent type with one character
        if first char is unique - use it, in other case suitable substitute used
        """
        char = attack.type.as_one_char.upper()
        if attack.rate_in_type < self.good_attack_threshold:
            char = char.lower()
        return char

pokemongo_bot/cell_workers/nickname_pokemon.py
diff --git a/pokemongo_bot/cell_workers/nickname_pokemon.py b/pokemongo_bot/cell_workers/nickname_pokemon.py
index 1ad0496878..cb5ab8e741 100644
--- a/pokemongo_bot/cell_workers/nickname_pokemon.py
+++ b/pokemongo_bot/cell_workers/nickname_pokemon.py
@@ -1,3 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
 import os
 import json
 from pokemongo_bot.base_task import BaseTask

Bot fails to start: UnicodeEncodeError 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
### Expected Behavior

Bot is able to start.
### Actual Behavior

Bot fails to start.

The names of some monsters are specified by Japanese characters. I'm not sure but it might cause this error.
### Your config.json (remove your credentials and any other private info)

```
{
    "auth_service": "google",
    "username": "xxx",
    "password": "xxx",
    "location": "xxx,xxx",
    "gmapkey": "xxx",
    "tasks": [
      {
        "type": "HandleSoftBan"
      },
      {
        "type": "CollectLevelUpReward"
      },
      {
        "type": "IncubateEggs",
        "config": {
          "longer_eggs_first": true
        }
      },
      {
        "type": "NicknamePokemon",
        "config": {
           "nickname_template": "{name:.8s}_{iv_pct}"
        }
      },
      {
        "type": "TransferPokemon"
      },
      {
        "type": "EvolvePokemon",
        "config": {
            "evolve_all": "none",
            "first_evolve_by": "iv",
            "evolve_above_cp": 500,
            "evolve_above_iv": 0.8,
            "logic": "or",
            "evolve_speed": 20,
            "use_lucky_egg": false
        }
      },
      {
        "type": "RecycleItems",
        "config": {
          "item_filter": {
            "Pokeball":       { "keep" : 110 },
            "Greatball":       { "keep" : 150 },
            "Ultraball":       { "keep" : 150 },
            "Potion":         { "keep" : 20 },
            "Super Potion":   { "keep" : 30 },
            "Hyper Potion":   { "keep" : 40 },
            "Revive":         { "keep" : 40 },
            "Razz Berry":     { "keep" : 120 }
          }
        }
      },
      {
        "type": "CatchVisiblePokemon"
      },
      {
        "type": "CatchLuredPokemon"
      },
      {
        "type": "SpinFort"
      },
      {
        "type": "MoveToFort",
        "config": {
            "lure_attraction": true,
            "lure_max_distance": 2000
        }
      },
      {
        "type": "FollowSpiral",
        "config": {
          "diameter": 4,
          "step_size": 70
        }
      }
    ],
    "map_object_cache_time": 5,
    "forts": {
      "avoid_circles": true,
      "max_circle_size": 50
    },
    "websocket_server": false,
    "walk": 4.16,
    "action_wait_min": 1,
    "action_wait_max": 4,
    "debug": false,
    "test": false,
    "health_record": true,
    "location_cache": true,
    "distance_unit": "km",
    "reconnecting_timeout": 15,
    "evolve_captured": "NONE",
    "catch_randomize_reticle_factor": 1.0,
    "catch_randomize_spin_factor": 1.0,
    "catch": {
      "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"},

      "// Example of always catching Rattata:": {},
      "// Rattata": { "always_catch" : true },

      "// Legendary pokemons (Goes under S-Tier)": {},
      "Lapras": { "always_catch": true },
      "Moltres": { "always_catch": true },
      "Zapdos": { "always_catch": true },
      "Articuno": { "always_catch": true },

      "// always catch": {},
      "Charmander": { "always_catch": true },
      "Squirtle": { "always_catch": true },
      "Pikachu": { "always_catch": true },
      "Eevee": { "always_catch": true },
      "Dragonite": { "always_catch": true },
      "Dragonair": { "always_catch": true },
      "Dratini": { "always_catch": true },

      "// never catch": {},
      "Caterpie": {"never_catch": true},
      "Weedle": {"never_catch": true},
      "Pidgey": {"never_catch": true},
      "Rattata": {"never_catch": true},
      "Psyduck": {"never_catch": true},
      "Slowpoke": {"never_catch": true}
    },
    "release": {
      "any": {"keep_best_iv": 2, "logic": "or"},
      "Exeggcutor": { "never_release" : true },
      "Gyarados": { "never_release" : true },
      "Lapras": { "never_release" : true },
      "Vaporeon": { "never_release" : true },
      "Jolteon": { "never_release" : true },
      "Flareon": { "never_release" : true },
      "Snorlax": { "never_release" : true },
      "Dragonite": { "never_release" : true },
      "// any": {"keep_best_cp": 2, "keep_best_iv": 2, "logic": "or"},
      "// any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"},
      "// Example of always releasing Rattata:": {},
      "// Rattata": {"always_release": true},
      "// Example of keeping 3 stronger (based on CP) Pidgey:": {},
      "// Pidgey": {"keep_best_cp": 3},
      "// Example of keeping 2 stronger (based on IV) Zubat:": {},
      "// Zubat": {"keep_best_iv": 2},
      "// Also, it is working with any": {},
      "// any": {"keep_best_iv": 3},
      "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {},
      "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3}
    },
    "vips" : {
         "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {},
        "any": {"catch_above_cp": 1200, "catch_above_iv": 0.9, "logic": "or" },
        "Lapras": {},
        "Moltres": {},
        "Zapdos": {},
        "Articuno": {},

        "// S-Tier pokemons (if pokemon can be evolved into tier, list the representative)": {},
        "Mewtwo": {},
        "Dragonite": {},
        "Snorlax": {},
        "// Mew evolves to Mewtwo": {},
        "Mew": {},
        "Arcanine": {},
        "Vaporeon": {},
        "Gyarados": {},
        "Exeggutor": {},
        "Muk": {},
        "Weezing": {},
        "Flareon": {}

    }
}
```
### Steps to Reproduce

2016-08-15 10:38:47,935 [       cli] [INFO] PokemonGO Bot v1.0
2016-08-15 10:38:47,936 [       cli] [INFO] No config argument specified, checking for /configs/config.json
2016-08-15 10:38:47,939 [       cli] [WARNING] The evolve_captured argument is no longer supported. Please use the EvolvePokemon task instead
2016-08-15 10:38:47,940 [       cli] [INFO] Configuration initialized
2016-08-15 10:38:47,940 [pokemongo_bot.health_record.bot_event] [INFO] Health check is enabled. For more information:
2016-08-15 10:38:47,940 [pokemongo_bot.health_record.bot_event] [INFO] https://github.com/PokemonGoF/PokemonGo-Bot/tree/dev#analytics
2016-08-15 10:38:47,945 [requests.packages.urllib3.connectionpool] [INFO] Starting new HTTP connection (1): www.google-analytics.com
2016-08-15 10:38:48,039 [PokemonGoBot] [INFO] [set_start_location] Setting start location.
2016-08-15 10:38:48,048 [PokemonGoBot] [INFO] [x] Coordinates found in passed in location, not geocoding.
2016-08-15 10:38:48,049 [PokemonGoBot] [INFO] [location_found] Location found: xxx, xxx (xxx,xxx, 0.0)
2016-08-15 10:38:48,049 [PokemonGoBot] [INFO] [position_update] Now at (xxx, xxx, 0)
2016-08-15 10:38:48,049 [PokemonGoBot] [INFO] [login_started] Login procedure started.
2016-08-15 10:38:50,020 [PokemonGoBot] [INFO] [login_successful] Login successful.
2016-08-15 10:38:52,387 [PokemonGoBot] [INFO] 
2016-08-15 10:38:52,387 [PokemonGoBot] [INFO] --- sunnyfortune ---
2016-08-15 10:38:52,387 [PokemonGoBot] [INFO] Level: 24 (Next Level: 69740 XP) (Total: 640260 XP)
2016-08-15 10:38:52,387 [PokemonGoBot] [INFO] Pokemon Captured: 1688 | Pokestops Visited: 1917
2016-08-15 10:38:52,388 [PokemonGoBot] [INFO] Pokemon Bag: 194/250
2016-08-15 10:38:52,389 [PokemonGoBot] [INFO] Items: 689/700
2016-08-15 10:38:52,389 [PokemonGoBot] [INFO] Stardust: 247878 | Pokecoins: 70
2016-08-15 10:38:52,389 [PokemonGoBot] [INFO] PokeBalls: 96 | GreatBalls: 154 | UltraBalls: 150 | MasterBalls: 0
2016-08-15 10:38:52,390 [PokemonGoBot] [INFO] RazzBerries: 124 | BlukBerries: 0 | NanabBerries: 0
2016-08-15 10:38:52,390 [PokemonGoBot] [INFO] LuckyEgg: 6 | Incubator: 8 | TroyDisk: 11
2016-08-15 10:38:52,390 [PokemonGoBot] [INFO] Potion: 23 | SuperPotion: 30 | HyperPotion: 41 | MaxPotion: 0
2016-08-15 10:38:52,390 [PokemonGoBot] [INFO] Incense: 4 | IncenseSpicy: 0 | IncenseCool: 0
2016-08-15 10:38:52,390 [PokemonGoBot] [INFO] Revive: 40 | MaxRevive: 0
2016-08-15 10:38:52,390 [PokemonGoBot] [INFO] 
2016-08-15 10:38:52,391 [PokemonGoBot] [INFO] Found encrypt.so! Platform: linux2 Encrypt.so directory: /home/sunny/project/PokemonGo-Bot
2016-08-15 10:38:52,391 [PokemonGoBot] [INFO] 
2016-08-15 10:38:53,321 [PokemonGoBot] [INFO] [bot_start] Starting bot...
2016-08-15 10:38:53,637 [CollectLevelUpReward] [INFO] [level_up_reward] Received level up reward: []
2016-08-15 10:38:53,638 [IncubateEggs] [INFO] [next_egg_incubates] Next egg incubates in 0.13 km
2016-08-15 10:38:56,931 [       cli] [INFO] 
2016-08-15 10:38:56,931 [       cli] [INFO] Ran for 0:00:09
2016-08-15 10:38:56,932 [       cli] [INFO] Total XP Earned: 0  Average: 0.00/h
2016-08-15 10:38:56,932 [       cli] [INFO] Travelled 0.00km
2016-08-15 10:38:56,932 [       cli] [INFO] Visited 0 stops
2016-08-15 10:38:56,932 [       cli] [INFO] Encountered 0 pokemon, 0 caught, 0 released, 0 evolved, 0 never seen before
2016-08-15 10:38:56,932 [       cli] [INFO] Threw 0 pokeballs
2016-08-15 10:38:56,933 [       cli] [INFO] Earned 0 Stardust
2016-08-15 10:38:56,933 [       cli] [INFO] 
2016-08-15 10:38:56,933 [       cli] [INFO] Highest CP Pokemon: 
2016-08-15 10:38:56,933 [       cli] [INFO] Most Perfect Pokemon: 
Traceback (most recent call last):
  File "pokecli.py", line 578, in <module>
    main()
  File "pokecli.py", line 103, in main
    bot.tick()
  File "/home/sunny/project/PokemonGo-Bot/pokemongo_bot/**init**.py", line 482, in tick
    if worker.work() == WorkerResult.RUNNING:
  File "/home/sunny/project/PokemonGo-Bot/pokemongo_bot/cell_workers/nickname_pokemon.py", line 204, in work
    self._nickname_pokemon(pokemon)
  File "/home/sunny/project/PokemonGo-Bot/pokemongo_bot/cell_workers/nickname_pokemon.py", line 271, in _nickname_pokemon
    data={'old_name': old_nickname, 'current_name': new_nickname}
  File "/home/sunny/project/PokemonGo-Bot/pokemongo_bot/base_task.py", line 28, in emit_event
    data=data
  File "/home/sunny/project/PokemonGo-Bot/pokemongo_bot/event_manager.py", line 61, in emit
    formatted_msg = formatted.format(*_data)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
2016-08-15 10:38:56,954 [sentry.errors] [ERROR] Sentry responded with an error: 'ascii' codec can't decode byte 0x9c in position 1: ordinal not in range(128) (url: https://app.getsentry.com/api/90254/store/)
Traceback (most recent call last):
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/raven/transport/threaded.py", line 174, in send_sync
    super(ThreadedHTTPTransport, self).send(data, headers)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/raven/transport/http.py", line 47, in send
    ca_certs=self.ca_certs,
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/raven/utils/http.py", line 66, in urlopen
    return opener.open(url, data, timeout)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/future/backports/urllib/request.py", line 494, in open
    response = self._open(req, data)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/future/backports/urllib/request.py", line 512, in _open
    '_open', req)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/future/backports/urllib/request.py", line 466, in _call_chain
    result = func(_args)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/raven/utils/http.py", line 46, in https_open
    return self.do_open(ValidHTTPSConnection, req)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/site-packages/future/backports/urllib/request.py", line 1284, in do_open
    h.request(req.get_method(), req.selector, req.data, headers)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/httplib.py", line 1057, in request
    self._send_request(method, url, body, headers)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/httplib.py", line 1097, in _send_request
    self.endheaders(body)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/httplib.py", line 1053, in endheaders
    self._send_output(message_body)
  File "/home/sunny/.pyenv/versions/anaconda2-2.5.0/envs/poke/lib/python2.7/httplib.py", line 895, in _send_output
    msg += message_body
UnicodeDecodeError: 'ascii' codec can't decode byte 0x9c in position 1: ordinal not in range(128)
2016-08-15 10:38:56,958 [sentry.errors.uncaught] [ERROR] [u"UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)", u'  File "pokecli.py", line 578, in <module>', u'  File "pokecli.py", line 103, in main', u'  File "pokemongo_bot/__init__.py", line 482, in tick', u'  File "pokemongo_bot/cell_workers/nickname_pokemon.py", line 204, in work', u'  File "pokemongo_bot/cell_workers/nickname_pokemon.py", line 271, in _nickname_pokemon', u'  File "pokemongo_bot/base_task.py", line 28, in emit_event', u'  File "pokemongo_bot/event_manager.py", line 61, in emit']
### Other Information

OS:ubuntu 14.04 LTS
Git Commit: 5c9cdb53e69b5069cee6fe100d39e3cf5d63539c
Python Version: Python 2.7.12 :: Continuum Analytics, Inc.

