protected GeoElement[] processConic(Equation equ) {
    double a = 0, b = 0, c = 0, d = 0, e = 0, f = 0;
    GeoElement[] ret = new GeoElement[1];
    GeoConic conic;
    String label = equ.getLabel();
    Polynomial lhs = equ.getNormalForm();

    boolean isExplicit = equ.isExplicit("y");
    boolean isSpecific = !isExplicit && (equ.isExplicit("yy") || equ.isExplicit("xx"));
    boolean isIndependent = lhs.isConstant();

    if (isIndependent) {
      a = lhs.getCoeffValue("xx");
      b = lhs.getCoeffValue("xy");
      c = lhs.getCoeffValue("yy");
      d = lhs.getCoeffValue("x");
      e = lhs.getCoeffValue("y");
      f = lhs.getCoeffValue("");
      conic = kernel.Conic(label, a, b, c, d, e, f);
    } else conic = kernel.DependentConic(label, equ);
    if (isExplicit) {
      conic.setToExplicit();
      conic.updateRepaint();
    } else if (isSpecific || conic.getType() == GeoConic.CONIC_CIRCLE) {
      conic.setToSpecific();
      conic.updateRepaint();
    }
    ret[0] = conic;
    return ret;
  }
 protected GeoElement[] processImplicitPoly(Equation equ) {
   GeoElement[] ret = new GeoElement[1];
   String label = equ.getLabel();
   Polynomial lhs = equ.getNormalForm();
   boolean isIndependent = !equ.isFunctionDependent() && lhs.isConstant();
   GeoImplicitPoly poly;
   GeoElement geo = null;
   if (isIndependent) {
     poly = kernel.ImplicitPoly(label, lhs);
     poly.setUserInput(equ);
     geo = poly;
   } else {
     geo = kernel.DependentImplicitPoly(label, equ); // might also return Line or Conic
     if (geo instanceof GeoUserInputElement) {
       ((GeoUserInputElement) geo).setUserInput(equ);
     }
   }
   ret[0] = geo;
   //		Application.debug("User Input: "+equ);
   ret[0].updateRepaint();
   return ret;
 }
  protected GeoElement[] processLine(Equation equ, boolean inequality) {
    double a = 0, b = 0, c = 0;
    GeoLine line;
    GeoElement[] ret = new GeoElement[1];
    String label = equ.getLabel();
    Polynomial lhs = equ.getNormalForm();
    boolean isExplicit = equ.isExplicit("y");
    boolean isIndependent = lhs.isConstant();

    if (isIndependent) {
      // get coefficients
      a = lhs.getCoeffValue("x");
      b = lhs.getCoeffValue("y");
      c = lhs.getCoeffValue("");
      line = kernel.Line(label, a, b, c);
    } else line = kernel.DependentLine(label, equ);

    if (isExplicit) {
      line.setToExplicit();
      line.updateRepaint();
    }
    ret[0] = line;
    return ret;
  }
  public GeoElement[] processEquation(Equation equ) throws MyError {
    //		Application.debug("EQUATION: " + equ);
    //		Application.debug("NORMALFORM POLYNOMIAL: " + equ.getNormalForm());

    try {
      equ.initEquation();
      // Application.debug("EQUATION: " + equ.getNormalForm());
      // check no terms in z
      checkNoTermsInZ(equ);

      if (equ.isFunctionDependent()) {
        return processImplicitPoly(equ);
      }

      // consider algebraic degree of equation
      // check not equation of eg plane
      switch (equ.degree()) {
          // linear equation -> LINE
        case 1:
          return processLine(equ, false);

          // quadratic equation -> CONIC
        case 2:
          return processConic(equ);

        default:
          // test for "y= <rhs>" here as well
          if (equ.getLHS().toString().trim().equals("y")) {
            Function fun = new Function(equ.getRHS());
            // try to use label of equation
            fun.setLabel(equ.getLabel());
            return processFunction(null, fun);
          }
          return processImplicitPoly(equ);
      }
    } catch (MyError eqnError) {
      eqnError.printStackTrace();

      // invalid equation: maybe a function of form "y = <rhs>"?
      String lhsStr = equ.getLHS().toString().trim();
      if (lhsStr.equals("y")) {
        try {
          // try to create function from right hand side
          Function fun = new Function(equ.getRHS());

          // try to use label of equation
          fun.setLabel(equ.getLabel());
          return processFunction(null, fun);
        } catch (MyError funError) {
          funError.printStackTrace();
        }
      }

      // throw invalid equation error if we get here
      if (eqnError.getMessage() == "InvalidEquation") throw eqnError;
      else {
        String[] errors = {"InvalidEquation", eqnError.getLocalizedMessage()};
        throw new MyError(app, errors);
      }
    }
  }
  public GeoElement[] processExpressionNode(ExpressionNode n) throws MyError {
    // command is leaf: process command
    if (n.isLeaf()) {
      ExpressionValue leaf = n.getLeft();
      if (leaf instanceof Command) {
        Command c = (Command) leaf;
        c.setLabels(n.getLabels());
        return cmdDispatcher.processCommand(c, true);
      } else if (leaf instanceof Equation) {
        Equation eqn = (Equation) leaf;
        eqn.setLabels(n.getLabels());
        return processEquation(eqn);
      } else if (leaf instanceof Function) {
        Function fun = (Function) leaf;
        fun.setLabels(n.getLabels());
        return processFunction(n, fun);
      } else if (leaf instanceof FunctionNVar) {
        FunctionNVar fun = (FunctionNVar) leaf;
        fun.setLabels(n.getLabels());
        return processFunctionNVar(n, fun);
      }
    }

    // ELSE:  resolve variables and evaluate expressionnode
    n.resolveVariables();
    eval = n.evaluate();
    boolean dollarLabelFound = false;

    ExpressionNode myNode = n;
    if (myNode.isLeaf()) myNode = myNode.getLeftTree();
    // leaf (no new label specified): just return the existing GeoElement
    if (eval.isGeoElement()
        && n.getLabel() == null
        && !(n.operation.equals(Operation.ELEMENT_OF))) {
      // take care of spreadsheet $ names: don't loose the wrapper ExpressionNode here
      // check if we have a Variable
      switch (myNode.getOperation()) {
        case $VAR_COL:
        case $VAR_ROW:
        case $VAR_ROW_COL:
          // don't do anything here: we need to keep the wrapper ExpressionNode
          // and must not return the GeoElement here
          dollarLabelFound = true;
          break;

        default:
          // return the GeoElement
          GeoElement[] ret = {(GeoElement) eval};
          return ret;
      }
    }

    if (eval.isBooleanValue()) return processBoolean(n, eval);
    else if (eval.isNumberValue()) return processNumber(n, eval);
    else if (eval.isVectorValue()) return processPointVector(n, eval);
    else if (eval.isVector3DValue()) return processPointVector3D(n, eval);
    else if (eval.isTextValue()) return processText(n, eval);
    else if (eval instanceof MyList) {
      return processList(n, (MyList) eval);
    } else if (eval instanceof Function) {
      return processFunction(n, (Function) eval);
    } else if (eval instanceof FunctionNVar) {

      return processFunctionNVar(n, (FunctionNVar) eval);
    }
    // we have to process list in case list=matrix1(1), but not when list=list2
    else if (eval instanceof GeoList && myNode.hasOperations()) {
      Application.debug("should work");
      return processList(n, ((GeoList) eval).getMyList());
    } else if (eval.isGeoElement()) {

      // e.g. B1 = A1 where A1 is a GeoElement and B1 does not exist yet
      // create a copy of A1
      if (n.getLabel() != null || dollarLabelFound) {
        return processGeoCopy(n.getLabel(), n);
      }
    }

    // REMOVED due to issue 131: http://code.google.com/p/geogebra/issues/detail?id=131
    //		// expressions like 2 a (where a:x + y = 1)
    //		// A1=b doesn't work for these objects
    //		else if (eval instanceof GeoLine) {
    //			if (((GeoLine)eval).getParentAlgorithm() instanceof AlgoDependentLine) {
    //				GeoElement[] ret = {(GeoElement) eval };
    //				return ret;
    //			}
    //
    //		}

    // if we get here, nothing worked
    Application.debug("Unhandled ExpressionNode: " + eval + ", " + eval.getClass());
    return null;
  }
 protected void checkNoTermsInZ(Equation equ) {
   if (!equ.getNormalForm().isFreeOf('z')) throw new MyError(app, "InvalidEquation");
 }