# -*- coding: utf-8 -*-
import re

## TODO Gestion des signes qui se suivent ( 3+-5 ou 3*-5 )

def priorites(calcul, pre = "", post = "", solution = []):
    if not solution: solution = [calcul]
    recherche_parentheses = r"""
    ^(.*)                           #des calculs dans le groupe 0
    (                               #début du groupe 1
      \(                            #commence par une parenthèse ouvrante
      (?:                           #regroupement 0 (non groupe)
        [\+\-]?                     #un éventuel signe
        (?:                         #regroupement 1 (non groupe)
          \(                        #une parenthèse ouvrante
          [\+\-]?                   #un éventuel signe
          \d+\.?\d*(?:e[\+\-]\d+)?  #on cherche un nombre avec une éventuelle
                                    #partie décimale et un éventuel exposant
          \)                        #une parenthèse fermante
        |                           #ou
          \d+\.?\d*(?:e[\+\-]\d+)?  #on cherche un nombre avec une éventuelle
                                    #partie décimale et un éventuel exposant
        |                           #ou
          \w+                       #un littéral
        )                           #fin du regroupement 1
        [\+\-\*/]+                  #un opérateur
      )+                            #fin du regroupement 0 (présent au moins
                                    #un fois)
      [\+\-]?                     #un éventuel signe
      (?:                           #regroupement 0 (non groupe)
          \(                        #une parenthèse ouvrante
          [\+\-]?                   #un éventuel signe
          \d+\.?\d*(?:e[\+\-]\d+)?  #on cherche un nombre avec une éventuelle
                                    #partie décimale et un éventuel exposant
          \)                        #une parenthèse fermante
        |                           #ou
          \d+\.?\d*(?:e[\+\-]\d+)?  #on cherche un nombre avec une éventuelle
                                    #partie décimale et un éventuel exposant
        |                           #ou
        \w+                         #un littéral
      )                             #fin du regroupement 0 présent une seule fois
      \)                            #fini par une parenthèse fermante
    )                               #fin du groupe 1
    (.*)$                           #des calculs pour finir
    """
    test = re.search(recherche_parentheses, calcul, re.VERBOSE)
    while test:
        sous_calcul = test.groups()
        (calcul, solution) = priorites_operations(sous_calcul[1],
                                                  sous_calcul[0],
                                                  sous_calcul[2],
                                                  solution)
        calcul = solution[-1]
        test = re.search(recherche_parentheses, calcul, re.VERBOSE)
    calcul, solution = priorites_operations(calcul, pre, post, solution)
    return(solution)

def traite_operation(operateur, calcul, pre, post, solution):
    pattern = r"""
            (                   #groupe 0
                ^\(*                #le calcul est au début (aux parenthèses près)
                                    #les signes +/- font parti du groupe 2
            |                   #ou
                ^.*?[\+\-]?         #il y a des calculs avant, le 1e signe +/-
                                    #est un opérateur
            )                   #fin du groupe 0
            (                   #groupe 1
                (?:                 #regroupement 1 (non groupe)
                    [\+\-]?                 #un éventuel signe
                    \(                      #une parenthèse ouvrante
                    [\+\-]?                 #un éventuel signe
                    \d+\.?\d*(?:e[\+\-]\d+)? #on cherche un nombre avec une
                                            #éventuelle partie décimale et un
                                            #éventuel exposant
                    \)                     #une parenthèse fermante
                |                   #ou
                    [\+\-]?                 #un éventuel signe
                    \d+\.?\d*(?:e[\+\-]\d+)? #on cherche un nombre avec une
                                            #éventuelle partie décimale et un
                                            #éventuel exposant
                |                   #ou
                    \w+                     #un littéral
                )                   #fin du regroupement 1
                {0}                 #opération
                (?:                 #regroupement 2 (non groupe)
                    [\+\-]?                 #un éventuel signe
                    \(                     #une parenthèse ouvrante
                    [\+\-]?                 #un éventuel signe
                    \d+\.?\d*(?:e[\+\-]\d+)? #on cherche un nombre avec une
                                            #éventuelle partie décimale et un
                                            #éventuel exposant
                    \)                     #une parenthèse fermante
                |                   #ou
                    [\+\-]?                 #un éventuel signe
                    \d+\.?\d*(?:e[\+\-]\d+)? #on cherche un nombre avec une
                                            #éventuelle partie décimale et un
                                            #éventuel exposant
                |                           #ou
                    \w+                     #un littéral
                )                   #fin du regroupement 2
            )                   #fin du groupe 1
            (.*?)$              #tout le reste
            """.format(operateur)
    test = re.search(pattern, calcul, re.VERBOSE)
    while test:
        sous_calcul = test.groups()
        sous_resultat = eval(sous_calcul[1])
        if (sous_calcul[0] and sous_calcul[0][-1] == '(') and \
           (sous_calcul[2][0] and sous_calcul[2][0] == ')') and \
           (post[:2] != '**' or sous_resultat > 0):
            #permet de supprimer les parenthèses
            solution.extend([pre +
                             sous_calcul[0][:-1] +
                             str(sous_resultat) +
                             sous_calcul[2][1:] +
                             post])
        else:
            solution.extend([pre +
                             sous_calcul[0] +
                             str(sous_resultat) +
                             sous_calcul[2] +
                             post])
        calcul = sous_calcul[0] + str(sous_resultat) + sous_calcul[2]
        test = re.search(pattern, calcul, re.VERBOSE)
    return (calcul, pre, post, solution)

def priorites_operations(calcul, pre = "", post = "", solution = []):
    calcul, pre, post, solution = traite_operation("\*\*", calcul, pre,
                                                   post, solution)
    calcul, pre, post, solution = traite_operation("[\*/]", calcul, pre,
                                                   post, solution)
    calcul, pre, post, solution = traite_operation("[\+\-]", calcul, pre,
                                                   post, solution)
    return (calcul, solution)

for element in priorites("(2-5)**2+(5-2)**3+((3*4+5)*2+3*(32-5*7)**2)*5+17*(12-3*5)"):
  print element 
  
#print priorites("((-(-1)+-2)++3)")
#print priorites("4-((-1+-2)+3)")
#print priorites('8-(-5*(2-4))')
#print priorites("1+2+3+4")
#print priorites("-3**+2")
#print priorites("9+8*7")
#print priorites("8+1.3e+2")
