# Copyright (C) 2008-2009 LottaNZB Development Team
# 
# This program 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; version 3.
# 
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

import gtk
import urllib

from kiwi.ui.objectlist import ObjectList, Column

from lottanzb.backend import Download
from lottanzb.core import App
from lottanzb.util import gsignal, _

class DownloadList(ObjectList):
    gsignal("file-dropped", object)
    
    def __init__(self):
        self.default_columns = [
            Column("name",
                title=_("Name"),
                expand=True
            ),
            Column("size",
                title=_("Size"),
                expand=True,
                format_func=self.format_size
            ),
            DownloadProgressColumn()
        ]
        
        ObjectList.__init__(self, self.default_columns)
        
        drag_targets = [("DOWNLOAD_ROW", gtk.TARGET_SAME_WIDGET, 0)]
        drop_targets = drag_targets + [("text/plain", 0, 1)]
        treeview = self.get_treeview()
        
        treeview.connect("drag-data-get", self.drag_data_get)
        
        treeview.enable_model_drag_source(
            gtk.gdk.BUTTON1_MASK,
            drag_targets,
            gtk.gdk.ACTION_MOVE
        )
        
        treeview.connect("drag-data-received", self.drag_data_received)
        treeview.enable_model_drag_dest(drop_targets, gtk.gdk.ACTION_MOVE)
        
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.show()
    
    def _load(self, instances, clear):
        # Do nothing if empty list or None provided
        if clear and not instances:
            self.unselect_all()
            self.clear()
            return
        
        model = self._model
        iters = self._iters
        old_instances = self[:]
        
        # Do not always just clear the list, check if we have the same
        # instances in the list we want to insert and merge in the new items.
        if clear:
            for index, instance in enumerate(instances):
                try:
                    old_index = self.index(instance)
                except ValueError:
                    self.insert(index, instance)
                else:
                    if old_index != index:
                        old_treeiter = model[old_index].iter
                        dest_treeiter = model[index].iter
                        
                        model.move_before(old_treeiter, dest_treeiter)
                    
                    self.update(instance)
            
            if old_instances:
                for instance in self[len(instances):]:
                    self.remove(instance)
        else:
            for instance in iter(instances):
                iters[id(instance)] = model.append((instance,))
        
        # As soon as we have data for that list, we can autosize it, and
        # we don't want to autosize again, or we may cancel user
        # modifications.
        if self._autosize:
            self._treeview.columns_autosize()
            self._autosize = False
    
    def drag_data_get(self, treeview, context, selection, info, timestamp):
        item = self.get_selected()
        
        if item.movable:
            selection.set("DOWNLOAD_ROW", 8, str(item.id))
    
    def drag_data_received(self, treeview, context, x, y, selection, info, timestamp):
        drop_info = treeview.get_dest_row_at_pos(x, y)
        
        if not selection.data:
            return
        
        if info == 0:
            self.handle_download_move(int(selection.data), drop_info)
        elif info == 1:
            files = []
            
            for a_file in selection.data.replace("file://", "").split():
                if a_file.lower().endswith(".nzb"):
                    files.append(urllib.unquote(a_file).strip())
            
            self.emit("file-dropped", files)
    
    def handle_download_move(self, download_id, drop_info):
        download = App().backend.downloads.get_by_id(download_id)
        source_index = App().backend.downloads.get_incomplete().index(download)
        not_movable_count = len(App().backend.downloads.get_finished()) + \
            len(App().backend.downloads.get_processing())
        
        target_index = None
        
        if drop_info:
            path, position = drop_info
            target_index = path[0] - not_movable_count
            
            if target_index - source_index == 1 and \
                position == gtk.TREE_VIEW_DROP_BEFORE:
                target_index += -1
            elif source_index - target_index == 1 and \
                position == gtk.TREE_VIEW_DROP_AFTER:
                target_index += 1
            else:
                if source_index < target_index and \
                    position == gtk.TREE_VIEW_DROP_BEFORE:
                    target_index += -1
                elif source_index > target_index and \
                    position == gtk.TREE_VIEW_DROP_AFTER:
                    target_index += 1
            
        App().backend.move(download, target_index)
    
    @staticmethod
    def format_size(size):
        if size:
            return "%s MB" % size
        else:
            return ""

class DownloadProgressColumn(Column):
    def __init__(self):
        Column.__init__(self, "", title=_("Progress"), width=200)
    
    def _guess_renderer_for_type(self, model):
        return gtk.CellRendererProgress(), "progress"
    
    def cell_data_func(self, tree_column, renderer, model, treeiter, *args):
        download = self._objectlist[treeiter]
        
        if download.state == Download.State.FINISHED:
            state = _("Finished")
        elif download.state == Download.State.PROCESSING:
            if download.recovery:
                state = _("Repairing and extracting")
            else:
                state = _("Processing")
        elif download.state == Download.State.DOWNLOADING:
            state = "%s %%" % (str(download.progress))
            
            if App().backend.paused:
                state = _("Paused at: %s%%") % (download.progress)
            elif download.recovery:
                state = _("Downloading PAR recovery files: %s") % (download.progress)
        else:
            if download.recovery:
                state = _("Queued: Need PAR recovery")
            else:
                state = _("Queued")
        
        renderer.set_property("value", download.progress)
        renderer.set_property("text", state)
