from rest_framework import serializers

from adhocracy4.dashboard import components
from adhocracy4.dashboard import signals as a4dashboard_signals
from adhocracy4.rules.discovery import NormalUser

from . import models


class ChoiceSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)

    count = serializers.SerializerMethodField()

    class Meta:
        model = models.Choice
        fields = ('id', 'label', 'count')

    def get_count(self, choice):
        if hasattr(choice, 'vote_count'):
            return getattr(choice, 'vote_count', -1)
        else:
            return choice.votes.all().count()


class QuestionSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    choices = ChoiceSerializer(many=True)

    authenticated = serializers.SerializerMethodField()
    isReadOnly = serializers.SerializerMethodField('get_is_read_only')
    userChoices = serializers.SerializerMethodField('get_user_choices')
    totalVoteCount = serializers.SerializerMethodField('get_total_vote_count')

    class Meta:
        model = models.Question
        fields = ('id', 'label', 'choices', 'multiple_choice',
                  'isReadOnly', 'authenticated', 'userChoices',
                  'totalVoteCount')

    def get_authenticated(self, _):
        if 'request' in self.context:
            user = self.context['request'].user
            return bool(user.is_authenticated)
        return False

    def get_is_read_only(self, question):
        if 'request' in self.context:
            user = self.context['request'].user
            has_poll_permission = user.has_perm(
                'a4polls.add_vote',
                question.poll.module
            )
            would_have_poll_permission = NormalUser().would_have_perm(
                'a4polls.add_vote',
                question.poll.module
            )
            return not has_poll_permission and not would_have_poll_permission

        return True

    def get_user_choices(self, question):
        if 'request' in self.context:
            user = self.context['request'].user
            return question.user_choices_list(user)
        return []

    def get_total_vote_count(self, question):
        return getattr(question, 'vote_count', -1)


class PollSerializer(serializers.ModelSerializer):
    questions = QuestionSerializer(many=True)

    class Meta:
        model = models.Poll
        fields = ('id', 'questions')

    def update(self, instance, data):
        # Delete removed questions from the database
        instance.questions.exclude(
            id__in=[question['id']
                    for question in data['questions']
                    if 'id' in question
                    ]).delete()

        # Update (or create) the questions
        for weight, question in enumerate(data['questions']):
            question_id = question.get('id')
            question_instance, _ = models.Question.objects.update_or_create(
                id=question_id,
                defaults={
                    'poll': instance,
                    'label': question['label'],
                    'multiple_choice': question['multiple_choice'],
                    'weight': weight
                })

            self._update_choices(question, question_instance)

        # Send the component updated signal
        # (the serializer is only used from within the dashboard)
        self._send_component_updated_signal(instance)

        return instance

    def _update_choices(self, question, question_instance):
        # Delete removed choices from the database
        choice_ids = [choice['id']
                      for choice in question['choices']
                      if 'id' in choice]
        question_instance.choices.exclude(id__in=choice_ids).delete()

        # Update (or create) this questions choices
        for choice in question['choices']:
            choice_id = choice.get('id')
            choice_instance, _ = models.Choice.objects.update_or_create(
                id=choice_id,
                defaults={
                    'question': question_instance,
                    'label': choice['label']
                }
            )

    def _send_component_updated_signal(self, question_instance):
        component = components.modules['polls']
        a4dashboard_signals.module_component_updated.send(
            sender=component.__class__,
            module=question_instance.module,
            component=component.__class__,
            user=self.context['request'].user
        )

@@ -450,24 +450,43 @@
 el', 'count'
+, 'is_other_choice'
 )%0A%0A    def g
@@ -1087,24 +1087,215 @@
 vote_count')
+%0A    totalVoteCountMulti = serializers.SerializerMethodField(%0A        'get_total_vote_count_multi')%0A    totalAnswerCount = serializers.SerializerMethodField(%0A        'get_total_answer_count')
 %0A%0A    class 
@@ -1364,16 +1364,29 @@
 'label',
+ 'help_text',
  'choice
@@ -1425,16 +1425,27 @@
         
+ 'is_open',
  'isRead
@@ -1513,24 +1513,67 @@
 alVoteCount'
+, 'totalVoteCountMulti', 'totalAnswerCount'
 )%0A%0A    def g
@@ -2491,80 +2491,484 @@
 get_
-total_vote_count(self, question):%0A        return getattr(question, 'vote
+user_answer(self, question):%0A        if 'request' in self.context:%0A            user = self.context%5B'request'%5D.user%0A            return question.user_answer(user)%0A        return %5B%5D%0A%0A    def get_total_vote_count(self, question):%0A        return getattr(question, 'vote_count', -1)%0A%0A    def get_total_vote_count_multi(self, question):%0A        return getattr(question, 'vote_count_multi', -1)%0A%0A    def get_total_answer_count(self, question):%0A        return getattr(question, 'answer
 _cou
@@ -3815,24 +3815,80 @@
 n%5B'label'%5D,%0A
+                    'help_text': question%5B'help_text'%5D,%0A
             
@@ -3939,24 +3939,76 @@
 e_choice'%5D,%0A
+                    'is_open': question%5B'is_open'%5D,%0A
             
@@ -4051,17 +4051,60 @@
      %7D)%0A
-%0A
+            if not question%5B'is_open'%5D:%0A    
         
@@ -5023,16 +5023,82 @@
 'label'%5D
+,%0A                    'is_other_choice': choice%5B'is_other_choice'%5D
 %0A       

add new freetext fields to serializers