'''
This file is part of TvTumbler.
 
Created on Sep 21, 2013
 
@author: Dermot Buckley
@copyright: Copyright (c) 2013, Dermot Buckley
@license: GPL
@contact: info@tvtumbler.com
'''
from datetime import datetime, date
import os
import sys
import threading
import time
 
import xbmc
import xbmcaddon
import xbmcgui
 
from .. import quality, logger
from ..comms.client import service_api
from .actions import *
from .common import TvTumblerWindowXMLDialog
 
 
__addon__ = xbmcaddon.Addon()
__addonpath__ = __addon__.getAddonInfo('path').decode('utf-8')
 
 
class TvTumblerDownloads(TvTumblerWindowXMLDialog):
    def __init__(self, *args, **kwargs):
        self._running_downloads = dict()
        self._running_lock = threading.Lock()
        self._non_running_downloads = dict()
        self._non_running_lock = threading.Lock()
 
    def onInit(self):
        self._show_loading_dialog()
        if not self.check_service_ok():
            self.close()
            return
 
        self._update_loading_dialog(35, 'Creating data loader...')
        self._running_data_loader = threading.Thread(target=self._refresh_data, name='_refresh_data')
        self._running_data_loader._abort = False
        self._update_loading_dialog(50, 'Loading data...')
        self._running_data_loader.start()
 
        self._update_loading_dialog(95, 'Completing ...')
        self.getControl(120).selectItem(0)  # select the first row
        self.setFocus(self.getControl(120))
        self._hide_loading_dialog()
 
    def _refresh_data(self):
        num_previous_running = -1  # we keep track of this, so that when it changes, we know to query the non-running also
        full_refresh = False
        while not (self._running_data_loader._abort or xbmc.abortRequested):
            temp_running = service_api.get_running_downloads()
            # copy from temp_running into _running_downloads and then ...
            t_dict = {}
            for r in temp_running:
                t_dict[r['rowid']] = r
            with self._running_lock:
                self._running_downloads = t_dict
 
            if num_previous_running != len(self._running_downloads):
                non_running = service_api.get_non_running_downloads()
                logger.debug('got non_running: ' + repr(non_running))
                t_dict = {}
                for r in non_running:
                    t_dict[r['rowid']] = r
                with self._non_running_lock:
                    self._non_running_downloads = t_dict
                num_previous_running = len(self._running_downloads)
                full_refresh = True
 
            self.updateDisplay(full=full_refresh)
            xbmc.sleep(4800)  # effectively this will be every 5 secs
            full_refresh = False
 
    def onClick(self, controlId):
        pass
 
    def onFocus(self, controlId):
        logger.debug('onFocus(' + str(controlId) + ')')
        self.controlId = controlId
 
    def onAction(self, action):
        logger.debug("ACTION: " + str(action.getId()) + " FOCUS: " +
                     str(self.getFocusId()) + " BC: " + str(action.getButtonCode()))
        if action == ACTION_CONTEXT_MENU:
            self.doMenu()
        elif action == ACTION_SELECT_ITEM:
            if self.getFocusId() == 205:  # follow/ignore button
                # self.toggleFollow()
                pass
            elif self.getFocusId() == 120:  # select a line on the list itself
                # self.toggleFollow()
                pass
            elif self.getFocusId() == 200:
                # self.add_show()
                pass
            elif self.getFocusId() == 201:
                pass
                # self.addFromLibrary()
            elif self.getFocusId() == 202:
                # self.openSettings()
                pass
            else:
                pass
                # self.eplist()
        elif action == ACTION_PARENT_DIR:
            action = ACTION_PREVIOUS_MENU
        elif action == ACTION_MOUSE_LEFT_CLICK:
            if self.getFocusId() == 205:  # follow/ignore button
                # self.toggleFollow()
                pass
            elif self.getFocusId() == 120:  # click a line on the list itself
                # self.toggleFollow()
                pass
            elif self.getFocusId() == 200:
                # self.add_show()
                pass
            elif self.getFocusId() == 201:
                pass
                # self.addFromLibrary()
            elif self.getFocusId() == 202:
                # self.openSettings()
                pass
 
        if (action == ACTION_PREVIOUS_MENU and
            self._running_data_loader and
            self._running_data_loader.is_alive()):
                self._running_data_loader._abort = True
 
        xbmcgui.WindowXMLDialog.onAction(self, action)
 
 
 
    def doMenu(self):
        pass
