from collections import defaultdict
import random
import abc
from proso_flashcards.models import Flashcard, FlashcardAnswer
from proso.django.config import instantiate_from_config


def get_option_set():
    return instantiate_from_config(
        'proso_flashcards', 'option_set',
        default_class='proso_flashcards.flashcard_construction.ContextOptionSet'
    )


def get_direction():
    return instantiate_from_config(
        'proso_flashcards', 'direction',
        default_class='proso_flashcards.flashcard_construction.RandomDirection'
    )


class OptionSet():
    def __init__(self, **kwargs):
        pass

    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def get_option_for_flashcards(self, flashcards):
        pass


class EmptyOptionSet(OptionSet):
    def get_option_for_flashcards(self, flashcards):
        return dict(map(lambda fc: (fc.item_id, []), flashcards))


class ContextOptionSet(OptionSet):
    def get_option_for_flashcards(self, flashcards):
        contexts = set()
        for flashcard in flashcards:
            contexts.add(flashcard.context_id)

        option_sets = defaultdict(set)
        for context, item in Flashcard.objects.filter(context_id__in=contexts).values_list("context", "item_id"):
            option_sets[context].add(item)

        return dict(map(lambda fc: (fc.item_id, list(option_sets[fc.context_id])), flashcards))


class Direction():
    def __init__(self, **kwargs):
        pass

    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def get_direction(self, flashcard):
        pass


class RandomDirection(Direction):
    def get_direction(self, flashcard):
        return random.choice([FlashcardAnswer.FROM_DESCRIPTION, FlashcardAnswer.FROM_TERM])


class OnlyFromTermDirection(Direction):
    def get_direction(self, flashcard):
        return FlashcardAnswer.FROM_TERM


class OnlyFromDescriptionDirection(Direction):
    def get_direction(self, flashcard):
        return FlashcardAnswer.FROM_DESCRIPTION

@@ -1009,16 +1009,38 @@
 = set()%0A
+        types = set()%0A
         
@@ -1115,16 +1115,184 @@
 ext_id)%0A
+            types.add(flashcard.term.type)%0A%0A        options_filter = %7B'context_id__in': contexts%7D%0A        if types:%0A            options_filter%5B'term__type__in'%5D = types
 %0A       
@@ -1343,16 +1343,27 @@
 context,
+ term_type,
  item in
@@ -1392,31 +1392,24 @@
 ter(
-context_id__in=contexts
+**options_filter
 ).va
@@ -1428,16 +1428,30 @@
 ontext%22,
+ %22term__type%22,
  %22item_i
@@ -1486,16 +1486,27 @@
 %5Bcontext
+, term_type
 %5D.add(it
@@ -1588,16 +1588,30 @@
 ntext_id
+, fc.term.type
 %5D)), fla

handle also type of terms in context option set