# -*- coding: utf-8 -*-

# Copyright 2009 Manik Bhattacharjee (manik-listes at altern.org)
#
# This file is part of PyVote.
#
# PyVote 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.
#
# PyVote 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 PyVote.  If not, see <http://www.gnu.org/licenses/>.

import sys, os, operator, PyQt4
from PyQt4 import QtGui, QtCore
from CalculResultatsUI import Ui_CalculResultatsDialog
from ScrutinIO import Scrutin, Votes, Registre
from ScrutinCalcul import getAllMethods

class CalculResultatsDialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)

        # Configure l'interface utilisateur à partir du fichier généré par Qt4 Designer
        self.ui = Ui_CalculResultatsDialog()
        self.ui.setupUi(self)

        # Les fonctions de calcul
        self.fonctionsCalcul = getAllMethods()
        # Les données
        self.scrutin = None
        self.files = {}
        self.votes = {}
        self.votants = []
        # Connecte les boutons aux fonctions associées.
        self.connect(self.ui.chargerBouton, QtCore.SIGNAL("clicked()"),self.chargerVotes)
        self.connect(self.ui.calculBouton, QtCore.SIGNAL("clicked()"),self.calcul)
        self.connect(self.ui.exportBouton, QtCore.SIGNAL("clicked()"),self.exportHTMLresults)



    # Quand l'utilisateur ferme la fenetre, demander une confirmation
    def closeEvent(self, event):
        reply = QtGui.QMessageBox.question(self, 'Message',"Voulez-vous vraiment quitter ?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    # Charger les fichiers de vote
    #
    # Contrôles : tous les fichiers de vote et les registres doivent correspondre au même scrutin,
    # avoir des uuid différents les uns des autres, et il faut vérifier que les votes ne sont pas présents en double
    def chargerVotes (self):
        # Autoriser les chargements multiples
        filenames = QtGui.QFileDialog.getOpenFileNames ( self, u"Charger un ou plusieurs fichiers de votes...", "", "Votes (*.votes)")
        print "Filenames : "+repr(filenames)
        # Si l'utilisateur a annulé
        if filenames is None or filenames == "" or filenames==[]:
          return True

        for filename in filenames:
          print "Chargement      des votes de " + unicode(filename)
          v = Votes.read(filename)
          print "                   -> OK"
          # Registre des votants correspondant
          basename, extension = os.path.splitext(unicode(filename))
          filenameR = basename + ".registre"

          # Comparer avec les données scrutins avec le scrutin courant s'il existe
          print "Chargement du registre..."
          r  = Registre.read(filenameR)
          print "                   -> OK"

          if r is None or v is None:
            self.erreur( u"Erreur de chargement du fichier de vote ou du registre correspondant !" )
            return False
          print u"Fichier chargé -- ok"
          if self.scrutin is not None:
              if self.scrutinIdentiques(self.scrutin, r["Scrutin"]) and self.scrutinIdentiques(self.scrutin, v["Scrutin"]):
                if self.addVotesRegistre(v,r, filename):
                    return True
                else:
                    self.erreur( u"Attention, une erreur s'est produite à l'ajout du fichier de votes\n" + unicode(filename)+u"\nFichier ignoré")
                    return False
              else:
                self.erreur( u"Le fichier de votes " + unicode(filename)+u" ne correspond pas au même scrutin que les fichiers déjà chargés !")
                return False
          else:
            if self.scrutinIdentiques(v["Scrutin"], r["Scrutin"]):
              if self.addVotesRegistre(v,r, filename):
                self.scrutin = v["Scrutin"]
                return True
              else:
                self.erreur( u"Attention, une erreur s'est produite à l'ajout du fichier de votes\n" + unicode(filename)+u"\nFichier ignoré")
                return False
            else:
              self.erreur( u"Le fichier de votes " + unicode(filename)+u" ne correspond pas au même scrutin que le fichier registre du même nom !")
              return False


    def addVotesRegistre(self,v,r, filename):
        # Comparer avec les identifiants des votes avec ceux présents  (pas de doublon !)
        if reduce (operator.or_, [i in self.votes.keys() for i in v["Votes"].keys()]) == True:
          self.erreur( u"Erreur : un vote du fichier en cours de chargement est déjà présent dans les votes chargés !")
          return False
        # Vérifier que chaque électeur a voté une fois seulement
        if reduce (operator.or_, [i in self.votants for i in r["Votants"]]) == True:
          self.erreur (u"Erreur : un électeur déjà comptabilisé a également voté dans le nouveau fichier !")
          return False
        # Ajouter les votes à self.votes
        self.votes.update(v["Votes"])
        # Ajouter les votants à self.votants
        self.votants.extend(r["Votants"])
        # Afficher le nom de fichier dans la liste et sauver self.files[path] = {"registre":leregistre, "votes":lesvotes}
        self.ui.fichierList.addItem(filename)
        self.files[filename]={"Registre":r, "Votes":v}

        # Effacer les résultats qui ne sont plus valides
        self.ui.elusList.clear()
        self.ui.detailEdit.setText("")
        return True


    def scrutinIdentiques( self, s1, s2 ):
      return s1 == s2


    # Lancer le calcul en fonction du type de scrutin
    def calcul(self):
      if self.scrutin is None or self.votes == []:
        return
      result = self.fonctionsCalcul[self.scrutin["Type Scrutin"]](self.votes, self.scrutin)
      self.ui.elusList.clear()
      for elu in result["Elus"]:
         self.ui.elusList.addItem(repr(elu))
      self.ui.detailEdit.setText(result["Details"])


    # Exporter les résultats détaillés dans un fichier HTML
    def exportHTMLresults( self ):
      # Demander le chemin pour le fichier à sauver
      filename = QtGui.QFileDialog.getSaveFileName ( self, u"Enregistrer les résultats détaillés", "", u"Fichier HTML (*.html)")
      if filename is None or filename == "": # L'utilisateur a annulé -> on sort
                return
      f = open(filename, 'w')
      f.write(self.ui.detailEdit.toHtml())
      f.close()


    # Fonction pour afficher une erreur
    def erreur( self, message ):
        QtGui.QMessageBox.warning(self, u"Résultat de Scrutin", message)

if __name__ == "__main__":
   app = QtGui.QApplication(sys.argv)
   window = CalculResultatsDialog()
   window.show()
   sys.exit(app.exec_())