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

namespace FormulaEditor
{
    public class MultiVariableArrayOperationAcceptor : IMultiVariableOperationAcceptor, IMultiVariableOperation
    {

        #region Fields

        private IMultiVariableOperationAcceptor acceptor;

        private IMultiVariableOperation operation;
        private IMultiVariableOperation op;
        protected object[] y;
        protected object[] types;
        protected ArrayReturnType returnType;
        protected object returnValue;
        protected bool[] isArray;
        protected int length = 0;
        protected int[] rank;
        protected int[][] ranks;
        protected object[][] yy;
        protected object[] yt;

        #endregion

        public MultiVariableArrayOperationAcceptor(IMultiVariableOperationAcceptor acceptor)
        {
            this.acceptor = acceptor;
        }


        #region IMultiVariableOperationAcceptor Members

        public IMultiVariableOperation AcceptOperation(MathSymbol symbol)
        {
            operation = acceptor.AcceptOperation(symbol);
            return this;
        }

        #endregion

        #region IOperationAcceptor Members

        public IObjectOperation Accept(object type)
        {
            if (type is ArrayReturnType)
            {
                ArrayReturnType a = type as ArrayReturnType;
                op = acceptor.Accept(a) as IMultiVariableOperation;
                if (op == null)
                {
                    return null;
                }
                types = new object[] { type };
                ArrayOperation.CreateAllArrays(op, types, out y, out yy, out rank, out ranks);
                returnType = new ArrayReturnType(op.ReturnType, rank);
                /*y = new object[1];
                isArray = new bool[]{true};
                returnType = convertor.CreateArray(op.ReturnType, a.Length);
                returnValue = convertor.CreateArray(op.ReturnType, a.Length);*/
                return this;
            }
            return acceptor.Accept(type);
        }

        #endregion

        #region IMultiVariableOperation Members

        public IObjectOperation Accept(object[] types)
        {
            this.types = types;
            if (types == null)
            {
                return acceptor.Accept(null);
            }
            object[] t = new object[types.Length];
            bool isArray = false;
            for (int i = 0; i < t.Length; i++)
            {
                t[i] = ArrayReturnType.GetBaseType(types[i]);
                if (types[i] is ArrayReturnType)
                {
                    isArray = true;
                }
            }
            op = operation.Accept(t) as IMultiVariableOperation;
            if (op == null)
            {
                return null;
            }
            if (!isArray)
            {
                return op;
            }
            ArrayOperation.CreateAllArrays(op, types, out y, out yy, out rank, out ranks);
            returnType = new ArrayReturnType(op.ReturnType, rank);
            returnValue = y;
            if (types != null)
            {
                if (types.Length > 0)
                {
                    yt = new object[types.Length];
                }
            }
            return this;
        }

        #endregion

        #region IObjectOperation Members

        public int Arity
        {
            get
            {
                return types.Length;
            }
        }

        public object this[object[] x]
        {
            get
            {
                ArrayOperation.PerformOperation(operation, returnValue as object[], x, yy,
                    rank.Length, ranks, rank, yt);
                return returnValue;
            }
        }

        public object ReturnType
        {
            get
            {
                return returnType;
            }
        }

        public bool IsPowered
        {
            get
            {
                return op.IsPowered;
            }
        }

        #endregion


    }
}
