# -*- encoding: utf-8 -*-

import os
import json, requests

from logger import *

class TaskManager(object):
	"""Class for communication with service engine. Has functions for retrieving new task (if available)
		and finishing completed tasks."""
	def __init__(self, config, logger):
		"""Constructor
			config - config given in the form of dictionary containing required paths and request data.
			logger - logger instance (as in logger.py)
		"""
		self.logger = logger

		self._process_dir = config['process_dir']
		self._done_dir = config['done_dir']
		self._tasker_url = config['tasker_url']
		self._tasker_get_method = config['tasker_get_method']
		self._tasker_finish_method = config['tasker_finish_method']
		self._request_headers = config['request_headers']
		self._data = config['data']

		self._reservation_session = requests.Session()
		self._reservation_session.headers.update(self._request_headers)

	def get_new_task(self):
		"""Retrieves new task from the queue if available. Engine is responsible for moving task to processing.
			returns: pair of path to task file and task options. If no task is available at the moment
					returns pair of Nones
		"""
		try:
			self.logger.log(DEBUG, "Sending POST request to the tasker")
			task_file, task_options = self.send_reservation()

			if task_file:
				task_file = os.path.join(self._process_dir, task_file)
			elif task_file is None:
				self.logger.log(DEBUG, "No `task` key in response")
			elif not task_file:
				self.logger.log(DEBUG, "No new tasks available")
				task_file = None
			return task_file, task_options
		except Exception as e:
			self.logger.log(ERROR, "Unable to fetch task")
			self.logger.log(ERROR, e)

	def finish_task(self, task_token, success=True):
		"""Finishes task with given path - checks for corresponding file in done and removes
			task file from processing.
			task_token can also be a path to any of task files (queued, progress or done)."""
		task_token = self.get_task_token(task_token)	# in case we provided path instead of token
		done_path = self.get_task_done_path(task_token)
		process_path = os.path.join(self._process_dir, task_token)
		if not os.path.exists(done_path):
			self.logger.task_log(task_token, ERROR, "Task finished, but no result file in done dir!")
		else:
			self.logger.log(DEBUG, "Finishing task " + task_token)
			self.send_response(task_token, success)
			try:
				os.remove(process_path)
			except Exception as e:
				self.logger.log(ERROR, "Unable to finish task " + task_token)
				self.logger.log(ERROR, e)
			else:
				self.logger.log(INFO, "Finished task: " + task_token)

	def send_reservation(self):
		task_file = None
		task_options = None
		try:
			url = self._tasker_url + self._tasker_get_method
			response_txt = self._reservation_session.post(url, data=json.dumps(self._data))
			response = json.loads(response_txt.text)
			self.logger.log(DEBUG, "response: " + response_txt.text)

			if 'task' in response:
				task_file = response['task'].encode('ascii', 'ignore')
			if 'options' in response:
				task_options = json.loads(response['options'].encode('ascii', 'ignore'))
		except Exception as e:
			self.logger.log(ERROR, "Unable to fetch task from tasker")
			self.logger.log(ERROR, e)
		return task_file, task_options

	def send_response(self, task_token, success=True):
		try:
			url = self._tasker_url + self._tasker_finish_method
			response_data = {'task': task_token, 'success': success}
			response_data.update(self._data)

			response_txt = None
			with requests.Session() as resp_session:
				response_txt = resp_session.post(url, data=json.dumps(response_data), headers=self._request_headers)
			response = json.loads(response_txt.text)

			if not 'status' in response:
				raise Exception("Response received has no STATE field")

			if not response['status'] == "OK":
				msg = "Response STATUS: " + response['status'] + "\n" \
					  "\nResponse VALUE: " + response['value']
				raise Exception(msg)
		except Exception as e:
			self.logger.log(ERROR, "Unable to send finish task info to tasker")
			self.logger.log(ERROR, e)

	@staticmethod
	def get_task_token(task_path):
		"""Returns task token from path (it cen be queue, processing or done path)"""
		return os.path.basename(task_path)

	def get_task_done_path(self, task_token):
		"""Returns task done path from it's queue or progess path.
			task_token can also be a path to any of task files (queued, progress or done)."""
		task_token = TaskManager.get_task_token(task_token)	# in case we provided path instead of token
		task_done_path = os.path.join(self._done_dir, task_token)
		return task_done_path
