# -*- 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, uuid, PyQt4
from PyQt4 import QtGui, QtCore
from VoteAdminUI import Ui_VoteAdminDialog
from ScrutinIO import Scrutin, Votes, Registre

from VoteAssentimentDialog import VoteAssentimentDialog
from VoteUniqueDialog import VoteUniqueDialog
from VoteUniqueTransferableDialog import VoteUniqueTransferableDialog


class VoteAdminDialog(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_VoteAdminDialog()
        self.ui.setupUi(self)

        # Les données internes (à quelle étape se trouve le programme, 
        self.etape = 1
        self.scrutin = None
        self.votewindow = None
        self.touslesvotes = {}
        self.touslesvotants = []
        self.urneFilename = None
        self.registreFilename = None
        self.datedebut = ""
        self.datefin = ""
        self.commentaires = ""
        self.titreVotes = ""
        self.idVotes ="NoID"
        self.connexions = {}
        self.cles = {}

        # Activation des boutons
        self.ui.chargeScrutinBouton.setEnabled(True)
        self.ui.verificationBouton.setEnabled(False)
        self.ui.sauverBouton.setEnabled(False)
        self.ui.connexionBouton.setEnabled(False)
        self.ui.ouvertureScrutinBouton.setEnabled(False)
        self.ui.fermetureScrutinBouton.setEnabled(False)
        self.ui.quitterBouton.setEnabled(True)

        # Connecte les boutons aux fonctions associées.
        self.connect(self.ui.chargeScrutinBouton, QtCore.SIGNAL("clicked()"), self.chargeScrutin)
        self.connect(self.ui.verificationBouton, QtCore.SIGNAL("clicked()"), self.verification)
        self.connect(self.ui.sauverBouton, QtCore.SIGNAL("clicked()"), self.sauverFichiers)
        self.connect(self.ui.connexionBouton, QtCore.SIGNAL("clicked()"), self.connexionServeurs)
        self.connect(self.ui.ouvertureScrutinBouton, QtCore.SIGNAL("clicked()"), self.ouvrirScrutin)
        self.connect(self.ui.fermetureScrutinBouton, QtCore.SIGNAL("clicked()"), self.fermerScrutin)
        self.connect(self.ui.quitterBouton, QtCore.SIGNAL("clicked()"), self.quitter)


    # Etape 1 - Charger un fichier SCRUTIN
    def chargeScrutin( self ):
        filename = QtGui.QFileDialog.getOpenFileName ( self, u"Charger un scrutin existant...", "", "Scrutin (*.scrutin)")
        # Si l'utilisateur a annulé
        if filename is None or filename == "":
                return
        #Ouverture du fichier
        self.scrutin = Scrutin.read( filename )
        if self.scrutin is None:
           self.erreur ( u"Impossible de charger le fichier " + filename)
           return


        ## Interface de vote pour les électeurs
        if self.scrutin["Type Scrutin"] == "Vote unique":
          self.votewindow = VoteUniqueDialog(self.scrutin)
        elif self.scrutin["Type Scrutin"] == "Vote unique transferable":
          self.votewindow = VoteUniqueTransferableDialog(self.scrutin)
        elif self.scrutin["Type Scrutin"] == "Vote par assentiment":
          self.votewindow = VoteAssentimentDialog(self.scrutin)
        else:
          self.erreur (u"Type de scrutin non reconnu !!")
          return

        # Il faut connecter les signaux de la fenetre de votes aux fonction de cette classe-ci
        self.connect(self.votewindow.ui.voterBouton, QtCore.SIGNAL("clicked()"), self.addVote)

        # Si c'est bon passons à l'étape suivante
        self.ui.affichageLabel.setText( u"<font color=green>Fichier Scrutin chargé !</font>" )
        self.ui.chargeScrutinBouton.setEnabled(False)
        self.ui.verificationBouton.setEnabled(True)
        self.etape = 2


    # Etape 2 - Vérifier que le programme lui-même correspond aux hash MD5 et SHA1 
    #  fournis dans les fichiers controle.md5 et controle.sha1
    def verification( self ):
        # Appeler md5sum et sha1sum pour générer des fichiers de signatures pour tous les fichiers python
        #  et comparer avec les fichiers de control fournis
        # Si c'est bon passons à l'étape suivante
        self.ui.affichageLabel.setText( u"<font color=orange>La vérification automatique du programme n'est pas implémentée !</font>" )
        self.ui.verificationBouton.setEnabled(False)
        self.ui.sauverBouton.setEnabled(True)
        self.etape = 3


    # Etape 3 - Choisir les fichiers locaux pour sauver les résultats
    def sauverFichiers( self ):
        # Générer un ID unique
        self.idVotes = str(uuid.uuid4())

        # Demander les chemins pour les deux fichiers à sauver, sauver un faux fichier pour tester, puis le supprimer
        filename = QtGui.QFileDialog.getSaveFileName ( self, u"Enregistrer les votes", "", "Votes (*.votes)")
        if filename is None or filename == "": # L'utilisateur a annulé -> on sort
                return
        if os.path.exists(filename):
            self.erreur (u"Attention, "+unicode(filename)+u" existe : \nil est interdit d'écraser un fichier de vote !\n Choisissez un autre fichier !")
            return
        if not Votes.write(  {"Header":"VOTES FILE version 1.0", "Titre Votes":self.titreVotes, "Commentaires":self.commentaires, "IdVotesFile":self.idVotes,\
                       "Date Debut":self.datedebut, "Date Fin":self.datefin, "Scrutin":self.scrutin, "Votes":self.touslesvotes }, filename ):
          self.erreur ( u"Attention : echec de la sauvegarde du fichier de Votes" )
          return
        self.urneFilename = filename
        os.remove(filename)

        #filename = QtGui.QFileDialog.getSaveFileName ( self, "Enregistrer le registre", "", "Registre (*.registre)")
        #if filename is None or filename == "": # L'utilisateur a annulé -> on sort
                #return
        # Pas besoin d'un autre nom, on change juste l'extension
        print "fichier "+unicode(filename)+"\n"
        basename, extension = os.path.splitext(unicode(filename))
        filename = basename + ".registre"
        if not Registre.write( {"Header":"REGISTRE FILE version 1.0", "Titre Votes":self.titreVotes, "Commentaires":self.commentaires, "IdVotesFile":self.idVotes,\
                       "Date Debut":self.datedebut, "Date Fin":self.datefin, "Scrutin":self.scrutin, "Votants":self.touslesvotants}, filename):
          self.erreur ( u"Attention : echec de la sauvegarde du Registre des électeurs" )
          return
        self.registreFilename = filename
        os.remove(filename)

        # Si c'est bon passons à l'étape suivante
        self.ui.affichageLabel.setText( u"<font color=green>Les fichiers de sauvegarde ont été choisis !</font>" )
        self.ui.sauverBouton.setEnabled(False)
        self.ui.connexionBouton.setEnabled(True)
        self.etape = 4


    # Etape 4 - Connexion aux serveurs nationaux et cross-validation des hashs
    def connexionServeurs( self ):
        # Ici, appeler le code réseau pour établir la connexion et vérifier que c'est ok
        self.connexions = {}
        # Ici envoyer les cles de connexion et attendre la validation du serveur. 
        # Couper la connexion et signaler un problème avec les cles en cas d'erreur

        # Les clefs sont ok, on les stockes
        self.cles = {"cle1": self.ui.cle1Edit.text(), "cle2": self.ui.cle2Edit.text(), "cle3": self.ui.cle3Edit.text()}
        # Si c'est bon passons à l'étape suivante
        self.ui.affichageLabel.setText( u"<font color=orange>Connexion aux serveurs/authentification externes non implémentée !</font>" )
        self.ui.connexionBouton.setEnabled(False)
        self.ui.ouvertureScrutinBouton.setEnabled(True)
        self.etape = 5


    # Etape 5 - Lancement du scrutin
    def ouvrirScrutin( self ):
        # Demander la confirmation pour lancer le vote
        if QtCore.QDateTime.fromString(self.scrutin["Date Debut"], QtCore.Qt.ISODate) > QtCore.QDateTime.currentDateTime ()\
           and QtCore.QDateTime.fromString(self.scrutin["Date Fin"], QtCore.Qt.ISODate) < QtCore.QDateTime.currentDateTime ():
              QtGui.QMessageBox.information(self, u"Lancement du scrutin", u"Veuillez confirmer le début du scrutin")
        else:
              rep = QtGui.QMessageBox.question(self, u"Lancement du scrutin", u"Attention\nla date et l'heure courante ne correspondent pas\n aux dates et heures du scrutin.\nConfirmez-vous le lancement du scrutin ?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
              if rep == QtGui.QMessageBox.No:
                 return

        # Noter le début du scrutin
        self.datedebut = QtCore.QDateTime.currentDateTime ().toString(QtCore.Qt.ISODate)
        # Effacer les cles pour empecher un electeur indélicat de fermer le scrutin
        self.ui.cle1Edit.setText("")
        self.ui.cle2Edit.setText("")
        self.ui.cle3Edit.setText("")

        # Ouvrir la fenetre de vote
        #self.votewindow.show()
        self.votewindow.showFullScreen()
        # Si c'est bon passons à l'étape suivante
        self.ui.affichageLabel.setText( u"<font color=green>Vote en cours !</font>" )
        self.ui.ouvertureScrutinBouton.setEnabled(False)
        self.ui.fermetureScrutinBouton.setEnabled(True)
        self.etape = 6


    # Etape 6 - Fermeture du scrutin et fermeture de la connexion aux serveurs
    def fermerScrutin( self ):
        if not(self.cles["cle1"] == self.ui.cle1Edit.text() and self.cles["cle2"] == self.ui.cle2Edit.text() and self.cles["cle3"] == self.ui.cle3Edit.text()):
           self.erreur (u"Les clefs sont incorrectes : vous devez les entrer à nouveau pour clore le scrutin !")
           return

        # Noter la fin du scrutin
        self.datefin = QtCore.QDateTime.currentDateTime ().toString(QtCore.Qt.ISODate)

        # Envoyer le registre des votants aux serveurs puis clore les connexions

        # Cacher la fenêtre
        # self.votewindow.showNormal()
        self.votewindow.hide()

        # Faire une dernière sauvegarde des fichiers - ou pas...

        # Si c'est bon passons à l'étape suivante
        self.ui.affichageLabel.setText( u"<font color=green>Le vote est clos</font>" )
        self.ui.fermetureScrutinBouton.setEnabled(False)
        self.etape = 7


    # Quitter l'interface (dernier bouton)
    def quitter ( self ):
      if self.etape == 5 or self.etape == 6:
        self.erreur(u"Impossible de quitter, il faut d'abord fermer le vote et les connexions !")
        return
      reply = QtGui.QMessageBox.question(self, 'Message',u"Voulez-vous vraiment quitter ?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
      if reply == QtGui.QMessageBox.Yes:
          QtGui.qApp.quit()


    # Ajouter un vote
    def addVote( self ):
      if not self.votewindow.validateVote(self.scrutin["Electeurs"], self.touslesvotants):
         return
      self.touslesvotes[str(uuid.uuid4())] = self.votewindow.getVoteHash()
      self.touslesvotants.append(self.votewindow.getVotant())
      self.saveNewVote()
      self.erreur( u"Votre vote a été enregistré !" )
      self.votewindow.resetVote()



    # Sauvegarde des fichiers complets et envoi du dernier vote aux serveurs
    def saveNewVote( self ):
      print "Sauvegarde des fichiers "+unicode(self.urneFilename) + " ou " + unicode(self.urneFilename)
      self.datefin  = QtCore.QDateTime.currentDateTime ().toString(QtCore.Qt.ISODate)
      Votes.write(  {"Header":"VOTES FILE version 1.0", "Titre Votes":self.titreVotes, "Commentaires":self.commentaires, "IdVotesFile":self.idVotes,\
                       "Date Debut":self.datedebut, "Date Fin":self.datefin, "Scrutin":self.scrutin, "Votes":self.touslesvotes }, self.urneFilename )
      self.touslesvotants.sort()
      Registre.write(  {"Header":"REGISTRE FILE version 1.0", "Titre Votes":self.titreVotes, "Commentaires":self.commentaires, "IdVotesFile":self.idVotes,\
                       "Date Debut":self.datedebut, "Date Fin":self.datefin, "Scrutin":self.scrutin, "Votants":self.touslesvotants}, self.registreFilename )
      # Envoi aux serveurs ?


    # Quand l'utilisateur ferme la fenetre, 
    def closeEvent(self, event):
        QtGui.QMessageBox.warning(self, u"Bureau de vote", u"Pour quitter, utilisez le bouton en bas de l'interface !")
        event.ignore()


    # Fonction pour afficher une erreur
    def erreur( self, message ):
        QtGui.QMessageBox.warning(self, "Scrutin", message)


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