package ModSQL;
import java.sql.*;
 
/* $Id: Operator_Divide.java,v 1.8 2003/07/09 06:54:49 cvs Exp $
 *
 * Copyright (c) 2003 Chris Studholme <chris.studholme@utoronto.ca>
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See COPYING for more information.
 */

/**
 * <p>SQL operator "/". 
 *
 * @author chris.studholme@utoronto.ca
 */
final class Operator_Divide extends Operator {

  /** SQL type of returned value. */
  private int return_type;


  /**
   * <p>Prepare the function for use.  This method verifies that we have
   * exactly two parameters and that their types are compatible.  The
   * return type is also computed here as is any constant parameters.
   *
   * @throws SQLException if the parameters are invalid
   */
  public void optimize() throws SQLException {
    super.optimize();
    if (parameters.length!=2) 
      throw new SQLException("'/' operator requires exactly two parameter");
    return_type = getCompatableType(parameters[0].getSQLType(),
				    parameters[1].getSQLType());
    switch (return_type) {
    case Types.NULL:
    case Types.TINYINT:
    case Types.SMALLINT:
    case Types.INTEGER:
    case Types.BIGINT:
    case Types.REAL:
    case Types.FLOAT:
    case Types.DOUBLE:
      break;
    default:
      throw new SQLException("invalid parameter type in '/' operator");
    }
    evaluateConstantParameters();
  }
  
  /**
   * Returns "#DIV".
   *
   * @return name of function 
   */
  public String functionName() {
    return "#DIV";
  }


  /****************  result meta-data  ****************/
  

  /**
   * Return the SQL type of the value that this function expects to return.
   * The data returned by the function must either be of this type, or null.
   *
   * @return SQL type of data to be returned
   */
  public int getSQLType() {
    return return_type;
  }


  /**
   * Returns -1 as this operator will never return a String object.
   *
   * @return maximum size of String returned or -1 if unknown
   */
  public int getMaxResultSize() {
    return -1;
  }


  /****************  evaluation methods  ****************/


  /**
   * Evaluate parameters and compute the function.  
   *
   * @param aggregate passed to parameters
   * @return result object
   * @throws SQLException if a database-access error occurs
   * @throws EndOfTable if thrown by a parameter
   */
  public Object evaluate(boolean aggregate) throws SQLException, EndOfTable {
    if (!evaluateParameters(aggregate))
      return null;
    Number result = 
      NumberMath.divide((Number)parameter_value[0],(Number)parameter_value[1]);
    return convertToSQLType(result,return_type);
  }

  /**
   * Evaluate parameters and compute the function.  
   *
   * @param match_op how the value should be matched
   * @param match_value desired value
   * @return result object
   * @throws SQLException if a database-access error occurs
   * @throws EndOfTable if thrown by a parameter
   */
  public Object evaluate(int match_op, Object match_value)
    throws SQLException, EndOfTable {
    // evaluate parameters
    for (int i=0; i<evaluate_order.length; ++i) {
      if (!parameter_constant[evaluate_order[i]]) {
	if (i<evaluate_order.length-1) {
	  if (match_value==null && match_op==MATCH_NE)
	    parameter_value[evaluate_order[i]] =
	      parameters[evaluate_order[i]].evaluate(MATCH_NE,null);
	  else
	    parameter_value[evaluate_order[i]] =
	      parameters[evaluate_order[i]].evaluate(false);
	}
	else if (match_value==null)
	  parameter_value[evaluate_order[i]] =
	    parameters[evaluate_order[i]].evaluate(match_op,null);
	else if (evaluate_order[i]==0) {
	  // next/value match_op match_value
	  //Number mv = add((Number)match_value,Operator_Negate.negate(value));
	  //term = (Number)parameters[evaluate_order[i]].evaluate(match_op,mv);
	  parameter_value[evaluate_order[i]] =
	    parameters[evaluate_order[i]].evaluate(false);
	}
	else {
	  // value/next match_op match_value
	  parameter_value[evaluate_order[i]] =
	    parameters[evaluate_order[i]].evaluate(false);
	}
      }
      if (parameter_value[evaluate_order[i]]==null)
	return null;
    }
    Number result = 
      NumberMath.divide((Number)parameter_value[0],(Number)parameter_value[1]);
    return convertToSQLType(result,return_type);
  }
};
