//
// Add.java -- Java class Add
// Project OrcScala
//
// Copyright (c) 2009 The University of Texas at Austin. All rights reserved.
//
// Use and redistribution of this file is governed by the license terms in
// the LICENSE file found in the project's top-level directory and also found at
// URL: http://orc.csres.utexas.edu/license.shtml .
//

package orc.lib.math;

import java.math.BigDecimal;
import java.math.BigInteger;

import orc.error.runtime.TokenException;
import orc.types.RecordExtensorType;
import orc.types.Type;
import orc.values.sites.TypedSite;
import orc.values.sites.compatibility.Args;
import orc.values.sites.compatibility.Args.NumericBinaryOperator;
import orc.values.sites.compatibility.EvalSite;
import orc.values.sites.compatibility.Types;

/**
 * NB: this is overloaded to operate on strings, with implicit toString coercion
 * (just like Java).
 * 
 * @author quark
 */
@SuppressWarnings("synthetic-access")
public class Add extends EvalSite implements TypedSite {
    private static final MyOperator op = new MyOperator();

    private static final class MyOperator implements NumericBinaryOperator<Number> {
        @Override
        public Number apply(final BigInteger a, final BigInteger b) {
            return a.add(b);
        }

        @Override
        public Number apply(final BigDecimal a, final BigDecimal b) {
            return a.add(b);
        }

        @Override
        public Number apply(final int a, final int b) {
            return Integer.valueOf(a + b);
        }

        @Override
        public Number apply(final long a, final long b) {
            return Long.valueOf(a + b);
        }

        @Override
        public Number apply(final byte a, final byte b) {
            return Integer.valueOf(a + b);
        }

        @Override
        public Number apply(final short a, final short b) {
            return Integer.valueOf(a + b);
        }

        @Override
        public Number apply(final double a, final double b) {
            return Double.valueOf(a + b);
        }

        @Override
        public Number apply(final float a, final float b) {
            return Float.valueOf(a + b);
        }
    }

    @Override
    public Object evaluate(final Args args) throws TokenException {
        try {
            return Args.applyNumericOperator(args.numberArg(0), args.numberArg(1), op);
        } catch (final TokenException _1) {
            try {
                final orc.values.OrcRecord a = (orc.values.OrcRecord) args.getArg(0);
                final orc.values.OrcRecord b = (orc.values.OrcRecord) args.getArg(1);
                return a.extendWith(b);
            } catch (final ClassCastException _2) {
                // If the arguments aren't both numbers or records, maybe
                // one or the other is a string
                try {
                    // the first argument is a string
                    final String a = args.stringArg(0);
                    return a + orc.values.Format.formatValueR(args.getArg(1), false);
                } catch (final TokenException _3) {
                    // the second argument is a string
                    final String b = args.stringArg(1);
                    return orc.values.Format.formatValueR(args.getArg(0), false) + b;
                }
            }
        }
    }

    @Override
    public Type orcType() {
        return Types.overload(Types.function(Types.integer(), Types.integer(), Types.integer()), Types.function(Types.number(), Types.number(), Types.number()), new RecordExtensorType(), Types.function(Types.string(), Types.top(), Types.string()), Types.function(Types.top(), Types.string(), Types.string()));
    }

    @Override
    public boolean nonBlocking() { return true; }
    @Override
    public int minPublications() { return 1; }
    @Override
    public int maxPublications() { return 1; }
    @Override
    public boolean effectFree() { return true; }
}

@@ -424,16 +424,72 @@
 teger;%0A%0A
+import orc.error.runtime.ArgumentTypeMismatchException;%0A
 import o
@@ -2225,36 +2225,33 @@
        %7D%0A    %7D%0A%0A
-    
+%09
 @Override%0A    pu
@@ -2240,28 +2240,25 @@
 %0A%09@Override%0A
-    
+%09
 public Objec
@@ -2321,161 +2321,385 @@
     
-try %7B%0A            return Args.applyNumericOperator(args.numberArg(0), args.numberArg(1), op);%0A        %7D catch (final TokenException _1) %7B%0A            try
+Object a = args.getArg(0);%0A        Object b = args.getArg(1);%0A        %0A        if (a instanceof Number && b instanceof Number) %7B%0A  %09%09%09return Args.applyNumericOperator(args.numberArg(0), args.numberArg(1), op);%0A        %7D else if (a instanceof String) %7B%0A            return (String)a + orc.values.Format.formatValueR(args.getArg(1), false);%0A        %7D else if (b instanceof String)
  %7B%0A 
@@ -2705,33 +2705,30 @@
             
-    final
+return
  orc.values.
@@ -2731,82 +2731,95 @@
 ues.
-OrcRecord a = (orc.values.OrcRecord) args.getArg(0);%0A                final
+Format.formatValueR(args.getArg(0), false) + (String)b;%0A        %7D else if (a instanceof
  orc
@@ -2840,13 +2840,24 @@
 ord 
-b = (
+%7C%7C b instanceof 
 orc.
@@ -2878,751 +2878,375 @@
 rd) 
-args.getArg(1);%0A                return a.extendWith(b);%0A            %7D catch (final ClassCastException _2) %7B%0A                // If the arguments aren't both numbers or records, maybe%0A                // one or the other is a string%0A                try %7B%0A                    // the first argument is a string%0A                    final String a = args.stringArg(0);%0A                    return a + orc.values.Format.formatValueR(args.getArg(1), false);%0A                %7D catch (final TokenException _3) %7B%0A                    // the second argument is a string%0A                    final String b = args.stringArg(1);%0A                    return orc.values.Format.formatValueR(args.getArg(0), false) + b;%0A                %7D%0A            %7D%0A        %7D%0A    
+%7B%0A            return ((orc.values.OrcRecord)a).extendWith((orc.values.OrcRecord)b);%0A%09%09%7D else %7B%0A%09%09  // TODO: This is not accurate, since we don't know WHICH parameter has the wrong time. However the old version wasn't very specific either.%0A%09%09  throw new ArgumentTypeMismatchException(0, %22Number, String, or record%22, a != null ? a.getClass().toString() : %22null%22);%0A%09%09%7D%0A%09
 %7D%0A%0A 

Fix really inefficient type check in + operation.