using System;
using System.Collections.Generic;
using System.Text;

namespace ECOT.Engine.Statistics
{
    public abstract class UnaryOperation : Variable
    {
        protected Variable var;
    }

    public abstract class Operation : Variable
    {
        protected Variable var1, var2;
    }

    public class ExpOperation : Operation
    {
        public ExpOperation(double d)
        {
            this.var1 = new Variable(d);
        }

        public ExpOperation(Variable var)
        {
            this.var1 = var;
        }

        public override double Compute()
        {
            return Math.Exp(this.var1.Compute());
        }
    }

    public class SubOperation : Operation
    {
        public SubOperation(Variable var, double d)
        {
            this.var1 = var;
            this.var2 = new Variable(d);
        }

        public SubOperation(double d, Variable var)
        {
            this.var1 = new Variable(d);
            this.var2 = var;
        }

        public SubOperation(Variable var1, Variable var2)
        {
            this.var1 = var1;
            this.var2 = var2;
        }

        public override double Compute()
        {
            return (this.var1.Compute() - this.var2.Compute());
        }
    }

    public class MultOperation : Operation
    {
        public MultOperation(Variable var, double d)
        {
            this.var1 = var;
            this.var2 = new Variable(d);
        }

        public MultOperation(double d, Variable var)
        {
            this.var1 = new Variable(d);
            this.var2 = var;
        }

        public MultOperation(Variable var1, Variable var2)
        {
            this.var1 = var1;
            this.var2 = var2;
        }

        public override double Compute()
        {
            return (this.var1.Compute() * this.var2.Compute());
        }
    }

    public class AddOperation : Operation
    {
        public AddOperation(Variable var, double d)
        {
            this.var1 = var;
            this.var2 = new Variable(d);
        }

        public AddOperation(double d, Variable var)
        {
            this.var1 = new Variable(d);
            this.var2 = var;
        }

        public AddOperation(Variable var1, Variable var2)
        {
            this.var1 = var1;
            this.var2 = var2;
        }

        public override double Compute()
        {
            return (this.var1.Compute() + this.var2.Compute());
        }
    }

    public class DivOperation : Operation
    {
        public DivOperation(Variable var, double d)
        {
            this.var1 = var;
            this.var2 = new Variable(d);
        }

        public DivOperation(double d, Variable var)
        {
            this.var1 = new Variable(d);
            this.var2 = var;
        }

        public DivOperation(Variable var1, Variable var2)
        {
            this.var1 = var1;
            this.var2 = var2;
        }

        public override double Compute()
        {
            // FIXME: temporaire pour éviter les NaN
            double d1 = var1.Compute();
            double d2 = var2.Compute();
            if (d2 == 0.0)
                return 0.0;
            return d1 / d2;
        }
    }

    public class NegateOperation : UnaryOperation
    {
        public NegateOperation(Variable var)
        {
            this.var = var;
        }

        public override double Compute()
        {
            return (-this.var.Compute());
        }
    }
}
