#!/usr/bin/env python
# -*- coding: utf-8 -*-

#    Copyright (C) 2008-2010 Ivan Garcia <contact@ivangarcia.org>
#    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; either version 3 of the License, or
#    (at your option) any later version.
#
#    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 Street, Fifth Floor, Boston, MA 02110-1301 USA.

from PyQt4.QtCore import Qt, SIGNAL
import PyQt4.QtCore as QtCore
from PyQt4.Qt import QApplication, QString, QFont, QAbstractListModel, \
                     QVariant, QAbstractTableModel, QTableView, QListView, \
                     QLabel, QAbstractItemView, QPixmap, QIcon, QSize, \
                     QSpinBox, QPoint, QPainterPath, QItemDelegate, QPainter, \
                     QPen, QColor, QLinearGradient, QBrush, QStyle, \
                     QByteArray, QBuffer, QMimeData, \
                     QDrag, QRect, QFileDialog, QMessageBox

from PyQt4.QtGui import QProgressDialog, QPixmap, QSplashScreen, QErrorMessage, QLineEdit, \
                        QMessageBox, QFileDialog, QIcon, QDialog, QInputDialog,QDirModel, QItemSelectionModel
#import languages.Languages as languages

import images_rc
import logging
log = logging.getLogger("babiloo.gui.OnlineDictionariesView")
import os, urllib, traceback, tempfile
import core.net.downloader as downloader
from core.languages import Languages, autodetect_lang, availablelanguages
from core.modules import APP_TITLE, APP_VERSION

class Node:
  def __init__(self, data, parent=None):
    self.data=data
    self.checked = False
    self.parent=parent
    self.children=[]

  def addChild(self, data):
    node=Node(data, self)
    self.children.append(node)
    return node

  def row(self):
    if self.parent:
      return self.parent.children.index(self)
    else:
      return 0


class OnlineDictionariesModel(QtCore.QAbstractItemModel):
  def __init__(self, parent=None):
    QtCore.QAbstractItemModel.__init__(self, parent)
    self.root=Node(QtCore.QVariant(""))
    self.selectedNode = None
    self._main = parent
    self.engine = parent.engine
    self.window = None
    #self.window = self._main.settingsDialog
    #check the list of dicts from registry
    self.dicts = self.engine.getDictionaries()

  def setDictionaries(self,dictionaries):
            self.clearTree()
            for lang, dicts in dictionaries.items():
                    languageName = availablelanguages.locale2name(lang)
                    if not languageName:
                        languageName = lang
                    lang_item = {'type':'lang','nameLanguage': languageName}
                    langNode = self.root.addChild(lang_item)
                    for dict in dicts:
                       dictNode = langNode.addChild(dict)
                       #dictNode.setCheckable(True)

  def getMainApp(self):
        return self._main


  def clearTree(self):
     self.selectedNode = None
     self.languageFilter = None
     del self.root
     self.root=Node(QtCore.QVariant(""))
     self.reset() #Better than emit the dataChanged signal


  def unselectDictionaries(self):
      for lang in self.root.children:
          for dict in lang.children:
              dict.checked = False

  def columnCount(self, parent):
    if parent.isValid():
      return 1 #Only 1 column
    else:
      # header
      return 1 #len(self.root.data)

  def getIndexFromLanguage(self, lang):
        #TODO
        for langItem in self.root.children:
            #self.index(langItem.row(),0,  langItem.parent)
            print langItem.data
            print langItem

  def data(self, index, role):
    if not index.isValid():
      return QVariant()
    data = index.internalPointer().data

    if data["type"]  == "lang": #It's a SUBTITLE treeitem.
        lang = data
