// Copyright (c) 2016 IBM Corporation.

package org.transscript.runtime;

import java.util.function.Function;

import org.transscript.runtime.Functions.ThunkMaker;
import org.transscript.runtime.StringTerm.VarStringTermUse;

/**
 * 
 * @author Lionel Villard
 */
public interface DoubleTerm extends Term
{

	@Override
	default DoubleTerm eval(Context context)
	{
		return (DoubleTerm) Term.super.eval(context);
	}

	public double unbox();

	static DoubleTerm doubleTerm(double d)
	{
		return new DoubleValue(d);
	}

	static DoubleTerm newLazyDoubleTerm(Function<Context, DoubleTerm> f)
	{
		return new LazyDoubleTerm(f);
	}

	static DoubleTerm lazyDoubleTerm(Function<Context, DoubleTerm> f)
	{
		return new LazyDoubleTerm(f);
	}

	static ThunkMaker<DoubleTerm> lazyDoubleTermMaker()
	{
		return DoubleTerm::lazyDoubleTerm;
	}

	static class DoubleValue implements DoubleTerm
	{
		// State

		/** The value */
		protected double value;

		// Constructor

		/** Constructs a literal term */
		public DoubleValue(double str)
		{
			this.value = str;
		}

		@Override
		public Term copy(Context c)
		{
			return new DoubleValue(value);
		}

		@Override
		public String toString()
		{
			// TODO: FIX BY ADDING INTEGERTERM
			return Integer.toString((int)value);
		}

		@Override
		public double unbox()
		{
			return value;
		}

	}

	public static class VarDoubleTerm extends Variable
	{

		public VarDoubleTerm(String name)
		{
			super(name);
		}

		@Override
		protected VariableUse newVarUse()
		{
			return new VarDoubleTermUse(this);
		}

		@Override
		public VarDoubleTermUse use()
		{
			return (VarDoubleTermUse) super.use();
		}

	}

	class VarDoubleTermUse extends VariableUse implements StringTerm
	{

		protected VarDoubleTermUse(Variable variable)
		{
			super(variable);
		}

	}

	static class LazyDoubleTerm extends LazyTerm<DoubleTerm>implements DoubleTerm
	{

		public LazyDoubleTerm(Function<Context, DoubleTerm> f)
		{
			super(f);
		}

		@Override
		public Term copy(Context c)
		{
			return new LazyDoubleTerm(f);
		}

		@Override
		public DoubleTerm eval(Context context)
		{
			return super.eval(context);
		}

		@Override
		public double unbox()
		{
			throw new RuntimeException("Cannot access unevaluated double value.");
		}

	}

}

@@ -1315,24 +1315,192 @@
 value;%0A%09%09%7D%0A%0A
+%09%09@Override%0A%09%09public boolean equals(Object other)%0A%09%09%7B%0A%09%09%09if (other instanceof DoubleValue)%0A%09%09%09%09return ((DoubleValue) other).unbox() == this.value;%0A%09%09%09return false;%0A%09%09%7D%0A
 %09%7D%0A%0A%09public 

Implement Equal on double