# -*- coding: utf-8 -*-
from django.db import models
from django.http import Http404
from django.utils.translation import gettext_lazy as _
from django.db.models import Q

# Create your models here.

class Comment(models.Model):
	lang = models.CharField(max_length=5)	
	comment = models.CharField(max_length=100)	
	level = models.CharField(max_length=5)

class Log(models.Model):
	game = models.CharField(max_length=30)
	date = models.DateField(blank=True, null=True)
	userinput = models.CharField(max_length=200)
	iscorrect = models.BooleanField()
	correct = models.CharField(max_length=200)
	example = models.CharField(max_length=200,null=True)
	feedback = models.CharField(max_length=200,null=True)
	comment = models.CharField(max_length=200)

class Semtype(models.Model):
	semtype = models.CharField(max_length=50)
	
	def __unicode__(self):
		return self.semtype

class Source(models.Model):
	type = models.CharField(max_length=20)
	name = models.CharField(max_length=20)
	
	
	def __unicode__(self):
		if self.type and self.name:
			return "%s: %s" % (self.type, self.name)
		elif self.name:
			return "%s" % self.name

# First, define the Manager subclass.
class NPosManager(models.Manager):
	def get_query_set(self):
		return super(NPosManager, self).get_query_set().filter(pos='N')

class Dialect(models.Model):
	dialect = models.CharField(max_length=5)
	name = models.CharField(max_length=100)
	
	def __unicode__(self):
		if self.dialect and self.name:
			return "%s: %s" % (self.dialect, self.name)
		elif self.name:
			return "%s" % self.name
		elif self.dialect:
			return "%s" % self.dialect

class MorphPhonTag(models.Model):
	stem		 = models.CharField(max_length=20)
	wordclass	= models.CharField(max_length=20)
	diphthong	= models.CharField(max_length=20)
	gradation	= models.CharField(max_length=20)
	rime		 = models.CharField(max_length=20)
	soggi		= models.CharField(max_length=20)
	# diphthong	= models.CharField(max_length=20)
	
	def __unicode__(self):
		attrs = [self.stem, 
				self.wordclass, 
				self.diphthong, 
				self.gradation, 
				self.rime, 
				self.soggi]
		
		S = unicode('/'.join([a for a in attrs if a.strip()])).encode('utf-8')
		return S
	
	class Meta:
		unique_together = ("stem",
							"wordclass",
							"diphthong",
							"gradation",
							"rime",
							"soggi",)

class Word(models.Model):
	"""
		>>> a = Word.objects.create(lemma='omg')
		>>> a.wordnob_set.create(lemma='bbq')	
	"""
	wordid = models.CharField(max_length=200)
	language = models.CharField(max_length=5, default='sma')
	lemma = models.CharField(max_length=200)
	presentationform = models.CharField(max_length=5)
	pos = models.CharField(max_length=12) # Accomodate larger PoS 
	stem = models.CharField(max_length=20)
	wordclass = models.CharField(max_length=8)
	valency = models.CharField(max_length=10)
	hid = models.IntegerField(max_length=3, null=True, default=None)
	semtype = models.ManyToManyField(Semtype)
	source = models.ManyToManyField(Source)
	diphthong = models.CharField(max_length=5)
	gradation = models.CharField(max_length=20)
	rime = models.CharField(max_length=20)
	attrsuffix = models.CharField(max_length=20)
	soggi = models.CharField(max_length=10)
	compare = models.CharField(max_length=5)
	frequency = models.CharField(max_length=10)
	geography = models.CharField(max_length=10)
	objects = models.Manager() # The default manager.
	N_objects = NPosManager() # The Noun-specific manager
	tcomm = models.BooleanField(default=False)
	# nob = Nob()
	morphophon = models.ForeignKey(MorphPhonTag, null=True)
	dialects = models.ManyToManyField(Dialect, null=True)
	
	def morphTag(self, nosave=True):
		try:
			mphon = self.morphophon
		except MorphPhonTag.DoesNotExist:
			mphon = False
		if not mphon:
			kwargs = {
				'stem':		 self.stem,
				'wordclass':	self.wordclass,
				'diphthong':	self.diphthong,
				'gradation':	self.gradation,
				'rime':		 self.rime,
				'soggi':		self.soggi,
			}
			morphtag, create = MorphPhonTag.objects.get_or_create(**kwargs)
			if nosave:
				return morphtag
			else:
				self.morphophon = morphtag
				self.save()
			
		
	def __init__(self, *args, **kwargs):
		super(Word, self).__init__(*args, **kwargs)
		self.definition = self.lemma
		if self.stem in ['3syll', 'trisyllabic']:
			self.wordclass = 'Odd'
		
		
	def create(self, *args, **kwargs):
		morphtag = self.morphTag()
		self.morphophon = morphtag
		self.pos = self.pos.lower().capitalize()
		super(Word, self).create(*args, **kwargs)
	
	def save(self, *args, **kwargs):
		""" Words model has an override to uppercase pos attribute on save, 
			in case data isn't saved properly.
			""" 
		morphtag = self.morphTag()
		self.pos = self.pos.lower().capitalize()
		self.morphophon = morphtag
		
		super(Word, self).save(*args, **kwargs)

	def __unicode__(self):
		return self.lemma
	
	def sem_types_admin(self):
		return ', '.join([item.semtype for item in self.semtype.order_by('semtype').all()])
	
	def source_admin(self):
		return ', '.join([item.name for item in self.source.order_by('name').all()])
	
	def translations2(self, target_lang):
		"""
			Returns obj.translations2XXX for string
		"""
		target_lang = target_lang[-3::]
		# related = Translations2(target_lang)
		# return self.__getattribute__(related)
		return self.wordtranslation_set.filter(language__startswith=target_lang)
	
	def baseform(self):
		"""
			Returns the infinitive/recitation Form for the Word.
			
			V - Inf
			N - Nom
			A - Attr
			
			Take a look at code in game.BareGame.get_baseform and move that here.
		"""
		
		pos_base = {
			'V': 'Inf',
			'N': 'Nom',
			'A': 'Attr',
			'Pron': 'Nom',
		}
		
		try:
			return self.form_set.filter(tag__string__icontains=pos_base[self.pos])[0]
		except:
			return None
	
# TODO: Wordxxx need to be one object
# TODO: admin interface is going to have problems loading tons of words, should use search field instead


class WordTranslation(models.Model):
	""" Abstract parent class for all translations.
		Meta.abstract = True
		
		TODO: null=True necessary?
	"""
	word = models.ForeignKey(Word)
	language = models.CharField(max_length=5)
	wordid = models.CharField(max_length=200)
	lemma = models.CharField(max_length=200, blank=True)
	phrase = models.TextField(blank=True)
	explanation = models.TextField(blank=True)
	# TODO: pos = models.CharField(max_length=12)
	pos = models.CharField(max_length=12)
	semtype = models.ManyToManyField(Semtype)
	source = models.ManyToManyField(Source)
	# translations = models.ManyToManyField(Word)
	frequency = models.CharField(max_length=10)
	geography = models.CharField(max_length=10)
	tcomm = models.BooleanField(default=False)
	tcomm_pref = models.BooleanField(default=False)
	# TODO: 
	# Need a method here which returns the correct translation string
	
	# lemma
	# lemma (phrase)
	# lemma (phrase) – explanation
	def _getTrans(self):
		if self.lemma:
			return self.lemma
		elif self.phrase:
			return self.phrase
		elif self.explanation:
			return self.explanation
		else:
			return ''
	
	def _getAnswer(self):
		word_answers = []
		if self.lemma:
			word_answers.append(self.lemma)
		elif self.phrase:
			word_answers.append(self.phrase)
		return word_answers
		
	def __unicode__(self):
		return self._getTrans().encode('utf-8')
	
	def __init__(self, *args, **kwargs):
		super(WordTranslation, self).__init__(*args, **kwargs)
		self.definition = self._getTrans()
		self.word_answers = self._getAnswer()
	
	
	# class Meta:
	# 	abstract = True

# Following are subclassed from above, no need to add anything special.
# 
# class Wordnob(WordTranslation):		
# 	class Meta: abstract = True
# class Wordswe(WordTranslation):		
# 	class Meta: abstract = True
# class Wordsme(WordTranslation):		
# 	class Meta: abstract = True
# class Wordeng(WordTranslation):		
# 	class Meta: abstract = True
# class Worddeu(WordTranslation):		
# 	class Meta: abstract = True

