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