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

"""
Место, куда стекаются данные из источника.
"""
import os
import tempfile
import hashlib

from stocks3.core.config import Configurable
from stocks3.core.factories import places
from stocks3.share.db import Database
from stocks3.core.withdbconfig import WithDBConfiguration
from stocks3.core.utils import force_decode


TEMPFILE_SUFFIX = "stocks3"


class MongoPlace(WithDBConfiguration):
    # def __init__(self, source, configfile):
    def __init__(self, source, tree, node):
        self.source_id = source.sourceId
        self.source_inner_id = source.source_inner_id
        self.composite_id = ''
        self.content = ''
        self.last_contenthash = ''
        self.contenthash = ''
        # print(configfile)
        WithDBConfiguration.__init__(self, tree, node)
        # print(self.get_dbinfo())
        self.db = Database(self.get_dbinfo())

    def makeConfig(self):
        WithDBConfiguration.makeConfig(self)

    def make_config(self):
        WithDBConfiguration.make_config(self)

    def store(self, content, transport_case_id=''):
        self.composite_id = '/'.join([str(self.source_inner_id), transport_case_id])
        data_from_db = self.db.place_get(self.composite_id)
        if data_from_db is None:
            data_from_db = {}
        self.last_contenthash = data_from_db.get('last_contenthash', '')

        if isinstance(content, bytes):
            content = force_decode(content)

        assert isinstance(content, str)
        self.content = content
        self.contenthash = hashlib.sha1(self.content.encode('utf-8')).hexdigest()
        if data_from_db.get('contenthash', '') != self.contenthash:
            # позволяем запись в базу только нового контента
            self.db.place_save(self.composite_id, self.content, self.contenthash)

    def check_new_content(self):
        return self.contenthash != self.last_contenthash

    def read(self):
        return self.content

    def clean(self, success=False):
        self.content = None
        if success:
            self.db.place_update_last_contenthash(self.composite_id, self.contenthash)


class AbstractPlace(object):
    """
    Абстрактное место.
    """

    def __init__(self):
        pass

    def clean(self):
        pass


class Place(AbstractPlace):
    def __init__(self, *args, **wargs):
        AbstractPlace.__init__(self)


class FilePlace(Place):
    def __init__(self, tree, node):
        Place.__init__(self, tree, node)

    def makeConfig(self):
        self._tmp = None
        self._fd = None
        # FIXME: нужно запретить использование этого поля и работать с
        # источником через метод open_for_read (которого ещё нет).
        self.filename = self.readString("", "filename", "") or None
        if self.filename is None:
            self._fd, self._tmp = tempfile.mkstemp(TEMPFILE_SUFFIX)
            self.filename = self._tmp
        return self

    def _open(self, mode):
        if self._tmp is None:
            return open(self.filename, mode)
        else:
            return os.fdopen(self._fd, mode)

    def open_for_write(self):
        return self._open("wb")

    def open_for_read(self):
        # FIXME: такой же метод есть и у TempFile
        return self._open("rb")

    def clean(self):
        if self._tmp is not None:
            os.unlink(self._tmp)


class TempFile(AbstractPlace):
    def __init__(self):
        self._fd, self.filename = tempfile.mkstemp(TEMPFILE_SUFFIX)

    def open_for_write(self):
        return os.fdopen(self._fd, "wb")

    def open_for_read(self):
        return os.fdopen(self._fd, "rb")

    def clean(self):
        if self.filename is not None:
            os.unlink(self.filename)


class TempFiles(Configurable, AbstractPlace):
    def __init__(self, tree, node):
        Configurable.__init__(self, tree, node)
        AbstractPlace.__init__(self)
        self._files = []

    def makeTempFile(self, name):
        f = TempFile()
        self._files.append((name, f))
        return f

    def clean(self):
        for name, f in self._files:
            f.clean()

    def __iter__(self):
        return self._files.__iter__()


# Регистрируем места.
# places.register("stocks3.places.File", FilePlace)
# places.register("stocks3.places.TempFiles", TempFiles)
# places.register("stocks3.places.MongoPlace", MongoPlace)
