# Copyright The IETF Trust 2007, All Rights Reserved
from django.conf import settings
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden, HttpResponseNotAllowed
from django.shortcuts import get_object_or_404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.core.exceptions import ObjectDoesNotExist

from ietf.submit.models import IdSubmissionDetail, IdApprovedDetail
from ietf.submit.forms import UploadForm, AutoPostForm, MetaDataForm
from ietf.submit.utils import (DraftValidation, perform_post, remove_docs,
                               get_person_for_user, is_secretariat,
                               request_full_url, UPLOADED,
                               WAITING_AUTHENTICATION, CANCELED,
                               INITIAL_VERSION_APPROVAL_REQUESTED,
                               MANUAL_POST_REQUESTED, POSTED)
from ietf.utils.mail import send_mail


def submit_index(request):
    if request.method == 'POST':
        try:
            form = UploadForm(request=request, data=request.POST, files=request.FILES)
            if form.is_valid():
                submit = form.save()
                return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id, 'submission_hash': submit.get_hash()}))
        except IOError, e:
            if "Client read error" in str(e): # The server got an IOError when trying to read POST data
                form = UploadForm(request=request)
                form._errors = {}
                form._errors["__all__"] = form.error_class(["There was a failure receiving the complete form data -- please try again."])
            else:
                raise
    else:
        form = UploadForm(request=request)
    return render_to_response('submit/submit_index.html',
                              {'selected': 'index',
                               'form': form},
                              context_instance=RequestContext(request))


def submit_status(request):
    error = None
    filename = None
    if request.method == 'POST':
        filename = request.POST.get('filename', '')
        detail = IdSubmissionDetail.objects.filter(filename=filename).order_by('-pk')
        if detail:
            return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail[0].submission_id}))
        error = 'No valid history found for %s' % filename
    return render_to_response('submit/submit_status.html',
                              {'selected': 'status',
                               'error': error,
                               'filename': filename},
                              context_instance=RequestContext(request))


def _can_approve(user, detail):
    person = get_person_for_user(user)
    if detail.status_id != INITIAL_VERSION_APPROVAL_REQUESTED or not detail.group_acronym:
        return None
    if person in [i.person for i in detail.group_acronym.wgchair_set.all()] or is_secretariat(user):
        return True
    return False


def _can_force_post(user, detail):
    if detail.status_id not in [MANUAL_POST_REQUESTED,
            WAITING_AUTHENTICATION, INITIAL_VERSION_APPROVAL_REQUESTED]:
        return None
    if is_secretariat(user):
        return True
    return False

def _can_cancel(user, detail, submission_hash):
    if detail.status_id in [CANCELED, POSTED]:
        return None
    if is_secretariat(user):
        return True
    if submission_hash and detail.get_hash() == submission_hash:
        return True
    return False

def _can_edit(user, detail, submission_hash):
    if detail.status_id != UPLOADED:
        return None
    if is_secretariat(user):
        return True
    if submission_hash and detail.get_hash() == submission_hash:
        return True
    return False

def draft_status(request, submission_id, submission_hash=None, message=None):
    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
    if submission_hash and not detail.get_hash() == submission_hash:
        raise Http404
    validation = DraftValidation(detail)
    is_valid = validation.is_valid()
    status = None
    allow_edit = _can_edit(request.user, detail, submission_hash)
    can_force_post = _can_force_post(request.user, detail)
    can_approve = _can_approve(request.user, detail)
    can_cancel = _can_cancel(request.user, detail, submission_hash)
    if detail.status_id != UPLOADED:
        if detail.status_id == CANCELED:
            message = ('error', 'This submission has been canceled, modification is no longer possible')
        status = detail.status
        allow_edit = None

    if request.method == 'POST' and allow_edit:
        if request.POST.get('autopost', False):
            auto_post_form = AutoPostForm(draft=detail, validation=validation, data=request.POST)
            if auto_post_form.is_valid():
                try:
                    approved_detail = IdApprovedDetail.objects.get(filename=detail.filename)
                except ObjectDoesNotExist:
                    approved_detail = None
                if detail.group_acronym and not approved_detail:
                    detail.status_id = INITIAL_VERSION_APPROVAL_REQUESTED
                    detail.save()
                else:
                    approved_detail = True

                if detail.revision == '00' and not approved_detail:
                    submitter = auto_post_form.save_submitter_info()
                    subject = 'New draft waiting for approval: %s' % detail.filename
                    from_email = settings.IDSUBMIT_FROM_EMAIL
                    to_email = []
                    if detail.group_acronym:
                        to_email += [i.person.email()[1] for i in detail.group_acronym.wgchair_set.all()]
                    to_email = list(set(to_email))
                    if to_email:
                        authors = detail.tempidauthors_set.exclude(author_order=0).order_by('author_order')
                        send_mail(request, to_email, from_email, subject, 'submit/submission_approval.txt',
                                  {'submitter': submitter, 'authors': authors,
                                   'draft': detail, 'domain': Site.objects.get_current().domain})
                    return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id}))
                else:
                    auto_post_form.save(request)
                    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
                    validation = DraftValidation(detail)
                    is_valid = validation.is_valid()
                    status = detail.status
                    can_force_post = _can_force_post(request.user, detail)
                    can_approve = _can_approve(request.user, detail)
                    can_cancel = _can_cancel(request.user, detail, submission_hash)
                    allow_edit = None
                    message = ('success', 'Your submission is pending email authentication. An email has been sent you with instructions.')
        else:
            submission_hash = detail.get_hash()
            if submission_hash:
                return HttpResponseRedirect(reverse('draft_edit_by_hash', None, kwargs={'submission_id': detail.submission_id, 'submission_hash': submission_hash}))
            else:
                return HttpResponseRedirect(reverse(draft_edit, None, kwargs={'submission_id': detail.submission_id }))
    else:
        auto_post_form = AutoPostForm(draft=detail, validation=validation)

    show_notify_button = False
    if allow_edit == False or can_cancel == False:
        show_notify_button = True
    if submission_hash is None and is_secretariat(request.user):
        submission_hash = detail.get_hash() # we'll need this when rendering the cancel button in the form
    return render_to_response('submit/draft_status.html',
                              {'selected': 'status',
                               'detail': detail,
                               'validation': validation,
                               'auto_post_form': auto_post_form,
                               'is_valid': is_valid,
                               'status': status,
                               'message': message,
                               'allow_edit': allow_edit,
                               'can_force_post': can_force_post,
                               'can_approve': can_approve,
                               'can_cancel': can_cancel,
                               'submission_hash': submission_hash,
                               'show_notify_button': show_notify_button,
                              },
                              context_instance=RequestContext(request))


def draft_cancel(request, submission_id, submission_hash=None):
    if request.method!='POST':
        return HttpResponseNotAllowed(['POST'])
    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
    can_cancel = _can_cancel(request.user, detail, submission_hash)
    if not can_cancel:
        if can_cancel == None:
            raise Http404
        return HttpResponseForbidden('You have no permission to perform this action')
    detail.status_id = CANCELED
    detail.save()
    remove_docs(detail)
    return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id}))


def draft_edit(request, submission_id, submission_hash=None):
    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
    can_edit = _can_edit(request.user, detail, submission_hash)
    if not can_edit:
        if can_edit == None:
            raise Http404
        return HttpResponseForbidden('You have no permission to perform this action')
    validation = DraftValidation(detail)
    validation.validate_wg()
    if request.method == 'POST':
        form = MetaDataForm(draft=detail, validation=validation, data=request.POST)
        if form.is_valid():
            form.save(request)
            return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id}))
    else:
        form = MetaDataForm(draft=detail, validation=validation)
    return render_to_response('submit/draft_edit.html',
                              {'selected': 'status',
                               'detail': detail,
                               'validation': validation,
                               'form': form,
                               'settings': settings
                              },
                              context_instance=RequestContext(request))


def draft_confirm(request, submission_id, auth_key):
    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
    message = None
    if auth_key != detail.auth_key:
        message = ('error', 'Incorrect authorization key')
    elif detail.status_id != WAITING_AUTHENTICATION:
        message = ('error', 'The submission can not be autoposted because it is in state: %s' % detail.status.status_value)
    else:
        if request.method=='POST':
            message = ('success', 'Authorization key accepted. Auto-Post complete')
            perform_post(request, detail)
        else:
            return render_to_response('submit/last_confirmation_step.html',
                               {'detail': detail, },
                               context_instance=RequestContext(request))
    return draft_status(request, submission_id, message=message)


def draft_approve(request, submission_id, check_function=_can_approve):
    if request.method!='POST':
        return HttpResponseNotAllowed(['POST'])
    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
    can_perform = check_function(request.user, detail)
    if not can_perform:
        if can_perform == None:
            raise Http404
        return HttpResponseForbidden('You have no permission to perform this action')
    perform_post(request, detail)
    return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id}))


def draft_force(request, submission_id):
    if request.method!='POST':
        return HttpResponseNotAllowed(['POST'])
    return draft_approve(request, submission_id, check_function=_can_force_post)


def full_url_request(request, submission_id):
    if request.method!='POST':
        return HttpResponseNotAllowed(['POST'])
    detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
    request_full_url(request, detail)
    message = ('success', 'An email has been sent to draft authors to inform them of the full access url')
    return draft_status(request, submission_id, message=message)
