# -*- coding: iso-8859-1 -*-
from __future__ import division # 1/2 == .5 (par defaut, 1/2 == 0)

##--------------------------------------##
#              WxGeometrie               #
#                tabvar                  #
##--------------------------------------##
#    WxGeometrie
#    Dynamic geometry, graph plotter, and more for french mathematic teachers.
#    Copyright (C) 2005-2007  Nicolas Pourcelot
#
#    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 2 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 St, Fifth Floor, Boston, MA  02110-1301  USA

import mathlib
import mathlib.universal_functions as maths
import math
import param
import sympy
oo = maths.oo = sympy.oo
nan = sympy.nan
import pylib
import re

#~ try:
    #~ maths.num_oo = float(mathlib.array(1.)/0.)
#~ except ZeroDivisionError:
    #~ if param.debug:
        #~ print_error()
    #~ maths.num_oo = maths.oo

import numpy
maths.num_oo = numpy.inf
maths.pi = math.pi
maths.e = math.e

import LIB
import param


def traduire_latex(expression):
    return LIB.parsers.traduire_formule(  expression,
                                            fonctions = [key for key, obj in maths.__dict__.items() if hasattr(obj, "__call__")],
##                                            variables = '[_A-Za-z][_A-Za-z0-9]*',
                                            OOo = False,
                                            LaTeX = True,
                                            changer_separateurs = True,
                                            separateurs_personnels = (',', ';'))


def convertir_en_latex(chaine):
    chaine = pylib.regsub("[ ]+", chaine, " ") # inutile en LaTeX, mais ça peut simplifier certaines expressions regulieres

    # On traite maintenant le (délicat) cas des fractions, ie. 2/3, mais aussi (pi+3)/(5-e)
    securite = 10000
    while "/" in chaine:
        securite -= 1
        if securite < 0:
            raise RuntimeError, "Boucle probablement infinie."
        i = chaine.find("/")

        # analyse des caractères précédants, pour localiser le numérateur
        k = i
        parentheses = 0
        debut_numerateur = fin_numerateur = None # indices correspondants au début et à la fin du numérateur
        while k>0:
            k -= 1
            if chaine[k].isalnum():
                if fin_numerateur is None:
                    fin_numerateur = k
            elif chaine[k] == ")":
                if parentheses == 0:
                    fin_numerateur = k
                parentheses += 1
            elif chaine[k] == "(":
                parentheses -= 1
                if parentheses == 0:
                    debut_numerateur = k
                    break
            elif parentheses == 0 and fin_numerateur is not None:
                debut_numerateur = k+1
                break
        if debut_numerateur is None:
            debut_numerateur = 0
        assert fin_numerateur is not None, "Numerateur introuvable"

        numerateur = chaine[debut_numerateur : fin_numerateur+1].strip()
        if numerateur[0] == "(":
            numerateur = numerateur[1:-1]


        # analyse des caractères suivants, pour localiser le dénominateur
        k = i
        parentheses = 0
        debut_denominateur = fin_denominateur = None # indices correspondants au début et à la fin du numérateur

        while k < len(chaine) - 1:
            k += 1
            if chaine[k].isalnum():
                if debut_denominateur is None:
                    debut_denominateur = k
            elif chaine[k] == "(":
                if parentheses == 0:
                    debut_denominateur = k
                parentheses += 1
            elif chaine[k] == ")":
                parentheses -= 1
                if parentheses == 0:
                    fin_denominateur = k
                    break
            elif parentheses == 0 and debut_denominateur is not None:
                fin_denominateur = k-1
                break
        if fin_denominateur is None:
           fin_denominateur = len(chaine)  - 1

        assert debut_denominateur is not None, "Denominateur introuvable"

        denominateur = chaine[debut_denominateur : fin_denominateur+1].strip()
        if denominateur[0] == "(":
            denominateur = denominateur[1:-1]

        # remplacement de la fraction python par une fraction LaTeX
        chaine = chaine[:debut_numerateur] + "\\frac{" + numerateur + "}{" + denominateur + "}" + chaine[fin_denominateur+1:]

    # Autres remplacements :
    chaine = pylib.regsub("(?<!\\w)pi(?!\\w)", chaine, "\\\\pi")
    chaine = pylib.regsub("(?<!\\w)oo(?!\\w)", chaine, "\\\\infty")
    chaine = pylib.regsub("(?<!\\w)e(?!\\w)", chaine, "\\\\mathrm{e}")
    chaine = pylib.regsub("(?<!\\w)sin(?!\\w)", chaine, "\\\\sin")
    chaine = pylib.regsub("(?<!\\w)cos(?!\\w)", chaine, "\\\\cos")
    chaine = pylib.regsub("(?<!\\w)tan(?!\\w)", chaine, "\\\\tan")
    chaine = pylib.regsub("(?<!\\w)ln(?!\\w)", chaine, "\\\\ln")
    chaine = pylib.regsub("(?<!\\w)exp(?!\\w)", chaine, "\\\\exp")

    chaine = chaine.replace("**", "^").replace("*", " ")

    return "$" + chaine + "$" # premiere ligne : la variable


