private List<ExpressionAtom> parseInputPolynomial(String inputExpression) {
    inputExpression = identifyUnaryMinuses(inputExpression);
    inputExpression = insertMultiplicationSigns(inputExpression);

    List<ExpressionAtom> inputExpressionTokens = new ArrayList<ExpressionAtom>();

    char[] inputChars = inputExpression.toCharArray();
    for (int i = 0; i < inputChars.length; ++i) {
      if (isOperator(inputChars[i]) || inputChars[i] == '%') {
        inputExpressionTokens.add(
            new ExpressionAtom(String.valueOf(inputChars[i]), AtomType.OPERATOR, 1));
      } else {
        int lastIndex = inputExpressionTokens.size() - 1;
        if (lastIndex >= 0
            && inputExpressionTokens.get(lastIndex).getAtomType() == AtomType.OPERAND) {
          ExpressionAtom lastElement = inputExpressionTokens.remove(lastIndex);
          if (Character.isDigit(inputChars[i])) {
            lastElement.setCoefficient(
                lastElement.getCoefficient() * 10 + Character.getNumericValue(inputChars[i]));
          } else {
            lastElement.setVariablesOrOperator(
                lastElement.getVariablesOrOperator() + String.valueOf(inputChars[i]));
          }
          inputExpressionTokens.add(lastElement);
        } else if (Character.isDigit(inputChars[i])) {
          inputExpressionTokens.add(
              new ExpressionAtom("", AtomType.OPERAND, Character.getNumericValue(inputChars[i])));
        } else {
          inputExpressionTokens.add(
              new ExpressionAtom(String.valueOf(inputChars[i]), AtomType.OPERAND, 1));
        }
      }
    }
    return inputExpressionTokens;
  }
  private static boolean isTopwithHigerPrecedence(ExpressionAtom peek, ExpressionAtom token) {
    if (!(peek.getAtomType() == AtomType.OPERATOR)
        || peek.getVariablesOrOperator().equals("(")
        || peek.getVariablesOrOperator().equals(")")) return false;

    // if(peek.getVariablesOrOperator().equals("%")) return true ;
    Operators op1 = operatorsMap.get(peek.getVariablesOrOperator());
    Operators op2 = operatorsMap.get(token.getVariablesOrOperator());

    if (op2.getAssociativity() == LEFT_ASSOCIATIVITY && op1.getPrecedence() >= op2.getPrecedence())
      return true;
    else if (op1.getPrecedence() >= op2.getPrecedence()) return true;
    else return false;
  }
  private List<ExpressionAtom> simplifyAndNormalize(List<ExpressionAtom> evaluatedExpression) {

    for (int x = 0; x < evaluatedExpression.size(); x++) {
      evaluatedExpression
          .get(x)
          .setVariablesOrOperator(
              new StringBuilder(evaluatedExpression.get(x).getVariablesOrOperator())
                  .reverse()
                  .toString());
      String newVar = fixVariablesOrOperator(evaluatedExpression.get(x).getVariablesOrOperator());
      evaluatedExpression.get(x).setVariablesOrOperator(newVar);
    }

    for (int x = 0; x < evaluatedExpression.size() - 1; x++) {
      ExpressionAtom first = evaluatedExpression.get(x);
      for (int y = x + 1; y < evaluatedExpression.size(); y++) {
        ExpressionAtom second = evaluatedExpression.get(y);
        if (first.getVariablesOrOperator().equals(second.getVariablesOrOperator())) {
          first.setCoefficient(first.getCoefficient() + second.getCoefficient());
          evaluatedExpression.remove(second);
        }
      }
    }

    return evaluatedExpression;
    /*
     * TODO: Write code here to operate on the List<ExpressionAtom> object obtaind from
     * 'evaluateExpression'. Specifically, ensure that you combine terms with same variables and
     * modify coefficients appropriately.
     */

  }
      @Override
      public List<ExpressionAtom> evaluate(
          List<ExpressionAtom> loperands, List<ExpressionAtom> roperands) {
        List<ExpressionAtom> match = match(loperands);
        while (match != null) {
          ExpressionAtom loperand = match.get(0);
          ExpressionAtom roperand = match.get(1);
          String degree = roperand.getVariablesOrOperator();
          int coefficient = loperand.getCoefficient() + roperand.getCoefficient();
          ExpressionAtom sum = new ExpressionAtom(degree, AtomType.OPERAND, coefficient);
          loperands.remove(loperand);
          loperands.remove(roperand);
          loperands.add(sum);

          match = match(loperands);
        }

        return loperands;
      }
 @Override
 public List<ExpressionAtom> evaluate(
     List<ExpressionAtom> loperands, List<ExpressionAtom> roperands) {
   if (roperands == null) {
     List<ExpressionAtom> product = new ArrayList<ExpressionAtom>();
     for (int x = 0; x < loperands.size(); x++) {
       if (product.size() == 0) {
         product.add(loperands.get(x));
       } else {
         ExpressionAtom atom = product.get(0);
         atom.setCoefficient(atom.getCoefficient() * loperands.get(x).getCoefficient());
         String var =
             incrementDegree(
                 loperands.get(x).getVariablesOrOperator(), atom.getVariablesOrOperator());
         atom.setVariablesOrOperator(var);
       }
     }
     return product;
   } else {
     return multiple(loperands, roperands);
   }
 }
  public static List<ExpressionAtom> multiple(
      List<ExpressionAtom> loperands, List<ExpressionAtom> roperands) {
    List<ExpressionAtom> product = new ArrayList<ExpressionAtom>();
    for (int left = 0; left < loperands.size(); left++) {
      for (int right = 0; right < roperands.size(); right++) {
        ExpressionAtom atomLeft = loperands.get(left);
        ExpressionAtom atomRight = roperands.get(right);

        int coefficient = atomLeft.getCoefficient() * atomRight.getCoefficient();
        String leftVar = atomLeft.getVariablesOrOperator();
        String rightVar = atomRight.getVariablesOrOperator();
        String var = incrementDegree(leftVar, rightVar);
        product.add(new ExpressionAtom(var, AtomType.OPERATOR, coefficient));
      }
    }
    return product;
  }
 public static List<ExpressionAtom> match(List<ExpressionAtom> operands) {
   List<ExpressionAtom> binomial = new ArrayList<ExpressionAtom>();
   for (int l = 0; l < operands.size() - 1; l++) {
     ExpressionAtom left = operands.get(l);
     if (left.getAtomType() == AtomType.OPERATOR) continue;
     for (int r = l + 1; r < operands.size(); r++) {
       ExpressionAtom right = operands.get(r);
       if (right.getAtomType() == AtomType.OPERATOR) continue;
       else {
         if (right.getVariablesOrOperator().equals(left.getVariablesOrOperator())) {
           binomial.add(left);
           binomial.add(right);
           return binomial;
         }
       }
     }
   }
   return null;
 }
  public void processOperator(ListRepresentation listExpression) {
    String operator = listExpression.getNodeVal().getVariablesOrOperator();
    if (computationStack.isEmpty()) {
      List<List<ExpressionAtom>> all = new ArrayList<List<ExpressionAtom>>();
      while (!expressionQueue.isEmpty()) {
        all.add(expressionQueue.dequeue());
      }
      List<ExpressionAtom> main = null;
      if (operator.equals("*")) {
        for (int x = 0; x < all.size() - 1; x++) {
          if (x + 1 >= all.size()) {
            System.out.println("ERROR @ Multiplicaiton NO DATA");
          } else {
            if (main == null) {
              main = operatorsMap.get(operator).evaluate(all.get(x), all.get(x + 1));
            } else {
              main = operatorsMap.get(operator).evaluate(main, all.get(x + 1));
            }
          }
        }
        expressionQueue.enqueue(main);
      } else if (operator.equals("+")) {
        main = new ArrayList<ExpressionAtom>();
        for (int x = 0; x < all.size(); x++) {
          for (int y = 0; y < all.get(x).size(); y++) {
            main.add(all.get(x).get(y));
          }
        }
        expressionQueue.enqueue(operatorsMap.get(operator).evaluate(main, null));
      }
    }

    while (!computationStack.isEmpty()) {
      if (computationStack.size() == 1) {
        List<ExpressionAtom> prev = expressionQueue.dequeue();
        List<ExpressionAtom> loperands = new ArrayList<ExpressionAtom>();
        while (!prev.isEmpty()) {
          loperands.add(prev.get(0));
          prev.remove(0);
        }
        List<ExpressionAtom> roperands = new ArrayList<ExpressionAtom>();
        while (!computationStack.isEmpty()) {
          roperands.add(computationStack.pop());
        }
        if (operator.equals("^")) {
          ExpressionAtom degree = roperands.get(0);
          List<ExpressionAtom> copy = null;
          for (int x = 1; x < degree.getCoefficient(); x++) {
            if (x == 1) {
              copy = operatorsMap.get(operator).evaluate(loperands, loperands);
            } else {
              operatorsMap.get(operator).evaluate(copy, loperands);
            }
          }
          expressionQueue.enqueue(copy);
        } else {
          expressionQueue.enqueue(operatorsMap.get(operator).evaluate(loperands, roperands));
        }

      } else {
        List<ExpressionAtom> loperands = new ArrayList<ExpressionAtom>();
        while (!computationStack.isEmpty()) {
          loperands.add(computationStack.pop());
        }
        if (operator.equals("^")) {
          int degree = loperands.get(0).getCoefficient();
          List<ExpressionAtom> main = new ArrayList<ExpressionAtom>();
          for (int ope = 1; ope < loperands.size(); ope++) {
            main.add(loperands.get(ope));
          }

          List<ExpressionAtom> copy = null;
          for (int c = 1; c < degree; c++) {
            if (c == 1) {
              copy = operatorsMap.get(operator).evaluate(main, null);
            } else {
              copy = operatorsMap.get(operator).evaluate(main, copy);
            }
          }

          if (listExpression.isNegative()) {
            List<ExpressionAtom> mult = new ArrayList<ExpressionAtom>();
            mult.add(new ExpressionAtom("", AtomType.OPERAND, -1));
            copy = operatorsMap.get("*").evaluate(copy, mult);
          }

          expressionQueue.enqueue(copy);
        } else {
          expressionQueue.enqueue(operatorsMap.get(operator).evaluate(loperands, null));
        }
      }
    }

    Utils.printExpression(expressionQueue.peek());
  }
  private ListRepresentation convertToListRepresentation() {
    SimpleQueue<ExpressionAtom> output = new SimpleQueue<ExpressionAtom>();
    SimpleStack<ExpressionAtom> stack = new SimpleStack<ExpressionAtom>();

    for (ExpressionAtom atom : infixExpression) {
      Utils.printAtom(atom);
      if (atom.getAtomType() == AtomType.OPERAND) {
        output.enqueue(atom);
      } else if (atom.getAtomType() == AtomType.OPERATOR
          && !atom.getVariablesOrOperator().equals("(")
          && !atom.getVariablesOrOperator().equals(")")) {
        while (!stack.isEmpty()) {
          ExpressionAtom peek = stack.peek();
          if (isTopwithHigerPrecedence(peek, atom)) {
            output.enqueue(stack.pop());
          } else break;
        }
        stack.push(atom);
      } else if (atom.getVariablesOrOperator().equals("(")) {
        stack.push(atom);
      } else if (atom.getVariablesOrOperator().equals(")")) {
        boolean isLeftFound = false;
        while (!stack.isEmpty()) {
          ExpressionAtom top = stack.pop();
          if (!top.getVariablesOrOperator().equals("(")) {
            output.enqueue(top);
          } else {
            isLeftFound = true;
            break;
          }
        }
        if (!isLeftFound) throw new RuntimeException("Parantheses are not balanced");
      }
    }

    while (!stack.isEmpty()) {
      ExpressionAtom top = stack.pop();
      if (top.getVariablesOrOperator().equals("(") || top.getVariablesOrOperator().equals(")")) {
        throw new RuntimeException("Parantheses are not balanced");
      }
      output.enqueue(top);
    }

    ListRepresentation temp = new ListRepresentation();
    temp.setNodeVal(new ExpressionAtom("", null, 0));
    SimpleStack<ListRepresentation> operands = new SimpleStack<ListRepresentation>();
    List<ListRepresentation> copy = new ArrayList<ListRepresentation>();

    System.out.println();

    while (!output.isEmpty()) {
      ExpressionAtom atom = output.dequeue();
      Utils.printAtom(atom);
      if (atom.getAtomType() == AtomType.OPERAND) {
        ListRepresentation operand = new ListRepresentation();
        operand.setNodeVal(atom);
        operands.push(operand);
      } else {
        if (atom.getVariablesOrOperator().equals("-")
            || atom.getVariablesOrOperator().equals("%")) {
          ListRepresentation peek = operands.peek();
          if (peek.operands.size() == 0) {
            peek.getNodeVal().setCoefficient(peek.getNodeVal().getCoefficient() * -1);
          } else {
            peek.setNegative(true);
          }

          if (atom.getVariablesOrOperator().equals("%")) {
            if (peek.operands.size() == 0) continue;
            else {
              continue;
            }
          }
          atom = new ExpressionAtom("+", AtomType.OPERATOR, 1);
        }
        ListRepresentation operator = new ListRepresentation();
        operator.setNodeVal(atom);

        ListRepresentation op = operands.pop();

        operator.operands.add(operands.pop());
        operator.operands.add(op);

        copy.add(operator);
        operands.push(operator);
        temp = operator;
      }
    }

    ListRepresentation cop = operands.pop();
    validate(cop, cop);
    listRepresentation = cop;

    return listRepresentation;
  }