from datetime import datetime
from functools import wraps
from socket import getfqdn
import itertools
import random
import re
import string

from autozygosity import app
import models

from flask import render_template, abort, request, session
from werkzeug.routing import BaseConverter


class TokenConverter(BaseConverter):
	""" Custom Flask converter for token ID """
	def __init__(self, url_map, *items):
		super(TokenConverter, self).__init__(url_map)
		self.regex = app.config['TOKEN_REGEX']

app.url_map.converters['token'] = TokenConverter


def validate_token(function):
	""" Decorator that checks if given token exists in database """

	# wraps solved a silly/bizzare problem where function.__name__
	# would always return the last decorated method in this file.
	# Still don't understand why that should be the case. Need to
	# read more
	# http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
	# http://www.artima.com/weblogs/viewpost.jsp?thread=240808
	@wraps(function)
	def validate_token_decorator(*args, **kwargs):

		# Token either comes from URI or POST variable.
		# Barf if neither.
		token = None
		if 'token' in kwargs:
			token = kwargs['token']
		elif 'token' in request.form:
			token = request.form['token']
		else:
			abort(500)

		# Check if valid token
		try:
			models.job.objects(token__contains = token.lower())[0]
		except IndexError, e:
			abort(404)
		else:
			return function(*args, **kwargs)

	return validate_token_decorator


def validate_download(function):
	""" Decorator that checks if a submission's files are
		available for download. Throws a 404 if the submission
		is completed but file is unavailable for whatever reason.
		Shows appropriate pages for 'completed' and 'failed'
		statuses, and "results not ready" for all others.
	"""	

	@wraps(function)
	def validate_download_decorator(*args, **kwargs):
		submission = models.job.objects(token__contains = kwargs['token'].lower())[0]

		try:
			function(*args, **kwargs)
		except Exception, e:
			print str(e)
			if submission.status == 'completed':
				abort(404)
			elif submission.status == 'failed':
				return render_template('token.html', submission=submission)
			else:
				return render_template('errors/unavailable.html', token=submission.token)
		else:
			return function(*args, **kwargs)

	return validate_download_decorator


def jinja_method_explain_submission(submission):
	""" Jinja2 method to determine whether or not to show submission explanation.
		Aimed at first-time visitors. Assume first-time visitor if the 
		'explain_submission' cookie's not set. Don't explain completed or failed
		submissions.
	"""
	if submission.status == 'completed' or submission.status == 'failed':
		return False

	try:
		return session['explain_submission']
	except Exception, e:
		return True


def jinja_method_get_hostname():
	""" Jinja2 method to get the hostname """
	return request.host_url


# http://code.activestate.com/recipes/577081-humanized-representation-of-a-number-of-bytes/
def jinja_method_max_upload_size(bytes = app.config['UPLOADED_VCF_MAX_SIZE'], precision=0):
	""" Return a humanized string representation of a number of bytes. """
	abbrevs = (
		(1<<50L, 'PB'),
		(1<<40L, 'TB'),
		(1<<30L, 'GB'),
		(1<<20L, 'MB'),
		(1<<10L, 'kB'),
		(1, 'bytes')
	)
	if bytes == 1:
		return '1 byte'
	for factor, suffix in abbrevs:
		if bytes >= factor: