#! /usr/bin/env python3
# -*- coding: utf-8 -*-

#	Copyright 2011-2013, Marten de Vries
#	Copyright 2011, Cas Widdershoven
#	Copyright 2011, Milan Boers
#
#	This file is part of OpenTeacher.
#
#	OpenTeacher 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.
#
#	OpenTeacher 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 OpenTeacher.  If not, see <http://www.gnu.org/licenses/>.

import random

class IntervalLessonType:
	def __init__(self, createEvent, list, indexes, modifyItem, groupSizeSetting, minQuestionsSetting, whenKnownSetting, *args, **kwargs):
		super().__init__(*args, **kwargs)

		self.newItem = createEvent()
		self.lessonDone = createEvent()
		self.list = list
		self._indexes = indexes
		self._modifyItem = modifyItem or (lambda item: item)

		self._groupSizeSetting = groupSizeSetting
		self._minQuestionsSetting = minQuestionsSetting
		self._whenKnownSetting = whenKnownSetting

		self._test = {
			"results": [],
			"finished": False,
			"pauses": [],
		}

	@property
	def totalItems(self):
		#the indexes still to do in the very best case + the amount of
		#items already asked.
		return len(self._indexes) + self.askedItems

	@property
	def askedItems(self):
		#the length of all the unique itemId's in the results of the
		#current tests gives the amount of asked items
		ids = set([result["itemId"] for result in self._test["results"]])
		return len(ids)

	@property
	def _minQuestions(self):
		minQuestions = self._minQuestionsSetting["value"]
		if minQuestions < 1:
			minQuestions = 2
		return minQuestions

	@property
	def _whenKnown(self):
		whenKnown = self._whenKnownSetting["value"]
		if whenKnown < 0 or whenKnown > 99:
			whenKnown = 80
		return whenKnown

	@property
	def _groupSize(self):
		#get the values of some settings
		return max(self._groupSizeSetting["value"], 2)

	def setResult(self, result):
		"""result is a Result-type object saying whether the question
		   was answered right or wrong

		"""
		#Add the test to the list (if it's not already there)
		self._appendTest()
		#and add this result, so it's weighed in the calculations below
		self._test["results"].append(result)

		#get the amount of right and wrong answers for the current item
		#in this test.
		right = 0
		wrong = 0
		currentItem = self.list["items"][self._currentIndex]
		for loopResult in self._test["results"]:
			if loopResult["itemId"] == currentItem["id"]:
				if loopResult["result"] == "right":
					right += 1
				elif loopResult["result"] == "wrong":
					wrong += 1

		#if the item is not known well enough, add it to the list again
		#so it's asked later.
		total = right + wrong
		percentageRight = right / float(total) * 100.0
		if total < self._minQuestions or percentageRight < self._whenKnown:
			#pos may not be 0, because the current item shouldn't be
			#asked again directly. Size is -1 because indexes start at
			#0, and counting at 1.
			try:
				pos = random.randint(1, min(len(self._indexes), self._groupSize -1))
			except ValueError:
				#len(self._indexes) is 0, but the item needs to be asked
				#again. No option other than doing it immediately.
				pos = 0
			self._indexes.insert(pos, self._currentIndex)

		#keep the user busy.
		self._sendNext()

	def addPause(self, pause):
		self._test["pauses"].append(pause)

	def correctLastAnswer(self, result):
		#it's questioned again anyway. Who cares...
		self._test["results"][-1] = result

	def _appendTest(self):
		try:
			self.list["tests"][-1]
		except KeyError:
			self.list["tests"] = [self._test]
		except IndexError:
			self.list["tests"].append(self._test)
		else:
			if not self.list["tests"][-1] == self._test:
				self.list["tests"].append(self._test)

	def _sendNext(self):
		try:
			self._currentIndex = self._indexes.pop(0)
		except IndexError:
			self._test["finished"] = True
			self.lessonDone.send()
		else:
			item = self.list["items"][self._currentIndex]
			self.newItem.send(self._modifyItem(item))

	#Just send the next question and everything will be fine :)
	start = _sendNext

	def skip(self):
		#just ask again at the end.
		self._indexes.append(self._currentIndex)
		self._sendNext()

class IntervalModule:
	def __init__(self, moduleManager, *args, **kwargs):
		super().__init__(*args, **kwargs)
		self._mm = moduleManager

		self.type = "lessonType"
		self.requires = (
			self._mm.mods(type="event"),
		)
		self.uses = (
			self._mm.mods(type="translator"),
			self._mm.mods(type="settings"),
		)
		self.filesWithTranslations = ("interval.py",)
		self.priorities = {
			"default": 170,
		}

	def enable(self):
		self._modules = set(self._mm.mods(type="modules")).pop()

		# Settings
		try:
			self._settings = self._modules.default(type="settings")
		except IndexError as e:
			self._whenKnownSetting = {"value": 80}
			self._minQuestionsSetting = {"value": 2}
			self.__groupSizeSetting = {"value": 4}
		else:
			self._groupSizeSetting = self._settings.registerSetting(**{
				"internal_name": "org.openteacher.lessonTypes.interval.groupSize",
				"type": "number",
				"defaultValue": 4,
				"minValue": 1,
			})
			self._minQuestionsSetting = self._settings.registerSetting(**{
				"internal_name": "org.openteacher.lessonTypes.interval.minQuestions",
				"type": "number",
				"defaultValue": 2,
				"minValue": 1,
			})
			self._whenKnownSetting = self._settings.registerSetting(**{
				"internal_name": "org.openteacher.lessonTypes.interval.whenKnown",
				"type": "number",
				"defaultValue":80,
				"minValue": 0,
				"maxValue": 99,
			})

		self.newItem = self._createEvent()

		#register _retranslate()
		try:
			translator = self._modules.default("active", type="translator")
		except IndexError:
			pass
		else:
			translator.languageChanged.handle(self._retranslate)
		self._retranslate()

		self.active = True

	def _retranslate(self):
		#install translator
		try:
			translator = self._modules.default("active", type="translator")
		except IndexError:
			_, ngettext = str, lambda a, b, n: a if n == 1 else b
		else:
			_, ngettext = translator.gettextFunctions(
				self._mm.resourcePath("translations")
			)

		self.name = _("Interval")

		#settings
		categories = {
			"category": _("Lesson type"),
			"subcategory": _("Interval"),
		}
		self._groupSizeSetting["name"] = _("Maximum size of group")
		self._groupSizeSetting.update(categories)
		self._minQuestionsSetting["name"] = _("Minimum amount of questions asked")
		self._minQuestionsSetting.update(categories)
		self._whenKnownSetting["name"] = _("Percent right before known")
		self._whenKnownSetting.update(categories)

	def disable(self):
		self.active = False

		del self._modules
		del self._settings
		del self._groupSizeSetting
		del self._minQuestionsSetting
		del self._whenKnownSetting

		del self.newItem
		del self.name

	@property
	def _createEvent(self):
		return self._modules.default(type="event").createEvent

	def createLessonType(self, list, indexes, modifyItem=None):
		lessonType = IntervalLessonType(self._createEvent, list, indexes, modifyItem, self._groupSizeSetting, self._minQuestionsSetting, self._whenKnownSetting)
		lessonType.newItem.handle(self.newItem.send)
		return lessonType

def init(moduleManager):
	return IntervalModule(moduleManager)
