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


from PyQt4 import QtCore, QtGui
import sys, os
from random import shuffle
from partielatormods import *


class MonApplication(Ui_MainWindow):

    def __init__(self, settings):
        self.first_time, self.tags, self.header, self.settings, self.compile_seq, self.generate = settings
        self.treeTeX = False
        self.enonce = "None" #last exercise
        self.whatson = "tree" #what is being previewed ? tree or list ?
        #Default font for editing TeX code
        self.myfont = QtGui.QFont()
        self.myfont.setFamily("Monospace")
        self.myfont.setFixedPitch(True)
        self.myfont.setPointSize(10)

    def create_main_tree(self):
        """Ask crazyparser to create a tree, then fills up the QtreeWidget with it"""
        topdir = str(self.lineEdit.text())
        if topdir[-1] == "/":
            topdir = topdir[0:-1]
        nb_ex, self.treeTeX = crazyparser(topdir,self.tags)
        self.fillTheTree(self.treeTeX,nb_ex)
        self.actionExpand_Collapse.setEnabled(True)


    def search(self):
        """Search for a string in folder/file names and in the exercices using treeTeX"""
        string = unicode(self.lineEdit_search.text())
        string = string.encode("utf-8").lower()
        string2 = power_rangers(string) #to allow a search with accents of the form \'e instead of é (see crazyparser.py)
        s1 = smart_cut(string)   #to allow searching for more than one keyword
        s2 = smart_cut(string2)

        if self.treeTeX:
            self.treeTeX.reverse()
            self.treeTeX2 = []
            nb_ex = 0
            for root,dirs,files in self.treeTeX:
                dossiers_a_ajouter = []
                fichiers_a_ajouter = []


                #Keep only interesting exercises
                for feuille_dexo in files:
                    liste_dexo = []
                    for exo in feuille_dexo[1]:
                        allin = True
                        for i in range(len(s1)):
                            if s1[i][0] != "-":
                                if not ((s1[i] in exo.lower()) or (s2[i] in exo.lower()) \
                                  or (s1[i] in root.lower()) or (s1[i] in feuille_dexo[0])):
                                    allin = False
                            if s1[i][0] == "-" and len(s1[i])>1:
                                if ((s1[i][1:] in exo.lower()) or (s2[i][1:] in exo.lower()) \
                                  or (s1[i][1:] in root.lower()) or (s1[i][1:] in feuille_dexo[0])):
                                    allin = False
                        if allin:
                            liste_dexo.append(exo)
                    if liste_dexo:
                        nb_ex += len(liste_dexo)
                        fichiers_a_ajouter.append((feuille_dexo[0],liste_dexo))

                #Look for folders containing "interesting" sub-folders
                for dossier in dirs:
                    for a in self.treeTeX2:
                        if os.path.join(root,dossier) == a[0]:
                            dossiers_a_ajouter.append(dossier)

                #If exercises or intersting sub-folders where found , give them
                if dossiers_a_ajouter or fichiers_a_ajouter:
                    self.treeTeX2.append((root,dossiers_a_ajouter,fichiers_a_ajouter))
            self.treeTeX.reverse()
            self.treeTeX2.reverse()
            self.fillTheTree(self.treeTeX2,nb_ex)



    def fillTheTree(self, someTree, nb_ex):
        """Fills the QtreeWidget with someTree"""
        self.treeWidget.clear()
        if nb_ex == 0:
            self.treeWidget.setHeaderLabel(QtGui.QApplication.translate("Dialog", "No exercise found", None, QtGui.QApplication.UnicodeUTF8))
        elif nb_ex == 1:
            self.treeWidget.setHeaderLabel(QtGui.QApplication.translate("Dialog", "1 exercise found", None, QtGui.QApplication.UnicodeUTF8))
        else:
            self.treeWidget.setHeaderLabel(str(nb_ex) + " " + \
                QtGui.QApplication.translate("Dialog","exercises found", None, QtGui.QApplication.UnicodeUTF8))
        self.treeWidget.header().show()
        if someTree:
            itemDict = {}
            topdir = someTree[0][0]
            topname = topdir.split('/')[-1]
            racine = os.path.split(topdir)[0]
            itemDict[racine] = self.treeWidget
            font = QtGui.QFont()
            font.setBold(True)

            for fullpath, b, c in someTree:
                nom = fullpath.split("/")[-1]
                parent = os.path.split(fullpath)[0]
                itemDict[fullpath] = QtGui.QTreeWidgetItem(itemDict[parent])
                itemDict[fullpath].setText(0,QtGui.QApplication.translate("Form", nom, None,\
                QtGui.QApplication.UnicodeUTF8))

                for i in c:#TeX file
                    nb = len(i[1]) #number of exercices in the file
                    nom_tex = i[0][:-4]
                    nom2 = nom_tex + " (" + str(nb) + ")"
                    nom_element = os.path.join(fullpath,i[0])
                    itemDict[nom_element] = QtGui.QTreeWidgetItem(itemDict[fullpath])
                    itemDict[nom_element].setText(0,QtGui.QApplication.translate("Form", nom2, None,\
                    QtGui.QApplication.UnicodeUTF8))
                    #change font for TeX files to bold
                    #font = QtGui.QFont()
                    #font = itemDict[nom_element].font(0)
                    #font.setBold(True)
                    itemDict[nom_element].setFont(0, font)

                    compteur_exos = 0
                    for j in i[1]:#Exercises
                        compteur_exos += 1
                        #What comes next is to ensure exercices will be displayed alphabetically :
                        # "Ex 2" > "Ex 20" which is annoying that's why "Ex 2" becomes
                        # "Ex 02" when needed
                        if nb > 99:
                            if compteur_exos < 10:
                                nom_exo = " Ex 00" + str(compteur_exos)
                            elif 10 < compteur_exos < 100:
                                nom_exo = " Ex 0" + str(compteur_exos)
                            else:
                                nom_exo = " Ex " + str(compteur_exos)
                        elif nb > 9:
                            if compteur_exos < 10:
                                nom_exo = " Ex 0" + str(compteur_exos)
                            else:
                                nom_exo = " Ex " + str(compteur_exos)
                        else:
                            nom_exo = " Ex " + str(compteur_exos)

                        nom_cp_exo = nom_element + nom_exo
                        itemDict[nom_cp_exo] = QtGui.QTreeWidgetItem(itemDict[nom_element])
                        itemDict[nom_cp_exo].setText(0,QtGui.QApplication.translate("Form",\
                                             nom_exo, None, QtGui.QApplication.UnicodeUTF8))
                        itemDict[nom_cp_exo].enonce = j
                        itemDict[nom_cp_exo].titre = nom_tex + " - ex "+str(compteur_exos)
        self.treeWidget.sortItems(0,QtCore.Qt.AscendingOrder)


    def show_preview(self,enonce,inside=1):
        if enonce == self.enonce:  #only run LaTeX if necessary
            return "no"
        self.enonce = enonce
        try:
            os.mkdir("/tmp/partielator")
        except:
            print "couldn't create partielator dir or partielator dir already exists"
        a = codecs.open("/tmp/partielator/file.tex","w","utf-8")
        if inside and self.settings["use_preview"] == "True":
            a.write(self.header)
            a.write("\n\usepackage[active,graphics]{preview}")
            a.write("\n\\begin{document}\n")
            a.write("\\begin{preview}\n")
            a.write(unicode(enonce,"utf-8"))
            a.write("\n\\end{preview}\n")
            a.write("\n\\end{document}")
        elif inside:
            a.write(self.header)
            a.write("\n\\begin{document}\n")
            a.write(unicode(enonce,"utf-8"))
            a.write("\n\\end{document}")
        else:
            a.write(enonce)
        a.close()
        for cmd in self.compile_seq:
            os.system(str(cmd).replace("!file", "/tmp/partielator/file"))

    def show_preview_outside(self, enonce):
        self.show_preview(enonce, 0)
        os.system(self.settings["file_viewer"] + " /tmp/partielator/file." + self.settings["type_of_file"] + " &")

    def show_preview_inside(self, enonce):
        a = self.show_preview(enonce)
        self.preview.setPixmap(QtGui.QPixmap("/tmp/partielator/file.png"))
        if self.whatson == "tree" and a is None:
            self.verticalScrollBar.setValue(0)

    def show_preview_tree(self):
        if not self.treeWidget.currentItem().childCount():
            item = self.treeWidget.currentItem().parent()
        else:
            item = self.treeWidget.currentItem()
        if not item.child(0).childCount():
            enonce = ""
            for i in range(item.childCount()):
                enonce += item.child(i).enonce
            self.show_preview_inside(enonce)
            self.whatson = "tree"

    def whole_thing(self):
        whole_thing = ""
        for i in range(self.listWidget.count()):
            whole_thing += self.listWidget.item(i).enonce + "\n\n"
        return whole_thing

    def show_preview_list(self):
        whole_thing = self.whole_thing()
        if whole_thing:
            self.show_preview_inside(whole_thing)
            self.whatson = "list"

    def list_child_exercises(self, parent, l=[]):
        """List all child exercises of parent item"""
        if parent.childCount():
            for i in range(parent.childCount()):
                item = parent.child(i)
                self.list_child_exercises(item,l)
        else:
            l.append({'titre':parent.titre,'enonce':parent.enonce})
        return l

    def parcourir(self):
        dirName = QtGui.QFileDialog.getExistingDirectory(MainWindow,"Pick a folder",
                    self.settings["tex_path"])
        if dirName:
            self.settings["tex_path"] = dirName
            self.lineEdit.setText(self.settings["tex_path"])

    ################### Moving elements in a listWidget #########################
    def goup(self, listWidget):
        """Move selected element up in the list"""
        numero = listWidget.currentRow()
        if numero > 0:
            item = listWidget.item(numero)
            listWidget.takeItem(numero)
            listWidget.insertItem(numero-1,item)
            listWidget.setCurrentItem(item)

    def godown(self, listWidget):
        """Move selected element down in the list"""
        numero = listWidget.currentRow()
        if numero > -1 and (numero < listWidget.count()-1):
            item = listWidget.item(numero)
            listWidget.takeItem(numero)
            listWidget.insertItem(numero+1,item)
            listWidget.setCurrentItem(item)


    ################# Dealing with MainWindow's listWidget ###################################
    def addme(self):
        """Add selected element to the list if it has no child"""
        if not self.treeWidget.currentItem().childCount():
            item = QtGui.QListWidgetItem(self.listWidget)
            plop = self.treeWidget.currentItem()
            nom = plop.titre
            item.enonce = plop.enonce
            item.setText(QtGui.QApplication.translate("Form", str(nom), None, QtGui.QApplication.UnicodeUTF8))
            self.listWidget.setCurrentItem(item)
            self.pushButton_preview.setEnabled(True)
            self.actionEdit_exercise.setEnabled(True)
            self.pushButton_edit.setEnabled(True)

    def removeme(self):
        """Delete selected element from the list"""
        self.listWidget.takeItem(self.listWidget.currentRow())
        if not self.listWidget.count():
            self.pushButton_preview.setEnabled(False)
            self.actionEdit_exercise.setEnabled(False)
            self.pushButton_edit.setEnabled(False)


    def goup1(self):
        self.goup(self.listWidget)

    def godown1(self):
        self.godown(self.listWidget)


    ############################# ABOUT #######################################
    def apropos(self):
        Dialog_apropos = QtGui.QDialog()
        ui_apropos = guiabout.Ui_Dialog()
        ui_apropos.setupUi(Dialog_apropos)
        guiaboutplus.updateUi(ui_apropos)
        Dialog_apropos.exec_()


    ############################# PREFERENCES WINDOW ##########################

    def parcourir_tex_path(self):
        guiprefsplus.parcourir_tex_path(self)

    def parcourir_sav(self):
        guiprefsplus.parcourir_sav(self)

    def removetags(self):
        guiprefsplus.removetags(self)

    def addtags(self):
        guiprefsplus.addtags(self)

    def addtocompileseq(self):
        guiprefsplus.addtocompileseq(self)

    def removefromcompileseq(self):
        self.ui_prefs.listWidget_comp.takeItem(self.ui_prefs.listWidget_comp.currentRow())

    def goup2(self):
        self.goup(self.ui_prefs.listWidget_comp)

    def godown2(self):
        self.godown(self.ui_prefs.listWidget_comp)

    def combo(self, text):
        guiprefsplus.combo(self, text)

    def update_generate_header(self):
        guiprefsplus.update_generate_header(self)

    def prefs_delete(self):
        guiprefsplus.prefs_delete(self)

    def prefs(self):
        self.Dialog_prefs = QtGui.QDialog()
        self.ui_prefs = guiprefs.Ui_Dialog()
        self.ui_prefs.setupUi(self.Dialog_prefs)
        guiprefsplus.updateUi(self, MyHighlighter)
        res = self.Dialog_prefs.exec_()
        guiprefsplus.close_prefs(self, res)



    def randomize(self):
        """Open a dialog to generate a random exam"""
        #First, let's show the dialog :
        Dialog_random = QtGui.QDialog()
        self.ui_random = guirandomize.Ui_Dialog()
        self.ui_random.setupUi(Dialog_random)
        res = Dialog_random.exec_()
        guirandomizeplus.close(self, res)


    def expand_collapse_me(self):
        liste = self.treeWidget.selectedItems()
        if liste:
            parent = liste[0]
            if self.treeWidget.isItemExpanded(parent):
                self.collapse(parent)
            else:
                self.expand(parent)
        else:
            self.expand(self.treeWidget.topLevelItem(0))


    def collapse(self, parent):
        """Expands the tree under the current item and don't expand if no grand-children"""
        self.treeWidget.collapseItem(parent)
        for i in range(parent.childCount()):
            self.collapse(parent.child(i))


    def expand(self, parent):
        """Collapses the tree under the current item"""
        self.treeWidget.expandItem(parent)
        for i in range(parent.childCount()):
            if not parent.child(i).childCount():
                self.treeWidget.collapseItem(parent)
                continue
            self.expand(parent.child(i))


    ############################## EDITING EXERCISES #############################
    def edit_exercise(self):
        """Opens a dialog to edit an exercise"""
        #First, let's show the dialog :
        Dialog_edit = QtGui.QDialog()
        self.ui_edit = guiedit.Ui_Dialog()
        self.ui_edit.setupUi(Dialog_edit)
        self.ui_edit.textEdit.setFont(self.myfont)
        self.highlighter4 = MyHighlighter(self.ui_edit.textEdit)
        self.ui_edit.textEdit.setText(unicode(self.listWidget.currentItem().enonce,"utf8"))
        res = Dialog_edit.exec_()
        #Then, depending on whether the user clicked ok or cancel...
        if res:
            self.listWidget.currentItem().enonce = unicode(self.ui_edit.textEdit.toPlainText()).encode("utf8")
            if self.whatson == "list":
                self.show_preview_list()



    ############################## EXPORTING ###############################
    def gen_next(self):
        guiexportplus.gen_next(self)

    def gen_back(self):
        guiexportplus.gen_back(self)

    def export_sources(self, key):
        return guiexportplus.export_sources(self, key)

    def gen_combo(self,text):
        guiexportplus.gen_combo(self, text)

    def update_generate2(self):
        guiexportplus.update_generate2(self)

    def save(self, tex_code):
        guiexportplus.save(self, tex_code, MainWindow)

    def fin_export(self):
        guiexportplus.fin_export(self)

    def export(self):
        #Create the dialog
        Dialog_export = QtGui.QDialog()
        self.ui_export = guiexport.Ui_Dialog()
        self.ui_export.setupUi(Dialog_export)
        self.ui_export.frame1.hide()
        guiexportplus.updateUi(self, MyHighlighter, Dialog_export)
        #Opening dialog
        Dialog_export.exec_()


    ############################## WIZARD ###############################
    def wizard_allow_next(self):
        guiwizardplus.wizard_allow_next(self)

    def wizard_next(self):
        guiwizardplus.wizard_next(self)

    def wizard_back(self):
        guiwizardplus.wizard_back(self)

    def wizard_browse(self):
        guiwizardplus.wizard_browse(self, self.Dialog_wizard)

    def wizard_addtags(self):
        guiwizardplus.wizard_addtags(self)

    def wizard_removetags(self):
        guiwizardplus.wizard_removetags(self)

    def wizard_guess(self):
        f = self.ui_wizard.lineEdit.text()
        self.gtags, self.gheader = get_tags_header(f)
        guiwizardplus.wizard_guess(self)

    def wizard(self):
        #Create the dialog
        self.Dialog_wizard = QtGui.QDialog()
        self.ui_wizard = guiwizard.Ui_Dialog()
        self.ui_wizard.setupUi(self.Dialog_wizard)
        guiwizardplus.updateUi(self, MyHighlighter, self.Dialog_wizard)
        #Opening dialog
        res = self.Dialog_wizard.exec_()
        guiwizardplus.wizard_apply(self, res)

    ########################### TRANSLATING ########################################

    def to_french(self):
        self.settings["lang"] = "fr"
        self.show_lang_dialog()

    def to_english(self):
        self.settings["lang"] = "en"
        self.show_lang_dialog()

    def to_czech(self):
        self.settings["lang"] = "cs"
        self.show_lang_dialog()

    def show_lang_dialog(self):
        Dialog_lang = QtGui.QDialog()
        ui_lang = guilangchange.Ui_Dialog()
        ui_lang.setupUi(Dialog_lang)
        Dialog_lang.exec_()
    
    ########################### EVENT FILTERING ####################################
    def close_Event(self, e):
        """Will be executed when user tries to close the main window"""
        Dialog_quit = QtGui.QDialog()
        ui_quit = guiquit.Ui_Dialog()
        ui_quit.setupUi(Dialog_quit)
        res = Dialog_quit.exec_()
        if res:
            self.nettoyage()
            self.save_size()
            e.accept()
        else:
            e.ignore()

    def show_Event(self, e):
        """Will be executed before the window is shown"""
        if self.first_time:
            self.wizard()


    def eventFilter(self, object, event):
        """filtering right click on treeWidget"""
        if event.type() == 82 and object == self.treeWidget:
            object.emit(QtCore.SIGNAL("right_clicked()"))
        return 0 #pass event to the next handler


    ########################### LEAVING TEXAMATOR ######################################
    def nettoyage(self):
        try:
            for fichier in os.listdir("/tmp/partielator"):
                os.remove(os.path.join("/tmp/partielator",fichier))
            os.rmdir("/tmp/partielator")
        except:
            print "Couldn't clean up or nothing to clean"

    def save_size(self):
        print "Leaving"
        home_dir = os.path.expanduser("~")
        self.settings["width"], self.settings["height"] = self.windowWidth(), self.windowHeight()
        self.settings["little_splitter_s1"] = self.little_splitter.sizes()[0]
        self.settings["little_splitter_s2"] = self.little_splitter.sizes()[1]
        self.settings["big_splitter_s1"] = self.big_splitter.sizes()[0]
        self.settings["big_splitter_s2"] = self.big_splitter.sizes()[1]
        f = codecs.open(os.path.join(home_dir,".partielator","basics"),'w',"utf-8")
        for key, value in self.settings.iteritems():
            f.write(key+"="+str(value)+"\n")
        f.close()

    ######################### COMPLETING MAIN WINDOW #################################
    def setupUi2(self,Form):
        """Adds what's missing to the main Window"""
        Ui_MainWindow.setupUi(self, Form)
        Form.closeEvent = self.close_Event
        Form.showEvent = self.show_Event
        #lineEdit
        self.lineEdit.setText(self.settings["tex_path"])
        #self.treeWidget.header().hide()
        QtCore.QObject.connect(self.button_add,QtCore.SIGNAL("clicked()"),self.addme)
        QtCore.QObject.connect(self.actionGenerate_Random_Exam,QtCore.SIGNAL("triggered()"),self.randomize)
        QtCore.QObject.connect(self.treeWidget,QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)")\
        ,self.addme)
        QtCore.QObject.connect(self.button_remove,QtCore.SIGNAL("clicked()"),self.removeme)
        QtCore.QObject.connect(self.button_up,QtCore.SIGNAL("clicked()"),self.goup1)
        QtCore.QObject.connect(self.button_down,QtCore.SIGNAL("clicked()"),self.godown1)
        QtCore.QObject.connect(self.button_refresh,QtCore.SIGNAL("clicked()"),self.create_main_tree)
        QtCore.QObject.connect(self.treeWidget,QtCore.SIGNAL("itemClicked(QTreeWidgetItem*,int)")\
        ,self.show_preview_tree)
        QtCore.QObject.connect(self.listWidget,QtCore.SIGNAL("itemDoubleClicked(QListWidgetItem*)")\
        ,self.edit_exercise)
        QtCore.QObject.connect(self.button_save,QtCore.SIGNAL("clicked()"),self.export)
        QtCore.QObject.connect(self.actionQuitter,QtCore.SIGNAL("triggered()"),MainWindow.close)
        QtCore.QObject.connect(self.actionStart_Wizard,QtCore.SIGNAL("triggered()"),self.wizard)
        QtCore.QObject.connect(self.actionPrefs,QtCore.SIGNAL("triggered()"),self.prefs)
        QtCore.QObject.connect(self.actionExport,QtCore.SIGNAL("triggered()"),self.export)
        QtCore.QObject.connect(self.actionA_propos,QtCore.SIGNAL("triggered()"),self.apropos)
        QtCore.QObject.connect(self.actionEdit_exercise,QtCore.SIGNAL("triggered()"),self.edit_exercise)
        QtCore.QObject.connect(self.actionFrench,QtCore.SIGNAL("triggered()"),self.to_french)
        QtCore.QObject.connect(self.actionEnglish,QtCore.SIGNAL("triggered()"),self.to_english)
        QtCore.QObject.connect(self.actionCzech,QtCore.SIGNAL("triggered()"),self.to_czech)
        QtCore.QObject.connect(self.pushButton_edit,QtCore.SIGNAL("clicked()"), self.edit_exercise)
        QtCore.QObject.connect(self.actionExpand_Collapse,QtCore.SIGNAL("triggered()"),self.expand_collapse_me)
        QtCore.QObject.connect(self.pushButton_parcourir,QtCore.SIGNAL("clicked()"),self.parcourir)
        QtCore.QObject.connect(self.pushButton_preview,QtCore.SIGNAL("clicked()"),self.show_preview_list)
        QtCore.QObject.connect(self.lineEdit_search,QtCore.SIGNAL("textChanged(QString)"),self.search)
        #eventFilter to detect right click on the treeWidget
        Form.eventFilter = self.eventFilter
        self.treeWidget.installEventFilter(Form)
        QtCore.QObject.connect(self.treeWidget,QtCore.SIGNAL("right_clicked()"),self.expand_collapse_me)
        #Scroll Area settings for exercices bigger than the window :
        self.scrollArea.setBackgroundRole(QtGui.QPalette.Light)
        self.preview = QtGui.QLabel()
        self.scrollArea.setWidget(self.preview)
        self.verticalScrollBar = self.scrollArea.verticalScrollBar()
        #Splitter sizes :
        self.windowHeight = Form.height
        self.windowWidth = Form.width
        l = int(self.settings["width"])
        w = int(self.settings["height"])
        l1 = [int(self.settings["little_splitter_s1"]) , int(self.settings["little_splitter_s2"])]
        l2 = [int(self.settings["big_splitter_s1"]), int(self.settings["big_splitter_s2"])]
        Form.resize(l,w)
        self.big_splitter.setSizes(l2)
        self.little_splitter.setSizes(l1)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    #Translate app ?
    settings = gimme_my_settings()
    x = settings[3]
    if x["lang"] != "en":
        p = sys.argv[0]
        full_path = os.path.split(os.path.abspath(p))[0]
        t = QtCore.QTranslator()
        t.load(os.path.join(full_path, "ts_files/TeXamator_"+x["lang"]))
        QtCore.QCoreApplication.installTranslator(t)
    #Let's go !
    MainWindow = QtGui.QMainWindow()
    ui = MonApplication(settings)
    ui.setupUi2(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

