"""
Overview
===============================================================================

+----------+------------------------------------------------------------------+
| Path     | PyPoE/cli/exporter/wiki/parsers/area.py                          |
+----------+------------------------------------------------------------------+
| Version  | 1.0.0a0                                                          |
+----------+------------------------------------------------------------------+
| Revision | $Id$                  |
+----------+------------------------------------------------------------------+
| Author   | Omega_K2                                                         |
+----------+------------------------------------------------------------------+

Description
===============================================================================



Agreement
===============================================================================

See PyPoE/LICENSE

Documentation
===============================================================================

Public API
-------------------------------------------------------------------------------

Interal API
-------------------------------------------------------------------------------
"""

# =============================================================================
# Imports
# =============================================================================

# Python
from functools import partialmethod
from collections import OrderedDict

# 3rd-party

# self
from PyPoE.cli.core import console, Msg
from PyPoE.cli.exporter.wiki.handler import ExporterHandler, ExporterResult, \
    add_format_argument
from PyPoE.cli.exporter.wiki.parser import BaseParser, format_result_rows

# =============================================================================
# Globals
# =============================================================================

__all__ = []

# =============================================================================
# Classes
# =============================================================================


class AreaCommandHandler(ExporterHandler):
    def __init__(self, sub_parser):
        self.parser = sub_parser.add_parser(
            'area',
            help='Area Exporter',
        )
        self.parser.set_defaults(func=lambda args: self.parser.print_help())

        sub = self.parser.add_subparsers()

        # By id
        a_id = sub.add_parser(
            'id',
            help='Extract areas by their id.'
        )
        self.add_default_parsers(
            parser=a_id,
            cls=AreaParser,
            func=AreaParser.by_id,
        )
        add_format_argument(a_id)
        a_id.add_argument(
            'area_id',
            help='Id of the area, can be specified multiple times.',
            nargs='+',
        )

        # by name
        a_name = sub.add_parser(
            'name',
            help='Extract areas by their name.'
        )
        self.add_default_parsers(
            parser=a_name,
            cls=AreaParser,
            func=AreaParser.by_name,
        )
        add_format_argument(a_name)
        a_name.add_argument(
            'area_name',
            help='Visible name of the area (localized), can be specified multiple times.',
            nargs='+',
        )

        # by row ID
        a_rid = sub.add_parser(
            'rowid',
            help='Extract areas by rowid.'
        )
        self.add_default_parsers(
            parser=a_rid,
            cls=AreaParser,
            func=AreaParser.by_rowid,
        )
        add_format_argument(a_rid)
        a_rid.add_argument(
            'start',
            help='Starting index',
            nargs='?',
            type=int,
            default=0,
        )
        a_rid.add_argument(
            'end',
            nargs='?',
            help='Ending index',
            type=int,
        )