def test_parentheses(chaine):
    u"Retourne True si le parenthésage est correct, False sinon."
    count = 0
    n = 0
    k = 0
    while count >= 0:
        k += 1
        i = chaine.find('(', n)
        j = chaine.find(')', n)
        if i == -1:
            n = j
        elif j == -1:
            n = i
        else:
            n = min(i, j)
        if n == -1:
            break
        parenthese = chaine[n]
        assert parenthese in '()'
        count += (1 if parenthese == '(' else -1)
        n += 1
    return not count




def tabvar(chaine = "", derivee = True):
    u"""Indiquer les variations de la fonction.

Exemples :
f: (-oo;3) << (1;2;0) << (3;+oo|-oo) << (5;2) >> (+oo;-oo)
\\sqrt{x};\\sqrt'{x}: 0;0;| << +oo;+oo"""

    chaine_originale = chaine = chaine.strip()

    chaine = chaine.replace("-oo", "-\\infty").replace("+oo", "+\\infty")

    #ligne_variable = ligne_derivee = ligne_fonction = ""

    liste = chaine.split(":", 1)
    if len(liste) == 1 or len(liste[0].strip()) == 0:
        ligne_variable = "x"
        ligne_derivee = "f'(x)"
        ligne_fonction = "f"

    else:
        legende, chaine = liste
        legende = legende.split(";")

        if len(legende) > 1:
            ligne_variable = legende[0].strip()
            ligne_fonction = legende[1].strip()

            if len(legende) > 2:
                ligne_derivee = legende[2].strip()
            else:
                deb = ligne_fonction.find("(")
                if deb == -1:
                    ligne_derivee = ligne_fonction[:].strip() + "'(" + ligne_variable + ")"
                else:
                    ligne_derivee = ligne_fonction[:deb].strip() + "'(" + ligne_variable + ")"

        else: # un seul argument pour la legende: c'est alors la fonction
            ligne_fonction = legende[0].strip()
            deb = ligne_fonction.find("(")
            fin = ligne_fonction.find(")")
            if deb == -1:
                ligne_variable = "x"
                ligne_derivee = ligne_fonction + "'(x)"
            else:
                ligne_variable = ligne_fonction[deb+1:fin].strip()
                ligne_derivee = ligne_fonction[:deb].strip() + "'(" + ligne_variable + ")"




    # on découpe la chaîne, en une suite contenant soit les valeurs de x, f(x) (et éventuellement f'(x)), 
    # soit le sens de variation entre ces valeurs.
    # ex: "-oo;3 << 1;2 >> 3;-oo|+oo << 5;2 << +oo;+oo" devient 
    # ["-oo;3", "<<", "1;2", ">>", "3;-oo|+oo", "<<", "5;2", "<<", "+oo;+oo"]

    sequence = re.split("(>>|<<|==)", chaine.strip())
    
    if not sequence[0]:     
        # en l'absence d'indication, x varie de -oo...
        sequence[0] = "-\\infty;"
    if not sequence[-1]:    
        # ... à +oo
        sequence[-1] = "+\\infty;"

    def formater(chaine):
        chaine = chaine.strip()
        if chaine not in ("<<", ">>", "==") and ";" not in chaine:
            if chaine[0] == '(' and chaine[-1] == ')' and test_parentheses(chaine[1:-1]):
                chaine = chaine[1:-1]
            chaine += ";" # il faut au minimum un ";" pour indiquer l'absence de valeur
        return chaine

    sequence = [formater(elt) for elt in sequence]

    # On effectue un premier balayage uniquement pour detecter les niveaux.
    niveaux = [] # chaque element de la liste correspond a une portion de tableau de variation comprise entre deux valeurs interdites.
    # A chacune de ces portions va correspondre un doublon (niveau minimal atteint, niveau maximal atteint) qu'on ajoute a la liste.
    niveau = niveau_minimum = niveau_maximum = 0
    for elt in sequence:
        if ";" in elt and "|" in elt.split(";")[1]: # presence d'une valeur interdite
            niveaux.append((niveau_minimum, niveau_maximum))
            niveau = niveau_minimum = niveau_maximum = 0
        else:
            if elt == "<<":
                niveau += 1
            elif elt == ">>":
                niveau -= 1
            if niveau < niveau_minimum:
                niveau_minimum = niveau
            if niveau > niveau_maximum:
                niveau_maximum = niveau
    niveaux.append((niveau_minimum, niveau_maximum))
    ecart_maximal = max(val[1] - val[0] for val in niveaux)

    # L'environnement tabvar ne permet pas de positionner un texte entre deux lignes.
    # Si, dans la 3e partie du tableau (la fonction elle-même),
    # le nombre de lignes (c-à-d. ecart_maximal+1) est impair,
    # on décale le texte légèrement vers le haut pour le centrer verticalement (via raisebox).
    if ecart_maximal%2:
        ligne_fonction = "\\niveau{" + str((ecart_maximal+2)//2) +"}{" + str(ecart_maximal+1) + "}\\raisebox{0.5em}{$" + ligne_fonction + "$}"
    else:
        ligne_fonction = "\\niveau{" + str((ecart_maximal+2)//2) +"}{" + str(ecart_maximal+1) + "}" + ligne_fonction

    #print "niveaux: ", niveaux
    nombre_colonnes = 0
    portion = 0 # indique la derniere portion traitee (les portions sont delimitees par les bornes de l'ensemble de definition et les valeurs interdites)
    debut = True

    # Deuxieme et dernier balayage :
    # on parcourt maintenant la liste pour construire colonne par colonne le tableau de variations.
    for i in xrange(len(sequence)):
        # on justifie apres chaque etape, ce qui rend une eventuelle relecture du tableau plus agreable
        n = max(len(ligne_variable), len(ligne_derivee), len(ligne_fonction))
        ligne_variable = ligne_variable.ljust(n)
        ligne_derivee = ligne_derivee.ljust(n)
        ligne_fonction = ligne_fonction.ljust(n)

        ligne_variable += "&"
        if debut:
            debut = False
            ligne_fonction += "&\\niveau{" + str(1-niveaux[portion][0]) +"}{" + str(ecart_maximal+1) + "}"
        else:
            ligne_fonction += "&"
        ligne_derivee += "&"

        elt = sequence[i]
        if elt in (">>", "<<", "=="):  # il s'agit d'une variation
            nombre_colonnes += 1
            #ligne_variable += " "
            if elt == "<<":
                ligne_derivee += "+"
                ligne_fonction += "\\croit"
            elif elt == ">>":
                ligne_derivee += "-"
                ligne_fonction += "\\decroit"
            else:
                ligne_derivee += "0"
                ligne_fonction += "\\constante"

        else: # il s'agit des valeurs entre deux variations
            valeurs = elt.split(";") 
            # valeurs = x, f(x), et eventuellement f'(x).
            # Si f(x) n'est pas defini (valeur interdite), il y a (en general) une valeur-double pour f(x) :
            # les limites a gauche et a droite, separees par un "|". (Idem pour f'(x)).
            
            if (valeurs[0].count('(') - valeurs[0].count(')') == 1 
                    and valeurs[-1].count(')') - valeurs[-1].count('(') == 1
                    and valeurs[0][0] == '(' 
                    and valeurs[-1][-1] == ')'
                    ):
                valeurs[0] = valeurs[0][1:-1]
                
            
            largeur = max(("|" in val and 3 or 1) for val in valeurs) 
            # 3 si x est une valeur interdite pour f ou f' (ie. une valeur contient un "|"), 1 sinon.

            if largeur == 3: # x est une valeur interdite pour f(x) ou f'(x)
                ligne_variable += " &" + valeurs[0] + "& "

                vals_fonc = valeurs[1].split("|")
                if len(vals_fonc) == 2: # x est une valeur interdite pour f(x)
                    portion += 1 # on change de portion
                    ligne_fonction += vals_fonc[0] + "&\\dbarre&" + "\\niveau{" + str(1-niveaux[portion][0]) +"}{" + str(ecart_maximal+1) + "}" + vals_fonc[1]
                else:
                    ligne_fonction += " &" + vals_fonc[0] + "&"

                if len(valeurs) < 3: # le nombre derive n'est pas specifie
                    valeurs.append("|") # si la fonction n'est pas definie en x, sa derivee non plus

                vals_deriv = valeurs[2].split("|")
                if len(vals_deriv) == 2:
                    ligne_derivee += vals_deriv[0] + "&\\dbarre&" + vals_deriv[1]
                else:
                    ligne_derivee += " &" + vals_deriv[0] + "&"

            else: # x n'est pas une valeur interdite
                ligne_variable += valeurs[0]
                ligne_fonction += valeurs[1]

                if len(valeurs) < 3: # le nombre derive n'est pas specifie
                    if 0 < i < len(sequence)-1 and sequence[i-1] != sequence[i+1]: # changement de sens de variation en x
                        valeurs.append("0") # la derivee s'annule donc
                    else:
                        valeurs.append(" ")
                ligne_derivee += valeurs[2]


            nombre_colonnes += largeur



    code = "\\[\\begin{tabvar}{|C|" + nombre_colonnes*"C" + "|}\n\\hline\n"
    code += ligne_variable + "\\\\\n"

    if derivee:
        code += "\\hline\n" + ligne_derivee + "\\\\\n"

    code += "\\hline\n" + ligne_fonction + "\\\\\n"

    code += "\\hline\n\\end{tabvar}\\]\n%" + chaine_originale + "\n"

    return code




# exemple: x;sin(x)::-5;5;0.1:0.01 (variable;expression:valeur initiale;valeur finale;pas:precision d'arrondi).
# exemple: x;h(x):sin(x)+1:-5;0;0.5|0;3;1:0.01 (variable;expression:valeur initiale;valeur finale;pas:precision d'arrondi).

def tabval(chaine = ""):
    u"""Syntaxe:
variable;fonction:expression:valeur initiale;valeur finale;pas:precision d'arrondi

Exemples:
x;\\sin(x)::-5;5;0.1:0.01
x;h(x):sin(x)+1:-5;0;0.5|0;3;1:0.01"""

    chaine_originale = chaine = chaine.strip()
    sequence = chaine.split(":")



    legende = sequence[0].split(";")
    fonction = legende[-1].strip()
    if fonction == "":
        fonction = "f(x)"
    if len(legende) == 1: # on essaie (sommairement) de detecter la variable (en principe, elle est entre parentheses)
        deb = fonction.find("(")
        fin = fonction.find(")")
        if deb == -1:
            variable = "x"
        else:
            variable = fonction[deb+1:fin].strip()
    else:
        variable = legende[0].strip()

    expression = sequence[1].strip()
    if expression == "":
        expression = fonction

    intervalles = sequence[2].split("|")
    valeurs_variable = []
    for intervalle in intervalles:
        intervalle = intervalle.split(";")
        if len(intervalle) == 1:
            valeur_initiale = 0
            valeur_finale = eval(intervalle[0], maths.__dict__)
            pas = 1
        else:
            valeur_initiale = float(eval(intervalle[0], maths.__dict__))
            valeur_finale = float(eval(intervalle[1], maths.__dict__))
            if len(intervalle) == 2:
                pas = 1
            else:
                pas = float(eval(intervalle[2], maths.__dict__))
        nouvelles_valeurs = [x for x in mathlib.pylab.arange(valeur_initiale, valeur_finale, pas)] + [valeur_finale]
        if valeurs_variable and valeurs_variable[-1] == nouvelles_valeurs[0]:
            valeurs_variable.pop()
        valeurs_variable += nouvelles_valeurs

    if len(sequence) == 4:
        precision = float(eval(sequence[3], maths.__dict__))
    else:
        precision = 0.01
    nbr_colonnes = len(valeurs_variable) + 1

    code_variable = "$" + variable + "$"
    code_expression = "$" + fonction + "$"

    expression = traduire_latex(expression)

    for val in valeurs_variable: # on construit le tableau colonne par colonne
        n = max(len(code_variable), len(code_expression))
        code_variable = code_variable.ljust(n) # on justifie avant chaque nouvelle colonne (le code LaTeX sera plus agreable a lire !)
        code_expression = code_expression.ljust(n)

        code_variable += "&$\\nombre{" + str(val).replace(".", ",") + "}$"
        try:
            dict = maths.__dict__.copy()
            dict.update({variable: val})
            evaluation = eval(expression, dict)
            if evaluation >= maths.num_oo:
                code_expression += "&$\\times$"
            elif evaluation <= -maths.num_oo:
                code_expression += "&$\\times$"
            else:
                code_expression += "&$\\nombre{" + str(precision*round(evaluation/precision)).replace(".", ",") + "}$"
        except:
            LIB.print_error()
            code_expression += "&$\\times$"

    code = "\\begin{center}\n\\begin{tabular}{|" + nbr_colonnes*"c|" + "}\n\\hline\n"
    code += code_variable + "\\\\\n"
    code += "\\hline\n"
    code += code_expression + "\\\\\n"
    code += "\\hline\n\\end{tabular}\n\\end{center}\n%" + chaine_originale + "\n"
    return code











def tabsign(chaine = "", cellspace = False):
    u"""Indiquer ligne par ligne le signe de chaque facteur.
La dernière ligne (produit ou quotient) est générée automatiquement.

Exemples:
x:-pi;pi //  sin(x):-pi -- 0 ++ pi //  !cos(x):-- -pi/2 ++ pi/2 -- // tan(x)
x:-2;2 // x+1:-- -1 ++ // !x-1:-- 1 ++

Le point d'exclamation avant une expression signifie qu'elle correspond à un dénominateur."""

    chaine_originale = chaine = chaine.strip()
    chaine = chaine.replace("-oo", r"-\infty").replace("+oo", r"+\infty").replace('//', '\n').replace(r'\\', '\n')
    
    lignes = [ligne.strip() for ligne in chaine.split('\n') if ligne.strip()]

    # 'resultat' est la dernière ligne, sauf si elle contient ':'
    # (Dans ce cas, 'resultat' sera généré automatiquement plus tard, à partir des autres lignes).
    resultat = (lignes.pop() if ':' not in lignes[-1] else '')

    ligne_variable = lignes.pop(0)
    print lignes
    if ":" in ligne_variable:
        variable, donnees_variable = ligne_variable.split(":")
    elif ";" in ligne_variable:
        variable = ""
        donnees_variable = ligne_variable
    else:
        variable = ligne_variable
        donnees_variable = ""

    variable = variable.strip()
    if ';' not in donnees_variable:
        donnees_variable += ';'
        
    xmin, xmax = donnees_variable.split(';')
    # Par défaut, la variable varie entre -oo et +oo
    xmin = xmin.strip() if xmin.strip() else r'-\infty'
    xmax = xmax.strip() if xmax.strip() else r'+\infty'

    # Séparation de la légende et des autres données pour chaque ligne
    expressions = []
    donnees_expressions = []
    for ligne in lignes:
        expression, signe_expression = ligne.split(":")
        expressions.append(expression.strip())
        donnees_expressions.append(signe_expression.strip())

    # Au besoin, on génère la légende de la dernière ligne (c.à-d. le résultat - produit ou quotient)
    if resultat == "":
        numerateur = []
        denominateur = []
        for expression in expressions:
            if expression[0] == "!":
                liste = denominateur
                expression = expression[1:]
            else:
                liste = numerateur
            if "+" in expression or "-" in expression[1:]: 
                # il s'agit d'une somme ou d'une difference, il faut donc des parentheses
                liste.append("(" + expression + ")")
            else:
                liste.append(expression)
        if denominateur:
            if len(denominateur) == 1 and denominateur[0][0] == "(" and denominateur[0][-1] == ")":
                denominateur[0] = denominateur[0][1:-1]
            if len(numerateur) == 1 and numerateur[0][0] == "(" and numerateur[0][-1] == ")":
                numerateur[0] = numerateur[0][1:-1]
            if not numerateur:
                numerateur = ["1"]
            resultat = "\\frac{%s}{%s}" %("".join(numerateur), "".join(denominateur))
        else:
            resultat = "".join(numerateur)

    # Cas particulier : 'produit' de 1 seul élément -> inutile d'afficher une ligne résultat
    if len(expressions) == 1 and not expressions[0].startswith("!"):
        afficher_resultat = False
    else:
        afficher_resultat = True

    # Au besoin, on génère la légende de la première ligne (c.à-d. la variable)
    if not variable:
        # On cherche les lettres isolées
        m = re.search('(?<![A-Za-z])[A-Za-z](?![A-Za-z])', resultat)
        # Si on n'en trouve pas, la variable sera 'x'
        variable = m.group() if m else 'x'

    # On récupère la liste de toutes les valeurs de x
    valeurs = set() # va contenir toutes les valeurs numeriques
    correspondances = {} # servira à retrouver le code (LaTeX notamment) à partir de la valeur numérique.
        
    # On convertit xmin et xmax en valeurs numériques
    for xm in (xmin, xmax):
        xm_num = eval(traduire_latex(xm), maths.__dict__)
        valeurs.add(xm_num)
        correspondances[xm_num] = xm
    
    # Idem pour toutes les autres valeurs
    for i, donnees in enumerate(donnees_expressions):
        donnees = re.split(r'(\+\+|--|00)', donnees)
        for j, valeur in enumerate(donnees):
            valeur = valeur.strip()
            if valeur not in ('++', '--', '00', ''):            
                # On préformate les donnees en vue d'un traitement ulterieur. 
                # Ex: '-5 ++ (1;|) -- 4' devient [(-5, "0"), "+", (1, "|"), "-", (4, "0")].
                if valeur[0] == '(' and valeur[-1] == ')' and test_parentheses(valeur[1:-1]):
                    valeur = valeur[1:-1]
                vals = [val.strip() for val in valeur.split(';')]
                if len(vals) == 1:
                    if vals[0].startswith('!'):
                        vals[0] = vals[0][1:]
                        vals.append('|')
                    else:
                        vals.append('0')
                else:
                    vals[1] = '$' + vals[1] + '$'
                valeur_num = vals[0] = eval(traduire_latex(valeur), maths.__dict__)
                valeurs.add(valeur_num)
                correspondances[valeur_num] = valeur
                donnees[j] = vals
        print donnees                
        donnees_expressions[i] = donnees
                
    valeurs = sorted(valeurs)


    indices_denominateurs = [] 
    # indique que les lignes correspondantes se trouvent au denominateur

    # On initialise le code LaTeX de chaque ligne avec sa légende.
    # NB: la liste 'lignes' contiendra le code LaTeX pour chaque ligne.
    n = max(len(chaine) for chaine in expressions + [variable, resultat])
    lignes = [convertir_en_latex(variable)] 
    i = 1
    for expression in expressions:
        if expression[0] == "!":
            expression = expression[1:]
            indices_denominateurs.append(i)
        lignes.append(convertir_en_latex(expression))
        i += 1
    lignes.append(convertir_en_latex(resultat))

    # On justifie le texte de la première colonne pour que le code LaTeX généré soit plus lisible.
    n = max(len(texte) for texte in lignes) + 1
    for i, ligne in enumerate(lignes):
        lignes[i] = ligne.ljust(n)

    def latex_signe(val):
        if val == nan:
            return '||'
        elif val > 0:
            return '+'
        elif val < 0:
            return '--'
        else:
            return '0'

    dict_signes = {'++': 1, '--': -1, '00': 0}


    # On génère maintenant le code LaTeX correspondant au tableau proprement dit.
    # On procède colonne par colonne.
    nbr_colonnes = 2*len(valeurs)
    for co in xrange(1, nbr_colonnes):
        colonne = ['' for i in xrange(len(donnees_expressions) + 2)]
        
        # Première ligne (valeurs de la variable)
        if co%2:
            # Il s'agit d'une valeur (et non d'un signe + ou -)
            valeur_num = valeurs[(co - 1)//2]
            valeur = correspondances[valeur_num]

            # On applique un formatage LaTeX à certaines expression :
            colonne[0] = convertir_en_latex(valeur)

        signe = 1 
        # (1 pour positif, -1 pour négatif, nan pour valeur interdite -> cf. latex_signe())

        # Autres lignes
        for li, donnees in enumerate(donnees_expressions):
            # À quel endroit de la ligne sommes-nous ?
            valeurs_precedentes = [k for k, val in enumerate(donnees) if not isinstance(val, basestring) and val[0]<=valeur_num]
            if valeurs_precedentes:
                # position de la dernière valeur de la ligne
                position = valeurs_precedentes[-1]
                if co%2: # on est au niveau d'une valeur
                    if donnees[position][0] == valeur_num:
                        if donnees[position][1] == '|':
                            colonne[li + 1] = '||'
                            signe = nan
                        else:
                            colonne[li + 1] = donnees[position][1]
                            signe *= 0
                        if li + 1 in indices_denominateurs:
                            signe = nan
                else: # on est entre deux valeurs
                    signe_ = dict_signes[donnees[position + 1]]
                    colonne[li + 1] += latex_signe(signe_) # le signe qui est juste apres la derniere valeur
                    signe *= signe_
            else: # on est au debut
                if co%2 == 0: # on est entre deux valeurs
                    print donnees[0]
                    signe_ = dict_signes[donnees[1]]
                    colonne[li + 1] += latex_signe(signe_)
                    signe *= signe_

        # Dernière ligne : signe du produit ou du quotient
        colonne[-1] += latex_signe(signe)

        # On centre le texte dans la colonne pour que le code LaTeX généré soit plus lisible.
        n = max(len(texte) for texte in colonne) + 2
        for i, ligne in enumerate(colonne):
            colonne[i] = ligne.center(n)

        for num, text in enumerate(colonne):
            lignes[num] += '&' + text


    # Cas particulier : 'produit' de 1 seul élément
    if not afficher_resultat:
        lignes.pop()

    # Et on rassemble les lignes
    if cellspace:
        code = "\\begin{center}\n\\begin{tabular}{|Sc|" + (nbr_colonnes - 1)*"Sc" + "|}\n\\hline\n"
    else:
        code = "\\begin{center}\n\\begin{tabular}{|c|" + (nbr_colonnes - 1)*"c" + "|}\n\\hline\n"
    for ligne in lignes:
        code += ligne + "\\\\\n\\hline\n"
    code += "\\end{tabular}\n\\end{center}\n%" + chaine_originale + "\n"
    return code




#2x+1:-;-1/2;+#-3x+2:-;2/3;+