class Tagset(models.Model):
	tagset = models.CharField(max_length=25)
	
	def __unicode__(self):
		return self.tagset
	
	def matchFromTagString(self, tag):
		values = self.tagname_set.all().values_list('tagname', flat=True)

		tag_matches = [v for v in values if v in tag.string]

		return tag_matches


class Tagname(models.Model):
	tagname = models.CharField(max_length=25)
	tagset = models.ForeignKey(Tagset)	
	
	def __unicode__(self):
		return self.tagname

class Tag(models.Model):
	string = models.CharField(max_length=25)
	# TODO: pos = models.CharField(max_length=12)
	attributive = models.CharField(max_length=5)
	case = models.CharField(max_length=5)
	conneg = models.CharField(max_length=5)
	grade = models.CharField(max_length=10)
	infinite = models.CharField(max_length=10)
	mood = models.CharField(max_length=5)
	number = models.CharField(max_length=5)
	personnumber = models.CharField(max_length=8)
	polarity = models.CharField(max_length=5)
	pos = models.CharField(max_length=12)
	possessive = models.CharField(max_length=5)
	subclass = models.CharField(max_length=10)
	tense = models.CharField(max_length=5)
		
	class Admin:
		pass
		
	def __unicode__(self):
		return self.string
	
	attributeFixes = {
		'attributive': 		'Attributive',
		'conneg': 			'ConNeg',
		'grade': 			'Grade',
		'infinite': 		'Infinite',
		'mood': 			'Mood',
		'number': 			'Number',
		'personnumber': 	'Person-Number',
		'polarity': 		'Polarity',
		'pos': 				'Wordclass',
		'possessive': 		'Possessive',
		'subclass': 		'Subclass',
		'tense': 			'Tense',
	}
	
	def repairAttributes(self):
		""" If data is loaded improperly, certain Form attributes may not be set,
			such as Form.conneg, Form.personnumber. This function repairs them all,
			and saves if any repairs are made.

			It is called as part of __init__

			TODO: eventually we want this not to be called, because it increases
				  the query count for each Tag load.
		"""
		need_to_save = False
		error = False
		for k, v in self.attributeFixes.items():
			if not self.__getattribute__(k):
				try:
					tags = Tagset.objects.get(tagset=v).matchFromTagString(self)
				except Tagset.DoesNotExist:
					error = Http404('Tagset %s does not exist. You may need to reinstall tags.' % v)
					continue
				if len(tags) == 1:
					self.__setattr__(k, tags[0])
					need_to_save = True

		if need_to_save:
			self.save()

		if error:
			raise error

	def __init__(self, *args, **kwargs):
		super(Tag, self).__init__(*args, **kwargs)
		self.repairAttributes()


class Form(models.Model):
	word = models.ForeignKey(Word)
	tag = models.ForeignKey(Tag)
	fullform = models.CharField(max_length=200)
	dialects = models.ManyToManyField(Dialect, null=True)
	
	def __unicode__(self):
		return u'%s' % self.fullform.decode('utf-8')
		# Testing-- related lookups seem to be quite slow in MySQL...?
		# return '%s; %s+%s' % (self.fullform, self.word.lemma, self.tag)
	
	def matchNumber(self, match):
		""" Return a form matching the number of another.

			Must return a type that supports indexing.
		"""
		if self.tag.pos not in ['N', 'Adj']:
			return [self]

		filter = self.tag.string.replace(self.tag.number, 
											match.tag.number)

		return self.word.form_set.filter(tag__string=filter)

	def getBaseform(self, match_num=False):
		""" Gets the base form (e.g., citation/dictionary form) for 
			the wordform. Nouns -> Nom+Sg, Verbs -> Inf

			@param match_num:
				True - If the form supplied is a noun and plural
					   the baseform will be Nominative Plural
		"""

		if self.tag.pos in ['N', 'n', 'Pron', 'Num']:
			if match_num:
				number = self.tag.number
			else:
				number = 'Sg'
			baseform_num = self.word.form_set.filter(tag__case='Nom')
			
			baseform = baseform_num.filter(tag__number=number)
			if baseform.count() == 0 and number == 'Sg' and baseform_num.count() > 0:
				baseform = baseform_num
		elif self.tag.pos in ['V', 'v']:
			baseform = self.word.form_set.filter(**kwarg)
			if baseform.count() == 0:
				baseform = self.word.form_set.filter(tag__personnumber='Sg3')
			if baseform.count() == 0:
				raise Form.DoesNotExist
			
		elif self.tag.pos in ['A', 'a']:
			baseform = self.word.form_set.filter(tag__string='A+Pos+Sg+Nom')
			if baseform.count() == 0:
				baseform = self.word.form_set.all()
			if not baseform:
				raise Form.DoesNotExist
		else:
			raise Form.DoesNotExist

		try:
			return baseform[0]
		except IndexError:
			raise Form.DoesNotExist