#         item, show = self._get_selected_item_and_show()
#         options = []
#         if item:
#             if show['followed']:
#                 options.append(('Ignore', self.toggleFollow))
#                 options.append(('Select Quality', self.select_wanted_quality))
#             else:
#                 options.append(('Follow', self.toggleFollow))
#         else:
#             # we have no non-item menu items
#             pass
#
#         if options:
#             dlg = xbmcgui.Dialog()
#             selected = dlg.select('Options', [o[0] for o in options])
#             if selected >= 0:
#                 options[selected][1]()
 
    def updateDisplay(self, full=False):
        def sizeof_fmt(num, zero_as='0'):
            if num is None or num == 0:
                return zero_as
            for x in ['bytes', 'KB', 'MB', 'GB']:
                if num < 1024.0 and num > -1024.0:
                    return "%3.1f%s" % (num, x)
                num /= 1024.0
            return "%3.1f%s" % (num, 'TB')
 
        def startdate_fmt(ts):
            dt = datetime.fromtimestamp(int(ts))
            last_midnight = datetime.combine(date.today(), datetime.min.time())
            age_since_mn = last_midnight - dt
            if dt >= last_midnight:
                _fmt = '%H:%M'
            elif age_since_mn.days < 7:
                _fmt = '%a %H:%M'
            else:
                _fmt = '%x'  # Locale's appropriate date representation.
            return dt.strftime(_fmt)
 
        def timedelta_fmt(start_ts, end_ts):
            secs = int(end_ts - start_ts)
            if secs < 90:
                return '%d secs' % (secs,)
            elif secs < 5400:  # 1.5 hrs
                return '%d mins' % (secs // 60,)
            elif secs < 86400:  # 24 hours
                h, s = divmod(secs, 3600)
                return '%d h %d m' % (h, s // 60)
            else:
                return '%d hours' % (secs // 3600,)
            # start_dt = datetime.fromtimestamp(start_ts)
            # end_dt = datetime.fromtimestamp(end_ts)
            # delta = end_dt - start_dt
            # return str(delta)
 
        def _update_listitem(i, d, running):
            if running:
                # --
                # A RUNNING download
                # --
                i.setLabel(d['name'])
                # this is a little trick to force refresh of the row
                if i.getLabel2() == d['status_text']:
                    i.setLabel2(d['status_text'] + ' ')
                else:
                    i.setLabel2(d['status_text'])
                start_time = startdate_fmt(int(d['start_time']))
                i.setProperty('start_time', start_time)
                # i.setProperty('total_size', str(sizeof_fmt(d['total_size'])))
                i.setProperty('progress', '%s/%s' % (sizeof_fmt(d['downloaded_size']),
                                                     sizeof_fmt(d['total_size'], '?')))
                if float(d['total_size']) < 0.0001:
                    progress = '0.0'
                else:
                    progress = "%.2f" % (100.0 * float(d['downloaded_size']) / float(d['total_size']))
                # logger.debug('progress = ' + progress)
                i.setProperty('download_progress', progress)
                i.setProperty('source', str(d['source']))
                i.setProperty('rowid', str(d['rowid']))
                i.setProperty('key', str(d['key']))
                i.setInfo('video', {"Genre": 'Running'})  # this controls the color of the status
                i.setInfo('data', d)
            else:
                # --
                # A completed/failed download
                # --
                i.setLabel(d['name'])
                status = str(d['final_status']) + ' (' + timedelta_fmt(int(d['start_time']), int(d['finish_time'])) + ')'
                i.setLabel2(status)
                start_time = startdate_fmt(int(d['start_time']))
                i.setProperty('start_time', start_time)
                # i.setProperty('total_size', str(sizeof_fmt(d['total_size'])))
                i.setProperty('progress', sizeof_fmt(d['total_size'], ''))
                #progress = "%.2f" % (100.0 * float(d['downloaded_size']) / float(d['total_size']))
                #i.setProperty('download_progress', progress)
                i.setProperty('source', str(d['source']))
                i.setProperty('rowid', str(d['rowid']))
                i.setProperty('key', str(d['key']))
                i.setInfo('video', {"Genre": d['final_status']})  # this controls the color of the status
                i.setInfo('data', d)
 
        lctrl = self.getControl(120)
        if full:
            lctrl.reset()
        items_to_remove = []
        keys_to_add = self._running_downloads.keys() + self._non_running_downloads.keys()
 
        # The first thing we do is to go through what's currently in the list, and update it.
        # (this won't have any effect of course if the list is empty)
        for i in range(0, lctrl.size()):
            item = lctrl.getListItem(i)
            rowid = int(item.getProperty('rowid'))
            in_running = rowid in self._running_downloads
            in_non_running = rowid in self._non_running_downloads
            if not in_running and not in_non_running:
                items_to_remove.append(i)
            else:
                keys_to_add.remove(rowid)  # need to remove it now, still running
                _update_listitem(item,
                                 self._running_downloads[rowid] if in_running else self._non_running_downloads[rowid],
                                 in_running)
 
        # Then remove anything we no longer need (again, no effect if the list is empty)
        for i in items_to_remove:
            # from here: http://forum.xbmc.org/showthread.php?tid=158937
            # window_instance.removeControl(window_instance.getControl(ID))
            lctrl.removeItem(i)  # actually, this works.  at least in Gotham.
 
        keys_to_add.sort(reverse=True)
        for k in keys_to_add:
            if k in self._running_downloads:
                d = self._running_downloads[k]
                item = xbmcgui.ListItem(label=d['name'],
                                        label2=d['status_text'])
                # item.addContextMenuItems([('Label', 'Action'), ('Label2', 'Action2')])
                _update_listitem(item, d, True)
            else:
                d = self._non_running_downloads[k]
                item = xbmcgui.ListItem(label=str(d['name']),
                                        label2=str(d['final_status']))
                _update_listitem(item, d, False)
 
            lctrl.addItem(item)
 
        # lctrl.setEnabled(bool(self._running_downloads))
        # lctrl.setSortMethod(1) # SORT_METHOD_LABEL