#        if role == QtCore.Qt.ForegroundRole:
#            if already in locale
#                return QVariant(QColor(Qt.red))

        if role == QtCore.Qt.FontRole:
                return QVariant(QFont('Arial', 9, QFont.Bold))

        if role == QtCore.Qt.DisplayRole:
                #Constructing the row text to show in the TreeView
                line = "[%s]" % lang["nameLanguage"]
                return QVariant(line)

        return QVariant()
    elif data["type"]  == "dict":
        dict = data
        if role == QtCore.Qt.ForegroundRole:
          return QVariant(QColor(Qt.blue))

        if role == QtCore.Qt.FontRole:
            return QVariant(QFont('Arial', 9, QFont.Bold))

        if role == QtCore.Qt.CheckStateRole:
            if index.internalPointer().checked:
                return  QVariant(Qt.Checked)
            else:
                return  QVariant(Qt.Unchecked)

        if role == QtCore.Qt.DisplayRole:
            return QVariant(dict["name"])

        return QVariant()

  def flags(self, index):
    if not index.isValid():
      return Qt.ItemIsEnabled
    data = index.internalPointer().data
    if data["type"]  == "dict":
        return QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    elif data["type"]  == "lang":
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

  def getTopNodes(self):
      return [self.index(parentItem.row(), 0) for parentItem in self.root.children]

  def getSelectedItem(self, index = None):
      if index == None: #We want to know the current Selected Item
        return self.selectedNode

      if not index.isValid():
            return None
      else:
            self.selectedNode = index.internalPointer()
            return self.selectedNode

  def getCheckedDictionaries(self):
      checkedDicts = []
      for lang in self.root.children:
          for dict in lang.children:
                if dict.checked:
                    checkedDicts.append(dict.data)
      return checkedDicts

  def headerData(self, section, orientation, role):
  #  if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
     # return self.root.data[section]

    return QtCore.QVariant("") #Hide headers

  def index(self, row, column, parent):
    if row < 0 or column < 0 or row >= self.rowCount(parent) or column >= self.columnCount(parent):
      return QtCore.QModelIndex()

    if not parent.isValid():
      parentItem = self.root
    else:
      parentItem = parent.internalPointer()

    if row > len(parentItem.children) -1 :
      return QtCore.QModelIndex()

    childItem = parentItem.children[row]
    if childItem:
        return self.createIndex(row, column, childItem)
    else:
      return QtCore.QModelIndex()

  def parent(self, index):
    if not index.isValid():
      return QtCore.QModelIndex()

    childItem = index.internalPointer()
    parentItem = childItem.parent
    #if parentItem == None:
        #return QtCore.QModelIndex()

    if parentItem == self.root:
      return QtCore.QModelIndex()

    return self.createIndex(parentItem.row(), 0, parentItem)

  def rowCount(self, parent):
    if parent.column() > 0:
      return 0

    if not parent.isValid():
      parentItem = self.root
    else:
      parentItem = parent.internalPointer()

    return len(parentItem.children)

  def downloadFile(self, link, dest_file):
            #Downloading....
            self.window.status_progress = QProgressDialog(_("Downloading files..."), _("&Abort"), 0, 0, self.window)
            self.window.status_progress.setWindowTitle(_("Downloading"))
            self.window.setCursor(Qt.BusyCursor)
            self.window.status_progress.show()
            self.window.progress(-1)

            try:
                outfile=open(dest_file, "wb")
                fileName=outfile.name.split(os.sep)[-1]
                proxies = None #TODO: take from options
                url, length=downloader.createDownload(link, proxies)
                if int(length) == 0:
                    return False

                self.window.progress(0, _("Starting the download (%s bytes) ...") % (length))
                log.debug("Downloading (%s bytes) to temporary file %s..." % (length, dest_file) )
                if length!="?":
                    length=float(length)
                bytesRead=0.0
                self.window.status_progress.setMaximum(100)
                bytesCounter = 0
                for line in url:
                    bytesRead+=len(line)
                    bytesCounter += 1
                    if bytesCounter == 1024:
                            bytesCounter = 0
                            if  not self.window.progress():
                                log.debug('Download canceled')
                                self.window.setCursor(Qt.ArrowCursor)
                                return False

                            if length!="?":
                                self.window.progress(100*bytesRead/length, "%s %.02f KB of %.02f KB" % (
                                    'Downloaded',
                                    bytesRead/1024.0,
                                    length/1024.0
                                ))
                            else:
                                self.window.progress(-1)

                    outfile.write(line)

                url.close()
                outfile.close()
            except Exception, e:
                QMessageBox.about(self.window,_("Error"),_("Unable to download file %s") % link)
                log.error("Error downloading %s" % link)
                traceback.print_exc()
                return False
            finally:
                self.window.status_progress.close()
                self.window.setCursor(Qt.ArrowCursor)

            return True

  def installLink(self, tempFilePath):
            dictionary = self.engine.loadDictionary(tempFilePath)
            if not dictionary['loaded']:
                    if dictionary['error'] != 'ALREADY_INSTALLED':
                            return False, dictionary['error']
                            #QMessageBox.about(self.window,_("Error"),_("Error trying to load the dictionary.\nFile corrupted or not supported."))
                    else:
                            return True, dictionary['error']
                            #QMessageBox.about(self.window,_("Alert"),_("The dictionary is already installed."))
            else:
                dictionary = dictionary['dict']
                self.getMainApp().loadDictionary(dictionary)
                filename = dictionary.getFileName()
                try:
                        self.getMainApp().dictFileManager.saveDictionaryFile(dictionary)
                        #QMessageBox.about(self.window,_("Info"), _("Dictionary successfully installed:\n %s") % filename)
                        return True, filename
                except:
                        return False, filename
                        #QMessageBox.about(self.window,_("Error"),_("Dictionary that couldn't be installed:\n %s") % filename)


  def onButtonDownloadFromLink(self):
            self.window = self.getMainApp().settingsDialog
            link = unicode(self.window.ui.downloadLinkEdit.text())
            if not link:
                QMessageBox.about(self.window,_("Error"),_("Link address is empty"))
                return

            fd, tempFilePath = tempfile.mkstemp()
            if self.downloadFile(link, tempFilePath):
                if not self.installLink(tempFilePath):
                    QMessageBox.about(self.window,_("Error"),_("Dictionary selected couldn't be installed."))

                self.window.dictionariesModel.emit(SIGNAL("layoutAboutToBeChanged()"))
                self.window.dictionariesModel.dicts = self.engine.getDictionaries()
                self.window.dictionariesModel.emit(SIGNAL("layoutChanged()"))

  def onButtonDownloadFromList(self):
            self.window = self.getMainApp().settingsDialog
            dicts = self.getCheckedDictionaries()
            if not dicts:
                QMessageBox.about(self.window,_("Error"),"Please select some dictionaries first")
            else:
                failed_installations = []
                for dict in dicts:
                    link = dict['link']

                    fd, tempFilePath = tempfile.mkstemp()
                    if self.downloadFile(link, tempFilePath):
                        if not self.installLink(tempFilePath):
                            failed_installations.append(tempFilePath)
                        self.window.dictionariesModel.emit(SIGNAL("layoutAboutToBeChanged()"))
                        self.window.dictionariesModel.dicts = self.engine.getDictionaries()
                        self.window.dictionariesModel.emit(SIGNAL("layoutChanged()"))
                    else:
                            failed_installations.append(dict['name'])

                if failed_installations:
                    QMessageBox.about(self.window,_("Error"),_("Dictionary that couldn't be installed:\n %s") % failed_installations)

  def onButtonInfoOnlineDict(self):
    dict = self.getSelectedItem().data
    QMessageBox.about(self.window,_("Info"),"Language Origin: %s\nLanguage Destination: %s\nName: %s\nLink: %s\n" %
                      (dict['lang_orig'], dict['lang_dest'], dict['name'], dict['link']))

  def onButtonRefreshOnlineDict(self):
        self.window = self.getMainApp().settingsDialog
        if hasattr(self.window, 'status_progress'):
            del self.window.status_progress
        else:
            self.window.status_progress = QProgressDialog(_("Rescanning dictionaries..."), _("&Abort"), 0, 0, self.window)
            self.window.status_progress.setWindowTitle(_("Info"))
            self.window.setCursor(Qt.BusyCursor)
            self.window.status_progress.show()
            self.window.progress(-1)

            self.refreshOnlineDict()
            self.window.ui.onlineDictionariesView.expandAll()

            self.window.status_progress.close()
            self.window.setCursor(Qt.ArrowCursor)

  def refreshOnlineDict(self):
        #dictionaries = [{'lang_orig':'vi','lang_dest':'en', 'link':'http://code.launchpad.net/babiloo/trunk/2.0.3/+download/babiloo_2.0.3.1-3_all.deb',  'name':'Vietnamese-English'}]
        dictionaries = self.getMainApp().OnlineService.GetDictionaries(APP_VERSION)
        dictionaries_per_lang = {}
        for dict in dictionaries:
            lang_orig = dict['lang_orig']
            lang_dest = dict['lang_dest']

            new_dict = dict
            new_dict['type'] ='dict'

            if dictionaries_per_lang.has_key(lang_orig) :
                dictionaries_per_lang[lang_orig].append(new_dict)
            else:
                dictionaries_per_lang[lang_orig] =  [new_dict]

            if lang_orig != lang_dest:
                if dictionaries_per_lang.has_key(lang_dest) :
                    dictionaries_per_lang[lang_dest].append(new_dict)
                else:
                    dictionaries_per_lang[lang_dest] =  [new_dict]

        #The english category will only contain those dictionary JUST in english-to-english
        #avoiding to have a long list of repeated dictionaries hanging from this category.

        if dictionaries_per_lang.has_key('en'):
            dictionaries_per_lang['en'] = [dict for dict in dictionaries_per_lang['en'] if dict['lang_orig'] == dict['lang_dest']]

        if not len(dictionaries_per_lang['en']):
            del dictionaries_per_lang['en']

        self.emit(SIGNAL("layoutAboutToBeChanged()"))
        self.setDictionaries(dictionaries_per_lang)
        self.emit(SIGNAL("layoutChanged()"))
        self.emit(SIGNAL("updatedOnlineDictionaries()"))