############# MORFA FEEDBACK

class Feedbackmsg(models.Model):
	"""
		XML code for messages in messages.xml
	"""
	msgid = models.CharField(max_length=100)
	
	def __unicode__(self):
		return self.msgid


class Feedbacktext(models.Model):
	"""
		Message text in messages.xml
	"""
	message = models.CharField(max_length=200)
	language = models.CharField(max_length=6)
	feedbackmsg = models.ForeignKey(Feedbackmsg)
	
	def __unicode__(self):
		attrs = [
				self.language,
				self.message, 
			]
		S = unicode('/'.join([a for a in attrs if a.strip()])).encode('utf-8')
		return self.language + u':' + self.message

class Feedback(models.Model):
	messages = models.ManyToManyField(Feedbackmsg)
	# TODO: pos = models.CharField(max_length=12)
	# tag = models.ForeignKey(Tag)
	
	# Word morphology / classes
	attrsuffix = models.CharField(max_length=10,null=True,blank=True)
	dialects = models.ManyToManyField(Dialect)
	# diphthong = models.CharField(max_length=5,blank=True,null=True)
	# gradation = models.CharField(max_length=15,null=True,blank=True)
	# rime = models.CharField(max_length=20,null=True,blank=True)
	soggi = models.CharField(max_length=10,null=True,blank=True)
	stem = models.CharField(max_length=20,blank=True,null=True)
	wordclass = models.CharField(max_length=20,blank=True,null=True)

	# Tag / inflection 
	attributive = models.CharField(max_length=10,null=True,blank=True)
	case2 = models.CharField(max_length=5,null=True,blank=True)
	grade = models.CharField(max_length=10,null=True,blank=True)
	mood = models.CharField(max_length=10,null=True,blank=True)
	number = models.CharField(max_length=5,null=True,blank=True)
	personnumber = models.CharField(max_length=5,null=True,blank=True)
	pos = models.CharField(max_length=12,blank=True,null=True)
	tense = models.CharField(max_length=5,null=True,blank=True)

	class Meta:
		# Sma doesn't have "diphthong","gradation"
		# Sma doesn't have "rime"
		# unique_together = ("tag")
		unique_together = ( "pos",
							"stem",
							"soggi",
							"wordclass",
							
							"case2",
							"number",
						
							"personnumber",
							"tense",
							"mood",
						
							"grade",
							"attrsuffix",
							"attributive", )

	def __unicode__(self):
		attrs = [
				self.stem,
				self.wordclass,
				self.pos,
				self.case2, 
				self.grade, 
				self.mood, 
				self.number, 
				self.personnumber,
				self.tense,
				self.attrsuffix,
				self.attributive, 
				self.soggi
			]
		attrs = [a for a in attrs if a]
		S = unicode('/'.join([a for a in attrs if a.strip()])).encode('utf-8')
		return S
	
	# def save(self, *args, **kwargs):
	# 	"""
	# 		Normalize syllables.
	# 	"""
	# 	syllables = {
	# 		'2syll': '2syll',
	# 		'3syll': '3syll',
	# 		'bisyllabic': '2syll',
	# 		'trisyllabic': '3syll',
	# 		'': '',
	# 	}
	# 	
	# 	if self.stem in syllables.keys():
	# 		self.stem = syllables[self.stem]
	# 	
	# 	super(Feedback, self).save(*args, **kwargs)
	





######### EXTRA
class Grammarlinks(models.Model):
	name = models.CharField(max_length=200,blank=True,null=True)
	address = models.CharField(max_length=800,blank=True,null=True)
	language = models.CharField(max_length=5,blank=True,null=True)
