# -*- coding: utf-8 -*-
"""
Ситуация такова. Котировка имеет несколько имен. Первое имя - это имя котировки
в исходных данных. Второе имя - это человеческое имя. Третье имя - это число,
под которым котировка хранится в базе данных. Этот модуль нужен для
преобразования человеческого имени в объект класса L{Quote}.
"""

import json
import codecs
from stocks3.core.config import Configurable
from stocks3.core.stock import *
from stocks3.core.stockscatalog import StocksCatalog
from stocks3.share.singleton import Singleton


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


class ConfigurableStock(Configurable, StockWithUnit):
    def makeConfig(self):
        self.configName = self.readString("", "stock").strip()
        stocksCatalog = StocksCatalog()
        if not stocksCatalog.is_valid_stock(self.configName):
            print(self.configName, 'is not valid stock!')
            import sys
            sys.exit(255)
            # raise RuntimeError("Unknown stock: %s" % self.configName.encode("utf-8"))
        defaultUnit = stocksCatalog.get_unit(self.configName)
        self.configUnit = self.readString("", "unit", defaultUnit)
        self.configScale = self.readFloat("", "scale", 1.0)
        return self

    def __init__(self, tree, node):
        Configurable.__init__(self, tree, node)
        unit = Unit(self.configUnit, self.configScale)
        StockWithUnit.__init__(self, self.configName, unit)


class QuoteError(Exception):
    pass


# FIXME: Здесь нужен singleton, но он тогда ломает прохождение тестов test_config.py и test_imports.py
class QuotesConfig(object):     # , metaclass=Singleton):

    def __init__(self, quotes_config):
        self._quotes_config = {}
        with codecs.open(quotes_config, 'r', 'utf-8') as fp:
            self._quotes_config = json.load(fp)
        self._quotes = {}
        self._reverse_quotes = {}
        self._names = {}
        for quote_config in self._quotes_config:
            name = quote_config.get('name')
            if name in self._quotes:
                raise RuntimeError("Quote with name %s already defined." % name.encode("utf-8"))
            quote = Quote(quote_config)
            self._quotes[name] = quote
            if quote.quote_id in self._reverse_quotes:
                raise RuntimeError("Quote with id %s already defined (name - %s)" %
                                   (quote.quote_id, self._names[quote.quote_id].encode("utf-8")))
            self._reverse_quotes[quote.quote_id] = quote
            self._names[quote.quote_id] = name

    def getQuote(self, name):
        return self.get_quote(name)

    def get_quote(self, name):
        """
        @param name: имя котировки в виде unicode.
        """
        try:
            return self._quotes[name]
        except KeyError as e:
            # print('Unknown quote {}'.format(e))
            # print(self._quotes)
            # import traceback
            # traceback.print_tb(e.__traceback__)
            # traceback.print_stack()
            raise QuoteError("Unknown quote %s" % e)

    def getQuoteByName(self, name):
        return self.getQuote(name)

    def get_quote_by_name(self, name):
        return self.get_quote(name)

    def getQuoteName(self, ident):
        return self.get_quote_name(ident)

    def get_quote_name(self, ident):
        return self._names[int(ident)]

    def getAllQuotes(self):
        for name, quote in list(self._quotes.items()):
            yield (name, quote)

    def getQuoteByInnerId(self, innerId):
        return self.get_quote_by_id(innerId)

    def get_quote_by_id(self, quote_id):
        """
        Ищет котировку по её внутреннему идентификатору.
        """
        assert type(quote_id) == int
        return self._reverse_quotes[quote_id] if quote_id in self._reverse_quotes else None
