class EpisodeFinderClientProtocol(NetstringReceiver):
	""" Twisted Protocol implementation """
	def __init__(self):
		self.encoder = MessageEncoder()
		self.defer = defer
		self.state = "init"
		self.defer_search_results = None
		self.defered_result_request_dl = None

	def stringReceived(self, string): #pylint: disable=C0103
		""" Data received protocol management
			Internal state dependant behavior :
			(init -> waiting results)
			(waiting results -> disconnect)
		"""
		result = self.encoder.decode(string)
		debug("receiving data")
		if self.state == "waiting_results" : 
			self.defer_search_results.callback(result)
			self.state = "waiting_dl_request"
		else:
			info("recieving result of dl launch order")
			self.defered_result_request_dl.callback(result) 
			info("finished : disconnecting")
			self.disconnect()

	def ep_request(self, episode):
		""" requests to deluge for @episode"""
		info("sending request to search")
		self.sendString(self.encoder.encode(episode))
		self.defer_search_results = defer.Deferred()
		self.state = "waiting_results"
		return self.defer_search_results

	def results_found(self):
		""" Unused method ? obsolete ?"""
		pass

	def dl_request(self, answer):
		""" Dl request handler -> 
		asks "answer" to be downloaded to the server

		returns the defered which will be triggered 
		when the server will have treated the request.
		"""
		logging.info("dl_request ...") 
		self.defered_result_request_dl = defer.Deferred()
		self.sendString(self.encoder.encode(answer))
		return self.defered_result_request_dl

	def disconnect(self):
		""" Disconnects """
		return self.transport.loseConnection()
 def __init__(self):
     debug("building episode finder")
     self.state = "wait_episode"
     self.encoder = MessageEncoder()
     self.episode_video_finder = None
class EpisodeFinderServer(NetstringReceiver):
    """ Server for finding magnets and handling requests
	(used in video_finder_server.py)
	"""

    def __init__(self):
        debug("building episode finder")
        self.state = "wait_episode"
        self.encoder = MessageEncoder()
        self.episode_video_finder = None

    def doStart(self):  # pylint: disable=C0103
        """ nothing to do """
        info("server started")

    def doStop(self):  # pylint: disable=C0103
        """ nothing to do """
        info("server stopped")

    def handle_ep_request(self, episode):
        """ Entry point method, calls to initiate a session
		@episode : the episode to search video for
		"""

        def on_result_found(results):
            """ Search done callback """
            info("sending video search results to client for {}...".format(episode))
            self.sendString(self.encoder.encode(results))

        def on_err(err):
            """ Error on search callback """
            info("Error on searching candidates video dowload for {}".format(episode))
            info(" ->: Err {}".format(err))
            return False

        self.episode_video_finder = EpisodeVideoFinder()
        wait_for_result = self.episode_video_finder.search_newep(episode)
        return wait_for_result.addCallback(on_result_found).addErrback(on_err)

    def sendObject(self, obj):  # pylint: disable=C0103
        """ method for sending a python object instead of
		a string (extension of twisted string server)
		@obj : the object to send

		"""
        self.sendString(self.encoder.encode(obj))

    def handle_dl_request(self, message):
        """ server handler
		"""

        def send_result(result):
            """ callback for sending results to client"""
            self.sendObject(result)

        info("dl_request ...")
        self.episode_video_finder.on_chosen_launch_dl(message).addCallback(send_result)

    def stringReceived(self, request):  # pylint: disable=C0103
        """ Implementation of the twisted method
		analyses client request and modify internal state accordingly
		"""
        debug("string received !!")

        request = self.encoder.decode(request)
        if self.state == "wait_episode":
            self.state = "wait_answer"
            self.handle_ep_request(request)
        else:
            self.handle_dl_request(request)
	def __init__(self):
		debug("building episode finder")
		self.state = "wait_episode"
		self.encoder = MessageEncoder()
		self.episode_video_finder = None
class EpisodeFinderServer(NetstringReceiver):
	""" Server for finding magnets and handling requests
	(used in video_finder_server.py)
	"""
	def __init__(self):
		debug("building episode finder")
		self.state = "wait_episode"
		self.encoder = MessageEncoder()
		self.episode_video_finder = None

	def doStart(self): #pylint: disable=C0103
		""" nothing to do """
		info("server started")

	def doStop(self): #pylint: disable=C0103
		""" nothing to do """
		info("server stopped")
	
	def handle_ep_request(self, episode):
		""" Entry point method, calls to initiate a session
		@episode : the episode to search video for
		"""
		def on_result_found(results):
			""" Search done callback """
			info("sending video search results to client for {}...".format(episode))
			self.sendString(self.encoder.encode(results))

		def on_err(err):
			""" Error on search callback """
			info("Error on searching candidates video dowload for {}".format(episode))
			info(" ->: Err {}".format(err))
			return False

		self.episode_video_finder = EpisodeVideoFinder()
		wait_for_result = self.episode_video_finder.search_newep(episode)
		return wait_for_result\
				.addCallback(on_result_found)\
				.addErrback(on_err)

	def sendObject(self, obj): #pylint: disable=C0103
		""" method for sending a python object instead of
		a string (extension of twisted string server)
		@obj : the object to send

		"""
		self.sendString(self.encoder.encode(obj))

	def handle_dl_request(self, message):
		""" server handler
		"""
		def send_result(result):
			""" callback for sending results to client"""
			self.sendObject(result)
		info("dl_request ...")
		self.episode_video_finder\
				.on_chosen_launch_dl(message)\
				.addCallback(send_result)

	def stringReceived(self, request): #pylint: disable=C0103
		""" Implementation of the twisted method
		analyses client request and modify internal state accordingly
		"""
		debug("string received !!")

		request = self.encoder.decode(request)
		if self.state == "wait_episode":
			self.state = "wait_answer"
			self.handle_ep_request(request)
		else:
			self.handle_dl_request(request)
	def __init__(self):
		self.encoder = MessageEncoder()
		self.defer = defer
		self.state = "init"
		self.defer_search_results = None
		self.defered_result_request_dl = None