class AreaParser(BaseParser):
    _files = [
        'WorldAreas.dat'
    ]

    _area_column_index_filter = partialmethod(
        BaseParser._column_index_filter,
        dat_file_name='WorldAreas.dat',
        error_msg='Several areas have not been found:\n%s',
    )

    _COPY_KEYS = OrderedDict((
        ('Id', {
            'template': 'id',
        }),
        ('Name', {
            'template': 'name',
        }),
        ('Act', {
            'template': 'act',
        }),
        ('AreaLevel', {
            'template': 'level',
        }),
        ('MaxLevel', {
            'template': 'level_restriction_max',
            'default': 100,
        }),
        ('AreaType_TagsKeys', {
            'template': 'area_type_tags',
            'format': lambda value: ', '.join([
                tag['Id'] for tag in value
            ]),
            'default': [],
        }),
        ('TagsKeys', {
            'template': 'tags',
            'format': lambda value: ', '.join([
                tag['Id'] for tag in value
            ]),
            'default': [],
        }),
        ('LoadingScreen_DDSFile', {
            'template': 'loading_screen',
            'format': lambda value: value.replace('Art/Textures/Interface/Loadi'
                'ngImages/', '').replace('.dds', ''),
        }),
        ('Connections_WorldAreasKeys', {
            'template': 'connections',
            'format': lambda value: ', '.join([
                area['Id'] for area in value
            ]),
            'default': [],
        }),
        ('ParentTown_WorldAreasKey', {
            'template': 'parent_town',
            'format': lambda value: value['Id'],
        }),
        ('ModsKeys', {
            'template': 'mod_ids',
            'format': lambda value: ', '.join([
                mod['Id'] for mod in value
            ]),
            'default': [],
        }),
        ('Bosses_MonsterVarietiesKeys', {
            'template': 'boss_monster_ids',
            'format': lambda value: ', '.join([
                mv['Id'] for mv in value
            ]),
            'default': [],
        }),
        ('Monsters_MonsterVarietiesKeys', {
            'template': 'monster_ids',
            'format': lambda value: ', '.join([
                mv['Id'] for mv in value
            ]),
            'default': [],
        }),
        ('FirstEntry_NPCTextAudioKey', {
            'template': 'entry_text',
            'format': lambda value: value['Text'],
        }),
        ('FirstEntry_NPCsKey', {
            'template': 'entry_npc',
            'condition': lambda area:
                area['FirstEntry_NPCTextAudioKey'] is not None,
            'format': lambda value: value['Name'],
        }),
        # Spawn chances section
        ('VaalArea_SpawnChance', {
            'template': 'vaal_area_spawn_chance',
            'condition': lambda area: area['VaalArea_SpawnChance'] > 0 and
                                      area['VaalArea_WorldAreasKeys'],
        }),
        ('VaalArea_WorldAreasKeys', {
            'template': 'vaal_area_ids',
            'condition': lambda area: area['VaalArea_SpawnChance'] > 0 and
                                      area['VaalArea_WorldAreasKeys'],
            'format': lambda value: ', '.join([
                area['Id'] for area in value
            ]),
        }),

        ('Strongbox_SpawnChance', {
            'template': 'strongbox_spawn_chance',
            'condition': lambda area: area['Strongbox_SpawnChance'] > 0,
        }),
        ('Strongbox_MaxCount', {
            'template': 'strongbox_max',
            'condition': lambda area: area['Strongbox_SpawnChance'] > 0,
            'default': 0,
        }),
        ('Strongbox_RarityWeight', {
            'template': 'strongbox_rarity_weight',
            'condition': lambda area: area['Strongbox_SpawnChance'] > 0,
            'default': '',
            'format': lambda value: ', '.join([str(v) for v in value]),
        }),
        # bools
        ('IsMapArea', {
            'template': 'is_map',
            'default': False,
        }),
        ('IsUniqueMapArea', {
            'template': 'is_unique_map_area',
            'default': False,
        }),
        ('IsTown', {
            'template': 'is_town',
            'default': False,
        }),
        ('IsHideout', {
            'template': 'is_hideout',
            'default': False,
        }),
        ('IsVaalArea', {
            'template': 'is_vaal_area',
            'default': False,
        }),
        ('IsMasterDailyArea', {
            'template': 'is_master_daily_area',
            'default': False,
        }),
        ('IsLabyrinthArea', {
            'template': 'is_labyrinth_area',
            'default': False,
        }),
        ('IsLabyrinthAirlock', {
            'template': 'is_labyrinth_airlock',
            'default': False,
        }),
        ('IsLabyrinthBossArea', {
            'template': 'is_labyrinth_boss_area',
            'default': False,
        }),
        ('HasWaypoint', {
            'template': 'has_waypoint',
            'default': False,
        }),
    ))

    def by_rowid(self, parsed_args):
        return self.export(
            parsed_args,
            self.rr['WorldAreas.dat'][parsed_args.start:parsed_args.end],
        )

    def by_id(self, parsed_args):
        return self.export(parsed_args, self._area_column_index_filter(
            column_id='Id', arg_list=parsed_args.area_id
        ))

    def by_name(self, parsed_args):
        return self.export(parsed_args, self._area_column_index_filter(
            column_id='Name', arg_list=parsed_args.area_name
        ))

    def export(self, parsed_args, areas):
        console('Found %s areas, parsing...' % len(areas))

        r = ExporterResult()

        if areas:
            console('Found %s areas. Processing...' % len(areas))
        else:
            console(
                'No areas found for the specified parameters. Quitting.',
                msg=Msg.warning,
            )
            return r

        for area in areas:
            data = OrderedDict()

            for row_key, copy_data in self._COPY_KEYS.items():
                value = area[row_key]

                condition = copy_data.get('condition')
                if condition is not None and not condition(area):
                    continue

                # Skip default values to reduce size of template
                if value == copy_data.get('default'):
                    continue
                '''default = copy_data.get('default')
                if default is not None and value == default:
                        continue'''

                fmt = copy_data.get('format')
                if fmt:
                    value = fmt(value)
                data[copy_data['template']] = value

            for i, (tag, value) in enumerate(zip(area['SpawnWeight_TagsKeys'],
                                                 area['SpawnWeight_Values'])):
                data['spawn_weight%s_tag' % i] = tag['Id']
                data['spawn_weight%s_value' % i] = value

            r.add_result(
                text=format_result_rows(
                    parsed_args=parsed_args,
                    template_name='Area',
                    ordered_dict=data,
                ),
                out_file='area_%s.txt' % data['id'],
                wiki_page=[
                    {
                        'page': 'Area:' + self._format_wiki_title(data['id']),
                        'condition': None
                    },
                ],
                wiki_message='Mod updater',
            )


        return r

# =============================================================================
# Functions
# =============================================================================
