# -*- coding: utf-8 -*-

"""
Шаблонизатор, который обрабатывает множество значений.
"""

from stocks3.core.config import ConfigurationError
from stocks3.core.factories import templaters
from stocks3.core.sharedregion import fix_earth_region
from stocks3.export.templater import Templater

__author__ = "Zasimov Alexey"
__email__ = "zasimov-a@yandex-team.ru"


class SetTemplater(Templater):
    TEMPFILE_SUFFIX = "stocks3_set_templater"

    def __init__(self, tree, node, exporter, calculator):
        Templater.__init__(self, tree, node, exporter, calculator)
        self._quotes = {}

    def makeConfig(self):
        Templater.makeConfig(self)
        if self.output_file is None:
            raise ConfigurationError("Parameter .output-file is not defined.")
        self.output_count = self.readInt("", "output-count", 0) or None

    def push(self, quote, data):
        Templater.push(self, quote, data)
        if quote.quote_id in self._quotes:
            raise RuntimeError("templater push duplicate: %s" % quote.quote_id)
        self._quotes[quote.quote_id] = (quote, data)

    def flush(self):
        ns = self.make_default_env()
        quotes = []
        quotes_for_index = []
        for quote_, regions in sorted(list(self._quotes.values()), key=lambda k_v: (int(k_v[0].quote_id), k_v[1])):
            r = []
            for region_id, prices in list(regions.items()):
                if self.output_count:
                    prices = prices[:self.output_count]
                r.append({'id': region_id, 'prices': prices})
            if 0 in regions:
                quotes_for_index.append({
                    'quote': quote_,
                    'prices': regions[0],
                })
            quotes.append({
                'quote': quote_,
                'regions': r,
            })
        ns.update({"quotes": quotes})
        ns.update({"quotes_for_index": quotes_for_index})
        self.save_through_tmp(ns, self.output_file)


def extract(d, keys):
    return dict((k, d[k]) for k in keys if k in d)


class SetTemplaterWithRegions(SetTemplater):
    """
    Отбрасывает значения для ненужных регионов.

    Используется при генерации экспорта для устройств.

    Параметры фильтрации задаются в виде xml:
        <regions>
            <region id="0">
                <quote name="name"/>
            </region>
        </regions>

        <locales>
            <locale language="lang" country="country">
                <region id="0">
                    <quote name="name"/>
                </region>
            </locale>
        </locale>

    Много логики в шаблоне tmpl/device.tmpl
    """

    def makeConfig(self):
        SetTemplater.makeConfig(self)
        # Читаем таблицу region - quotes.
        # self.regions = {}
        self.quotes_for_region = {}

        # Множество всех необходимых регионов (используется при фильтрации)
        all_regions = set()

        for region in self.node.findall("regions/region"):
            region_id = self.fix_region(int(region.attrib["id"]))
            for quote in region.findall("quote"):
                quote_name = quote.attrib["name"]
                quote_id = self.exporter.getQuoteId(quote_name)

                # Множество всех регионов.
                all_regions.update([region_id])

                # Для каждой котировки регионы (не используется)
                # Нужно для _filter_data, а она тоже не используется.
                # if quote_id not in self.regions:
                #    self.regions[quote_id] = [region_id]
                # else:
                #    self.regions[quote_id].append(region_id)

                # Для каждого из выводимых регионов список выводимых котировок.
                if region_id in self.quotes_for_region:
                    self.quotes_for_region[region_id].append(quote_id)
                else:
                    self.quotes_for_region[region_id] = [quote_id]
        all_regions = list(all_regions)
        self.all_regions = [{'id': region, 'stocks': self.quotes_for_region[region]} for region in all_regions]

        # Читаем параметры локалей.

        # Мы не обновляем здесь all_regions, так как смысл этой переменной
        # исказился. Она используется в шаблоне для вывода списка регионов в
        # секции index.

        self.locales = []
        for locale in self.node.findall("locales/locale"):
            one_locale = {
                'language': locale.attrib["language"],
                'country': locale.attrib["country"],

            }
            # Словарь, где для каждого региона будет хранится список котировок,
            # которые нужно будет отобразить.
            regions = {}
            for region in locale.findall("region"):
                region_id = self.fix_region(int(region.attrib["id"]))
                for quote in region.findall("quote"):
                    quote_name = quote.attrib["name"]
                    quote_id = self.exporter.getQuoteId(quote_name)

                    if region_id in regions:
                        regions[region_id].append(quote_id)
                    else:
                        regions[region_id] = [quote_id]
            one_locale['regions'] = [{'id': region_id, 'quotes': quotes} for region_id, quotes in list(regions.items())]
            self.locales.append(one_locale)

    def _filter_regions(self, regions):
        """
        Так как нам нужно выводить только те регионы, которые указаны в
        конфигурации, а не те, для которых есть значения, фильтруем этой
        функцией.
        regions - словарь: region -> quotes
        """
        extracted = extract(regions, self.all_regions)
        # Добавляем регионы, которых не хватает.
        for region in self.all_regions:
            if region not in extracted:
                extracted[region] = {}
        return extracted

    def _filter_regions_for_locale(self, locale, regions):
        """ Обтрасывает регионы, которые не нужно выводить для локали.
        """
        pass

    def _make_show_string(self, region):
        """
        Список выводимых котировок для региона region.
        """
        return ",".join(map(str, self.quotes_for_region[region]))

    def get_quotes_for_region(self, region):
        """
        Для региона region возвращает список отображаемых котировок.
        Для построения идекса.
        """
        return self.quotes_for_region[region]

    def get_quotes_for_region_and_locale(self, locale, region):
        """
        Список котировок для локали и региона.
        """
        pass

    @staticmethod
    def fix_region(region):
        """ В базе земля - 0, в экспорте земля - 10000.
        """
        return fix_earth_region(region)

    def make_default_env(self):
        """
        Добавляем функции, необходимые для фильтрации регионов.
        """
        ns = SetTemplater.make_default_env(self)
        ns["filter_regions"] = self._filter_regions
        ns["filter_regions_for_locale"] = self._filter_regions_for_locale
        ns["make_show_string"] = self._make_show_string
        ns["quotes_for_region_and_locale"] = self.get_quotes_for_region_and_locale
        ns["all_regions"] = self.all_regions
        ns["locales"] = self.locales
        return ns

    def flush(self):
        ns = self.make_default_env()
        quotes = []
        for quote_, regions in sorted(list(self._quotes.values()), key=lambda k_v1: (int(k_v1[0].quote_id), k_v1[1])):
            r = []
            for region_id, prices in list(regions.items()):
                if self.output_count:
                    prices = prices[:self.output_count]
                r.append({'id': self.fix_region(region_id), 'prices': prices})
            quotes.append({
                'quote': quote_,
                'regions': r,
            })
        ns.update({"quotes": quotes})
        self.save_through_tmp(ns, self.output_file)

    def _filter_data(self, quote, data):
        """
        Выбирает данные только для интересных нам регионов.
        Не используется.
        """
        # Список интересных нам регионов
        try:
            regions = self.regions[quote.quote_id]
        except KeyError:
            return None
        filtered = {}
        for region, prices in list(data.items()):
            if region in regions:
                filtered[region] = prices
        return filtered


templaters.register("stocks3.templaters.Set", SetTemplater)
templaters.register("stocks3.templaters.SetWithRegions", SetTemplaterWithRegions)
