#!/usr/bin/env python
#encoding:utf-8
#author:dbr/Ben
#project:tvdb_api
#repository:http://github.com/dbr/tvdb_api
#license:Creative Commons GNU GPL v2
# (http://creativecommons.org/licenses/GPL/2.0/)

"""Contains included user interfaces for Tvdb show selection.

A UI is a callback. A class, it's __init__ function takes two arguments:

- config, which is the Tvdb config dict, setup in tvdb_api.py
- log, which is Tvdb's logger instance (which uses the logging module). You can
call log.info() log.warning() etc

It must have a method "selectSeries", this is passed a list of dicts, each dict
contains the the keys "name" (human readable show name), and "sid" (the shows
ID as on thetvdb.com). For example:

[{'name': u'Lost', 'sid': u'73739'},
 {'name': u'Lost Universe', 'sid': u'73181'}]

The "selectSeries" method must return the appropriate dict, or it can raise
tvdb_userabort (if the selection is aborted), tvdb_shownotfound (if the show
cannot be found).

A simple example callback, which returns a random series:

>>> import random
>>> from tvdb_ui import BaseUI
>>> class RandomUI(BaseUI):
...    def selectSeries(self, allSeries):
...            import random
...            return random.choice(allSeries)

Then to use it..

>>> from tvdb_api import Tvdb
>>> t = Tvdb(custom_ui = RandomUI)
>>> random_matching_series = t['Lost']
>>> type(random_matching_series)
<class 'tvdb_api.Show'>
"""

__author__ = "dbr/Ben"
__version__ = "1.2.1"

from tvdb_exceptions import tvdb_userabort

class BaseUI:
    """Default non-interactive UI, which auto-selects first results
    """
    def __init__(self, config, log):
        self.config = config
        self.log = log

    def selectSeries(self, allSeries):
        return allSeries[0]


class ConsoleUI(BaseUI):
    """Interactively allows the user to select a show from a console based UI
    """

    def _displaySeries(self, allSeries):
        """Helper function, lists series with corresponding ID
        """
        print "TVDB Search Results:"
        for i in range(len(allSeries[:6])): # list first 6 search results
            i_show = i + 1 # Start at more human readable number 1 (not 0)
            self.log.debug('Showing allSeries[%s] = %s)' % (i_show, allSeries[i]))
            print "%s -> %s # http://thetvdb.com/?tab=series&id=%s" % (
                i_show,
                allSeries[i]['name'].encode("UTF-8","ignore"),
                allSeries[i]['sid'].encode("UTF-8","ignore")
            )

    def selectSeries(self, allSeries):
        self._displaySeries(allSeries)

        if len(allSeries) == 1:
            # Single result, return it!
            print "Automatically selecting only result"
            return allSeries[0]

        if self.config['select_first'] is True:
            print "Automatically returning first search result"
            return allSeries[0]

        while True: # return breaks this loop
            try:
                print "Enter choice (first number, ? for help):"
                ans = raw_input()
            except KeyboardInterrupt:
                raise tvdb_userabort("User aborted (^c keyboard interupt)")
            except EOFError:
                raise tvdb_userabort("User aborted (EOF received)")

            self.log.debug('Got choice of: %s' % (ans))
            try:
                selected_id = int(ans) - 1 # The human entered 1 as first result, not zero
            except ValueError: # Input was not number
                if ans == "q":
                    self.log.debug('Got quit command (q)')
                    raise tvdb_userabort("User aborted ('q' quit command)")
                elif ans == "?":
                    print "## Help"
                    print "# Enter the number that corresponds to the correct show."
                    print "# ? - this help"
                    print "# q - abort tvnamer"
                else:
                    self.log.debug('Unknown keypress %s' % (ans))
            else:
                self.log.debug('Trying to return ID: %d' % (selected_id))
                try:
                    return allSeries[ selected_id ]
                except IndexError:
                    self.log.debug('Invalid show number entered!')
                    print "Invalid number (%s) selected!"
                    self._displaySeries(allSeries)
            #end try
        #end while not valid_input

