//
// Add.java -- Java class Add
// Project OrcScala
//
// $Id$
//
// 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.Type;
import orc.types.RecordExtensorType;
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 maxPublications() { return 1; }
    @Override
    public boolean effectFree() { return true; }
}

@@ -435,16 +435,72 @@
 teger;%0A%0A
+import orc.error.runtime.ArgumentTypeMismatchException;%0A
 import o
@@ -2091,24 +2091,155 @@
 ption %7B%0A
-%09%09try
+        Object a = args.getArg(0);%0A        Object b = args.getArg(1);%0A        %0A        if (a instanceof Number && b instanceof Number)
  %7B%0A
+  
 %09%09%09retur
@@ -2313,138 +2313,295 @@
 p);%0A
-%09%09%7D catch (final TokenException _1) %7B%0A%09%09%09try %7B%0A%09%09%09%09final orc.values.OrcRecord a = (orc.values.OrcRecord) args.getArg(0);%0A%09%09%09%09final
+        %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            return orc.values.Format.formatValueR(args.getArg(0), false) + (String)b;%0A        %7D else if (a instanceof
  orc
@@ -2622,13 +2622,24 @@
 ord 
-b = (
+%7C%7C b instanceof 
 orc.
@@ -2660,556 +2660,369 @@
 rd) 
-args.getArg(1);%0A%09%09%09%09return a.extendWith(
+%7B%0A            return ((orc.values.OrcRecord)a).extendWith((orc.values.OrcRecord)
 b);%0A%09%09
-%09
 %7D 
-catch (final ClassCastException _2)
+else
  %7B%0A%09%09
-%09%09// If the arguments aren't both numbers or records, maybe%0A%09%09%09%09// one or the other is a string%0A%09%09%09%09try %7B%0A%09%09%09%09%09// the first argument is a string%0A%09%09%09%09%09final String a = args.stringArg(0);%0A%09%09%09%09%09return a + orc.values.Format.formatValueR(args.getArg(1), false);%0A%09%09%09%09%7D catch (final TokenException _3) %7B%0A%09%09%09%09%09// the second argument is a string%0A%09%09%09%09%09final String b = args.stringArg(1);%0A%09%09%09%09%09return orc.values.Format.formatValueR(args.getArg(0), false) + b;%0A%09%09%09%09%7D%0A%09%09%09%7D
+  // 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

Fix really inefficient type check in + operation.