# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
import ulib.base.i_need_py23

__all__ = ('MultipleStore',)

from ulib.base.base import isseq
from ulib.base.uio import _s, _u
from consts import *
from store import AbstractStore

class MultipleStore(AbstractStore):
    _stores = None
    _cstores = None
    _last_lsid = 0

    def __init__(self, stores=None):
        AbstractStore.__init__(self)
        if stores is None: stores = ()
        elif not isseq(stores): stores = (stores,)
        self._stores = []
        for store in stores:
            self.add_store(store)

    def add_store(self, store):
        if store.get_sid() is None:
            store.set_lsid(self._last_lsid)
            self._last_lsid = self._last_lsid + 1
        self._stores.append(store)
        self._cstores = None # pour qu'il soit reconstruit

    def get_name(self):
        u"""Retourner le nom de ce store.

        Il s'agit des noms de tous les stores gérés par ce store, séparés par
        des caractères '+'.

        @rtype: unicode
        """
        return u"+".join([store.name for store in self.get_stores()])
    name = property(get_name)

    _wstore = None

    def get_wstore(self):
        u"""Retourner le store destination, c'est à dire celui dans lequel on
        ajoute les tâches par défaut. Par défaut, il s'agit du premier store
        de la liste.

        @raise IndexError: s'il n'y a aucun stores
        """
        if self._wstore is not None:
            return self._wstore
        else:
            if self._stores: return self._stores[0]
            raise IndexError("Unable to find destination store")

    def set_wstore(self, name=None):
        u"""Choisir le store destination.

        @param name: Nom du store à sélectionner, ou None pour prendre le
            premier de la liste.
        @return: self
        """
        if name is None:
            self._wstore = None
        else:
            for store in self.get_stores():
                if store.get_name() == name:
                    self._wstore = store
                    break
            else:
                raise ValueError("Invalid store: %s" % name)

    def get_stores(self, force=False):
        u"""Retourner la liste des stores gérés par ce store. Si c'est un store
        simple, la liste de contient qu'un élément.

        @param force: forcer la reconstruction de la liste. par défaut,
            utiliser une valeur mise en cache.
        @rtype: tuple
        """
        if force or self._cstores is None:
            stores = []
            for store in self._stores:
                stores.extend(store.get_stores())
            self._cstores = tuple(stores)
        return self._cstores

    def get_store_by_sid(self, sid=None):
        u"""Obtenir le store dont on donne le sid, ou None si le sid n'existe
        pas. Si sid==None, retourner le store par défaut.

        @rtype: AbstractStore
        """
        if sid is None: return self.get_store()
        sid = _u(sid)
        for store in self.get_stores():
            if _u(store.sid) == sid: return store
        return None

    def get_tasks(self):
        tasks = []
        for store in self.get_stores():
            tasks.extend(store.tasks)
        return tasks
    tasks = property(get_tasks)

    def remove(self, task):
        for store in self.get_stores():
            if store.remove(task): return True
        return False

    def load(self, infdn=None, force=False, force_reload=False, **ignored):
        if infdn is not None:
            raise ValueError("infdn is not supported for this store")
        for store in self.get_stores():
            if force_reload or store.should_reload():
                store.load(force=force)

    def should_reload(self):
        for store in self.get_stores():
            if store.should_reload(): return True
        return False

    def revert(self):
        for store in self.get_stores(): store.revert()

    def save(self, outfdn=None, force=False):
        if outfdn is not None:
            raise ValueError("outfdn is not supported for this store")
        saved = False
        for store in self.get_stores():
            if store.save(force=force):
                saved = True
        return saved
