001    package org.hackystat.telemetry.analyzer.function.impl;
002    
003    import org.hackystat.telemetry.analyzer.function.TelemetryFunction;
004    import org.hackystat.telemetry.analyzer.function.TelemetryFunctionException;
005    import org.hackystat.telemetry.analyzer.model.TelemetryStreamCollection;
006    
007    /**
008     * If passed two numbers, returns their sum, and if passed two telemetry streams, returns a 
009     * new TelemetryStreamCollection containing the pairwise addition of the individual elements. 
010     * 
011     * @author (Cedric) Qin ZHANG, Philip Johnson
012     */
013    public class AddFunction extends TelemetryFunction {
014      
015      /** Thread-safe add operator. */
016      private AddOperator addOperator = new AddOperator();
017    
018      /**
019       * Constructs this instance.
020       * 
021       */
022      public AddFunction() {
023        super("add");
024      }
025      
026     /**
027      * @param parameters An array of 2 objects of type either <code>Number</code> 
028      *        or <code>TelemetryStreamCollection</code>. 
029      * 
030      * @return Either an instance of <code>Number</code> or <code>TelemetryStreamCollection</code>. 
031      * 
032      * @throws TelemetryFunctionException If anything is wrong.
033      */
034      @Override
035      public Object compute(Object[] parameters) throws TelemetryFunctionException {
036        //parameter validity check
037        if (parameters.length != 2 
038           || ! (parameters[0] instanceof Number || parameters[0] instanceof TelemetryStreamCollection)
039           || ! (parameters[1] instanceof Number || parameters[1] instanceof TelemetryStreamCollection)
040           ) {
041          throw new TelemetryFunctionException("Telemetry function " + this.getName()
042              + " takes 2 parameters of type 'Number' and/or 'TelemetryStreamCollection'.");
043        }
044        
045        if (parameters[0] instanceof Number && parameters[1] instanceof Number) {
046          return this.addOperator.computes((Number) parameters[0], (Number) parameters[1]);
047        }
048        else {
049          TelemetryStreamCollection tsc0 = (parameters[0] instanceof Number)
050            ? Utility.expandNumber((Number) parameters[0], (TelemetryStreamCollection) parameters[1])
051            : (TelemetryStreamCollection) parameters[0];
052          TelemetryStreamCollection tsc1 = (parameters[1] instanceof Number)
053            ? Utility.expandNumber((Number) parameters[1], (TelemetryStreamCollection) parameters[0])
054            : (TelemetryStreamCollection) parameters[1];
055          return BinaryOperationUtility.computes(this.addOperator, tsc0, tsc1);
056        }
057      }
058    
059      /**
060       * Binary operator used by the enclosing class.
061       * 
062       * @author (Cedric) Qin ZHANG
063       */
064      private static class AddOperator implements BinaryOperationUtility.BinaryOperator {
065        /**
066         * Performs binary operation. 
067         * @param a Number 1.
068         * @param b Number 2.
069         * @return The result.
070         */
071        public Number computes(Number a, Number b) {
072          if (a instanceof Integer && b instanceof Integer) {
073            return Integer.valueOf(a.intValue() + b.intValue());
074          }
075          else {
076            return Double.valueOf(a.doubleValue() + b.doubleValue());
077          }      
078        }
079      }
080    }