#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
# import optparse
import os
import pg
# import types
import urllib
import urlparse
import datetime
# import re
# import json
# import time
# import urllib2
# import itertools
# import cPickle as pickle
# import zlib
import PIL
import itertools


class Error(Exception):
	pass
	
	
class Database:

	def __init__(self, p):
		self.conn = None
		if type(p) is type(''):
			self.params = self.parseConnectionString(p)
		else:
			self.params = p
		
	def connect(self):
		self.conn = pg.connect(self.params[2], host=self.params[0], port=self.params[1], user=self.params[3], passwd=self.params[4])
	
	def query(self, sql):
		return self.conn.query(sql).dictresult()
		
	def parseConnectionString(self, string):
		name = None
		user = 'pianos'
		password = 'pianos'
		hostname = 'localhost'
		port = 5432
		
		expectedScheme = 'pgsql'
		expectedFullScheme = expectedScheme + '://'
		
		if string[:len(expectedFullScheme)] != expectedFullScheme:
			url = expectedFullScheme + string
		else:
			url = string
			
		res = urlparse.urlsplit(url)
		if res.scheme != expectedScheme:
			raise ValueError("Invalid PostgreSQL url scheme in '%s'" % string)
			
		# Since urlparse does not recognize pgsql:// as a valid scheme, it will not parse correctly
		# the hostname:port/path?foo=bar#baz part. We thus replace pgsql:// by http:// to get the
		# correct parsed values.
		url = 'http' + url[len(res.scheme):]
		res = urlparse.urlsplit(url)
		if len(res.path):
			name = urllib.unquote(res.path.strip().strip('/'))
		if res.username: 
			user = res.username
		if res.password: 
			password = res.password
		if res.hostname: 
			hostname = res.hostname
		if res.port:
			port = int(res.port)
		
		if name is None or user is None or password is None or hostname is None or port is None:
			raise ValueError("Invalid PostgreSQL url: %s" % string)
			
		return hostname,port,name,user,password,'pgsql://'+user+'@'+hostname+':'+str(port)+'/'+name

class sqlverbatim:
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return str(self.value)

def sqlarg(args):
	all = []
	for a in args:
		if type(a) is types.InstanceType:
			t = 'verbatim'
		else:
			if a is None:
				t = 'null'
			elif type(a) is types.StringType:
				t = 'string'
			elif type(a) is types.BooleanType:
				t = 'bool'
			else:
				t = 'verbatim'
			
		if t == 'null':
			v = 'NULL'
		elif t == 'string':
			v = "E'"+pg.escape_string(a)+"'"
		elif t == 'bool':
			v = 'true' if a else 'false'
		else:
			v = str(a)

		all.append(v)
		
	return ','.join(all)


def sanitizefn(filename):
	return ''.join([x if x.isalnum() or x in ('_','-') else '$' for x in filename])
	
class Application:

	def __init__(self, dumpdir=None, cache=None):
		def initpath(path):
			if path is not None:
				res = os.path.realpath(path)
				if res and not os.path.isdir(res):
					os.makedirs(res)
				return res
			else:
				return None
		self.dumpdir = initpath(dumpdir)
		self.cache = initpath(cache)

	def run(self):
		raise Error("Pure virtual function call")
	
	def collectAssignments(self, username=None, exname=None, limit=None):
		sql = '''SELECT assignment.id,
			object.createdon,
			getAssignmentStatus(assignment.id) AS status,
			person.id AS userid,person.username AS username,
			exercise.id AS exid,exercise.name AS exname
		FROM assignment
		JOIN object ON assignment.id = object.id 
		JOIN person ON object.creator = person.id
		JOIN exercise ON exercise.id = assignment.exercise
		WHERE assignment.ispreview IS false
		'''
		filters = []
		if username:
			sql += " AND person.username SIMILAR TO E'"+pg.escape_string(username)+"'"
			filters.append(('user',username))
		if exname:
			sql += " AND exercise.name SIMILAR TO E'"+pg.escape_string(exname)+"'"
			filters.append(('exercise',exname))
		
		sql += " ORDER BY exid,userid,createdon DESC"

		if len(filters):
			print "Searching in results filtered by",', '.join([x+'='+y for x,y in filters])
		else:
			print "Searching in all results"
		
		if limit:
			print "Limiting the result set to "+limit+" users"
			sql += " LIMIT "+str(int(limit))+";"
			
		assignments = self.db.query(sql)
		print "Found",len(assignments),"assignments"
		
		return assignments
	
	
	def getMinutiaTypes(self, ids = False, noext = False):
		mtypes = ['bifurcation','ridge_ending','unknown','unknown2']
		if not noext:
			mtypes.extend(['difference','center'])
		if ids:
			return dict(zip(range(1,len(mtypes)+1), mtypes))
		else:
			return mtypes
	
	
	def saveQualityMap(self, map, dims, filename, colors={1:(255,255,255,255),0:(0,0,0,255)}):
		surface = PIL.Image.new('RGBA', (dims[0],dims[1]), (0,0,0,255))
		dc = PIL.ImageDraw.Draw(surface)
		y = 0
		for line in itertools.izip_longest(*[iter(map)]*dims[0]):
			for x in range(dims[0]):
				value = line[x]
				dc.point((x,y), fill=colors[value])
			y += 1
		surface.save(filename)

	
	
# Context-based stdout duplicator. Pass 'None' as filename to make it a noop
class Tee(object):
	def __init__(self, filename=None, mode='w'):
		self.name = filename
		self.mode = mode
		
	def __enter__(self):
		if self.name is not None:
			self.file = open(self.name, self.mode)
			self.file.write('# Log file created on: '+str(datetime.datetime.now())+'\n')
			self.file.write('# Command was: '+' '.join([x if ' ' not in x else '"'+x+'"' for x in sys.argv])+'\n\n')
			self.stdout = sys.stdout
			sys.stdout = self
	
	def __exit__(self, _1, _2, _3):
		if self.name is not None:
			sys.stdout = self.stdout
			self.file.write('\n# Log file closed on: '+str(datetime.datetime.now())+'\n')
			self.file.close()

	def write(self, data):
		assert self.name
		self.file.write(data)
		self.stdout.write(data)


from Extractor import Extractor
from QMapToImage import QMapToImage
from QMapToCSV import QMapToCSV
from Summary import Summary
from GeneralMetrics import MxMetrics, MinutiaeExport