# Copyright (C) 2010-2014 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging

from urllib import quote

from django.shortcuts import get_object_or_404
from django.contrib import messages
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from astakos.im import transaction
from django.db.models import Q
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import redirect
from django.utils.translation import ugettext as _
from django.core.exceptions import PermissionDenied
from django.views.decorators.http import require_http_methods
from django.utils import simplejson as json
from django.template import RequestContext

from synnefo_branding import utils as branding
from synnefo_branding import settings as branding_settings

import astakos.im.messages as astakos_messages

from astakos.im import activation_backends, user_logic
from astakos.im.models import AstakosUser, ApprovalTerms, EmailChange, \
    AstakosUserAuthProvider, PendingThirdPartyUser, Component, Project
from astakos.im.util import get_context, prepare_response, get_query, \
    restrict_next
from astakos.im.forms import LoginForm, InvitationForm, FeedbackForm, \
    SignApprovalTermsForm, EmailChangeForm
from astakos.im.forms import ExtendedProfileForm as ProfileForm
from synnefo.lib.services import get_public_endpoint
from astakos.im.user_utils import send_feedback, logout as auth_logout, \
    invite as invite_func
from astakos.im import settings
from astakos.im import presentation
from astakos.im import auth_providers as auth
from astakos.im import quotas
from astakos.im.views.util import render_response, _resources_catalog
from astakos.im.views.decorators import cookie_fix, signed_terms_required,\
    required_auth_methods_assigned, valid_astakos_user_required, login_required
from astakos.api import projects as projects_api
from astakos.api.util import _dthandler

logger = logging.getLogger(__name__)


@require_http_methods(["GET", "POST"])
@cookie_fix
@signed_terms_required
def login(request, template_name='im/login.html', extra_context=None):
    """
    Renders login page.

    **Arguments**

    ``template_name``
        A custom login template to use. This is optional; if not specified,
        this will default to ``im/login.html``.

    ``extra_context``
        An dictionary of variables to add to the template context.
    """

    extra_context = extra_context or {}

    third_party_token = request.GET.get('key', False)
    if third_party_token:
        messages.info(request, astakos_messages.AUTH_PROVIDER_LOGIN_TO_ADD)

    if request.user.is_authenticated():
        return HttpResponseRedirect(reverse('landing'))

    return render_response(
        template_name,
        login_form=LoginForm(request=request),
        context_instance=get_context(request, extra_context)
    )


@require_http_methods(["GET", "POST"])
@cookie_fix
@signed_terms_required
def index(request, authenticated_redirect='landing',
          anonymous_redirect='login', extra_context=None):
    """
    If user is authenticated redirect to ``authenticated_redirect`` url.
    Otherwise redirects to ``anonymous_redirect`` url.

    """
    if request.user.is_authenticated():
        return HttpResponseRedirect(reverse(authenticated_redirect))
    return HttpResponseRedirect(reverse(anonymous_redirect))


@require_http_methods(["POST"])
@cookie_fix
@valid_astakos_user_required
@transaction.commit_on_success
def update_token(request):
    """
    Update api token view.
    """
    user = AstakosUser.objects.select_for_update().get(id=request.user.id)
    user.renew_token()
    user.save()
    messages.success(request, astakos_messages.TOKEN_UPDATED)
    return HttpResponseRedirect(reverse('api_access'))


@require_http_methods(["GET", "POST"])
@cookie_fix
@valid_astakos_user_required
@transaction.commit_on_success
def invite(request, template_name='im/invitations.html', extra_context=None):
    """
    Allows a user to invite somebody else.

    In case of GET request renders a form for providing the invitee
    information.
    In case of POST checks whether the user has not run out of invitations and
    then sends an invitation email to singup to the service.

    The number of the user invitations is going to be updated only if the email
    has been successfully sent.

    If the user isn't logged in, redirects to settings.LOGIN_URL.

    **Arguments**

    ``template_name``
        A custom template to use. This is optional; if not specified,
        this will default to ``im/invitations.html``.

    ``extra_context``
        An dictionary of variables to add to the template context.

    **Template:**

    im/invitations.html or ``template_name`` keyword argument.

    **Settings:**

    The view expectes the following settings are defined:

    * LOGIN_URL: login uri
    """
    extra_context = extra_context or {}
    status = None
    message = None
    form = InvitationForm()

    inviter = request.user
    if request.method == 'POST':
        form = InvitationForm(request.POST)
        if inviter.invitations > 0:
            if form.is_valid():
                email = form.cleaned_data.get('username')
                realname = form.cleaned_data.get('realname')
                invite_func(inviter, email, realname)
                message = _(astakos_messages.INVITATION_SENT) % locals()
                messages.success(request, message)
        else:
            message = _(astakos_messages.MAX_INVITATION_NUMBER_REACHED)
            messages.error(request, message)

    sent = [{'email': inv.username,
             'realname': inv.realname,
             'is_consumed': inv.is_consumed}
            for inv in request.user.invitations_sent.all()]
    kwargs = {'inviter': inviter,
              'sent': sent}
    context = get_cont
ext(request, extra_context, **kwargs)
 
   return render_response(template_name,
                           invitation_form=form,
                           context_instance=context)


@require_http_methods(["GET", "POST"])
@required_auth_methods_assigned()
@login_required
@cookie_fix
@signed_terms_required
def api_access_config(request, template_name='im/api_access_config.html',
                      content_type='text/plain', extra_context=None,
                      filename='.kamakirc'):

    if settings.KAMAKI_CONFIG_CLOUD_NAME:
        cloud_name = settings.KAMAKI_CONFIG_CLOUD_NAME
    else:
        cloud_name = branding_settings.SERVICE_NAME.replace(' ', '_').lower()

    url = get_public_endpoint(settings.astakos_services, 'identity')

    context = {
        'user': request.user,
        'services': Component.catalog(),
        'token_url': url,
        'cloud_name': cloud_name
    }

    extra_context = extra_context or {}
    context.update(extra_context)
    content = branding.render_to_string(template_name, context,
                                        RequestContext(request))
    response = HttpResponse(content_type=content_type)
    response.status_code = 200
    response['Content-Disposition'] = 'attachment; filename="%s"' % filename
    response.content = content
    return response


@required_auth_methods_assigned()
@login_required
@cookie_fix
@signed_terms_required
def api_access(request, template_name='im/api_access.html',
               extra_context=None):
    """
    API access view.
    """
    context = {}

    url = get_public_endpoint(settings.astakos_services, 'identity')
    context['services'] = Component.catalog()
    context['token_url'] = url
 