import hotshot
import time
import os
import datetime
import functools
import inspect
import logging
from django.conf import settings
from django.core import exceptions as django_exceptions
from django.core.urlresolvers import reverse
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse, HttpResponseForbidden, Http404
from django.http import HttpResponseRedirect
from django.utils import simplejson
from django.utils.translation import ugettext as _
from django.utils.encoding import smart_str
from askbot import exceptions as askbot_exceptions
from askbot.conf import settings as askbot_settings
from askbot.utils import url_utils
from askbot.utils.html import site_url
from askbot import get_version

def auto_now_timestamp(func):
    """decorator that will automatically set
    argument named timestamp to the "now" value if timestamp == None

    if there is no timestamp argument, then exception is raised
    """
    @functools.wraps(func)
    def decorated_func(*arg, **kwarg):
        timestamp = kwarg.get('timestamp', None)
        if timestamp is None:
            kwarg['timestamp'] = datetime.datetime.now()
        return func(*arg, **kwarg)
    return decorated_func


def ajax_login_required(view_func):
    @functools.wraps(view_func)
    def wrap(request, *args, **kwargs):
        if request.user.is_authenticated():
            return view_func(request, *args, **kwargs)
        else:
            json = simplejson.dumps({'login_required':True})
            return HttpResponseForbidden(json, mimetype='application/json')
    return wrap


def anonymous_forbidden(view_func):
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if request.user.is_anonymous():
            raise askbot_exceptions.LoginRequired()
        return view_func(request, *args, **kwargs)
    return wrapper


def get_only(view_func):
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if request.method != 'GET':
            raise django_exceptions.PermissionDenied(
                'request method %s is not supported for this function' % \
                request.method
            )
        return view_func(request, *args, **kwargs)
    return wrapper


def post_only(view_func):
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if request.method != 'POST':
            raise django_exceptions.PermissionDenied(
                'request method %s is not supported for this function' % \
                request.method
            )
        return view_func(request, *args, **kwargs)
    return wrapper

def ajax_only(view_func):
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        if not request.is_ajax():
            raise Http404
        try:
            data = view_func(request, *args, **kwargs)
            if data is None:
                data = {}
        except Exception, e:
            #todo: also check field called "message"
            if hasattr(e, 'messages'):
                if len(e.messages) > 1:
                    message = u'<ul>' + \
                        u''.join( 
                            map(lambda v: u'<li>%s</li>' % v, e.messages)
                        ) + \
                        u'</ul>'
                else:
                    message = e.messages[0]
            else:
                message = unicode(e)
            if message == '':
                message = _('Oops, apologies - there was some error')
            logging.debug(message)
            data = {
                'message': message,
                'success': 0
            }
            return HttpResponse(simplejson.dumps(data), mimetype='application/json')

        if isinstance(data, HttpResponse):#is this used?
            data.mimetype = 'application/json'
            return data
        else:
            data['success'] = 1
            json = simplejson.dumps(data)
            return HttpResponse(json, mimetype='application/json')
    return wrapper

def check_authorization_to_post(func_or_message):

    message = _('Please login to post')
    if not inspect.isfunction(func_or_message):
        message = unicode(func_or_message)

    def decorator(view_func):
        @functools.wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if request.user.is_anonymous():
                #todo: expand for handling ajax responses
                if askbot_settings.ALLOW_POSTING_BEFORE_LOGGING_IN == False:
                    request.user.message_set.create(message = message)
                    params = 'next=%s' % request.path
                    return HttpResponseRedirect(url_utils.get_login_url() + '?' + params)
            return view_func(request, *args, **kwargs)
        return wrapper

    if inspect.isfunction(func_or_message):
        return decorator(func_or_message)
    else:
        return decorator

try:
    PROFILE_LOG_BASE = settings.PROFILE_LOG_BASE
except:
    PROFILE_LOG_BASE = "/tmp"

def profile(log_file):
    """Profile some callable.

    This decorator uses the hotshot profiler to profile some callable (like
    a view function or method) and dumps the profile data somewhere sensible
    for later processing and examination.

    It takes one argument, the profile log name. If it's a relative path, it
    places it under the PROFILE_LOG_BASE. It also inserts a time stamp into the 
    file name, such that 'my_view.prof' become 'my_view-20100211T170321.prof', 
    where the time stamp is in UTC. This makes it easy to run and compare 
    multiple trials.     

    http://code.djangoproject.com/wiki/ProfilingDjango
    """

    if not os.path.isabs(log_file):
        log_file = os.path.join(PROFILE_LOG_BASE, log_file)

    def _outer(f):
        def _inner(*args, **kwargs):
            # Add a timestamp to the profile output when the callable
            # is actually called.
            (base, ext) = os.path.splitext(log_file)
            base = base + "-" + time.strftime("%Y%m%dT%H%M%S", time.gmtime())
            final_log_file = base + ext

            prof = hotshot.Profile(final_log_file)
            try:
                ret = prof.runcall(f, *args, **kwargs)
            finally:
                prof.close()
            return ret

        return _inner
    return _outer

def check_spam(field):
    '''Decorator to check if there is spam in the form'''

    def decorator(view_func):
        @functools.wraps(view_func)
        def wrapper(request, *args, **kwargs):

            if askbot_settings.USE_AKISMET and askbot_settings.AKISMET_API_KEY == "":
                raise ImproperlyConfigured('You have not set AKISMET_API_KEY')

            if askbot_settings.USE_AKISMET and request.method == "POST":
                comment = smart_str(request.POST[field])
                data = {'user_ip': request.META["REMOTE_ADDR"],
                        'user_agent': request.environ['HTTP_USER_AGENT'],
                        'comment_author': smart_str(request.user.username),
                        }
                if request.user.is_authenticated():
                    data.update({'comment_author_email': request.user.email})

                from akismet import Akismet
                api = Akismet(
                    askbot_settings.AKISMET_API_KEY, 
                    smart_str(site_url(reverse('questions'))), 
                    "Askbot/%s" % get_version()
                )

                if api.comment_check(comment, data, build_data=False):
                    logging.debug(
                        'Spam detected in %s post at: %s',
                        request.user.username,
                        datetime.datetime.now()
                    )
                    spam_message = _(
                        'Spam was detected on your post, sorry '
                        'for if this is a mistake'
                    )
                    if request.is_ajax():
                        return HttpResponseForbidden(
                                spam_message, 
                                mimetype="application/json"
                            )
                    else:
                        request.user.message_set.create(message=spam_message)
                        return HttpResponseRedirect(reverse('index'))

            return view_func(request, *args, **kwargs)
        return wrapper

    return decorator

def admins_only(view_func):
    @functools.wraps(view_func)
    def decorator(request, *args, **kwargs):
        if request.user.is_anonymous():
            raise django_exceptions.PermissionDenied()
        if not request.user.is_administrator_or_moderator():
            raise django_exceptions.PermissionDenied(
            _('This function is limited to moderators and administrators')
        )
        return view_func(request, *args, **kwargs)
    return decorator

