from django.forms.fields import CharField, BooleanField
from django.forms.widgets import Textarea
from django.forms.models import ModelMultipleChoiceField
from threadedcomments.forms import ThreadedCommentForm
from xerxes.tools.forms import ContextModelForm
from xerxes.tools.widgets import DropDownMultiple
from models import Influence, Character

#
# A few comment form classes, to handle the various cases (staff/no staff,
# reply to public/private post)
# 
# It is probably possible to reduce this mess a bit using metaclasses, but I
# didn't get this to work yet.
# 
class InfluenceCommentForm(ThreadedCommentForm):
    # Force the textare to 80 columns. This is really a hack, we should
    # rather create a template tag to do this at the template level.
    comment = CharField(widget=Textarea(attrs={'cols' : 80}))
    def __init__(self, *args, **kwargs):
        super(InfluenceCommentForm, self).__init__(*args, **kwargs)

    class Meta(ThreadedCommentForm.Meta):
        exclude = ('markup', )

class AdminInfluenceCommentForm(ThreadedCommentForm):
    comment = CharField(widget=Textarea(attrs={'cols' : 80}))
    is_public = BooleanField(required=False, initial=False)
    def __init__(self, *args, **kwargs):
        super(AdminInfluenceCommentForm, self).__init__(*args, **kwargs)

    class Meta(ThreadedCommentForm.Meta):
        fields = ThreadedCommentForm.Meta.fields + ('is_public',)
        exclude = ('markup', )

class AdminPrivateInfluenceCommentForm(ThreadedCommentForm):
    comment = CharField(widget=Textarea(attrs={'cols' : 80}))
    def __init__(self, *args, **kwargs):
        super(AdminPrivateInfluenceCommentForm, self).__init__(*args, **kwargs)
        self.instance.is_public = False

    class Meta(ThreadedCommentForm.Meta):
        exclude = ('markup', )

def get_influence_comment_form(is_staff, reply_to):
    """ Gets the form class that a user can use to reply to the given comment.
    reply_to can be None, in which case the form class for a new comment is
    returned. """
    allow_markup = False
    allow_private = is_staff
    if reply_to:
        allow_public = reply_to.is_public
    else:
        allow_public = True
    return _get_influence_comment_form(allow_markup, allow_public, allow_private)
    
def _get_influence_comment_form(allow_markup, allow_public, allow_private):
    """ Internal wrapper that selects the right form class depending on the
    given options. Should not be called directly, call
    get_influence_comment_form instead. """
    if not allow_markup and allow_public and allow_private:
        return AdminInfluenceCommentForm
    elif not allow_markup and not allow_public and allow_private:
        return AdminPrivateInfluenceCommentForm
    elif not allow_markup and allow_public and not allow_private:
        return InfluenceCommentForm
    else:
        raise Exception("Unsupported configuration")

class InfluenceForm(ContextModelForm):
    # Manually define this field so we can select the DropDownMultiple
    # widget. However, we leave the queryset empty, which characters can
    # be selected depends on the logged in user and should be set by
    # setting the choices property in the view.
    other_characters = ModelMultipleChoiceField(queryset=Character.objects.none(), widget=DropDownMultiple)
    class Meta:
        model = Influence
        fields = ('initiator', 'summary', 'other_characters', 'other_contacts', 'description')

class CharacterForm(ContextModelForm):
    class Meta:
        model = Character
        fields = ('name', 'type')

