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

namespace FormulaEditor
{
    /// <summary>
    /// Like operation
    /// </summary>
    public class LikeOperation : IObjectOperation, IBinaryAcceptor, IBinaryDetector
    {
        static public readonly LikeOperation Object = new LikeOperation();
        static private readonly Boolean type = false;
        static private readonly string strType = "";

        List<IBinaryAcceptor> acceptors = new List<IBinaryAcceptor>();

        static public bool Like(object o1, object o2)
        {
            string s1 = o1 + "";
            string s2 = o2 + "";
            s1 = s1.ToLower();
            s2 = s2.ToLower();
            int n = s1.IndexOf(s2);
            return n >= 0;
        }


        IObjectOperation getOtherOperation(object typeA, object typeB)
        {
            foreach (IBinaryAcceptor acceptor in acceptors)
            {
                IObjectOperation op = acceptor.Accept(typeA, typeB);
                return op;
            }
            return null;
        }

        public void Add(IBinaryAcceptor acceptor)
        {
            acceptors.Add(acceptor);
        }

        #region IObjectOperation Members

        public int Arity
        {
            get
            {
                return 2;
            }
        }

        public object this[object[] x]
        {
            get
            {
                return Like(x[0], x[1]);
            }
        }

        public object ReturnType
        {
            get
            {
                return type;
            }
        }

        public bool IsPowered
        {
            get
            {
                return false;
            }
        }

        #endregion

        #region IBinaryAcceptor Members

        public IObjectOperation Accept(object typeA, object typeB)
        {
            if (typeA is object[])
            {
                object[] o = typeA as object[];
                Type t = o[0].GetType();
                string prop = o[1] as string;
                PropertyInfo info = t.GetProperty(prop);
                if (info == null)
                {
                    return getOtherOperation(typeA, typeB);
                }
            }
            else if (!typeA.Equals(strType))
            {
                return getOtherOperation(typeA, typeB);
            }
            if (typeB is object[])
            {
                object[] o = typeB as object[];
                Type t = o[0].GetType();
                string prop = o[1] as string;
                PropertyInfo info = t.GetProperty(prop);
                if (info == null)
                {
                    return getOtherOperation(typeA, typeB);
                }
            }
            else if (!typeB.Equals(strType))
            {
                return getOtherOperation(typeA, typeB);
            }
            return this;
        }

        #endregion

        #region IBinaryDetector Members

        public BinaryAssociationDirection AssociationDirection
        {
            get
            {
                return BinaryAssociationDirection.RightLeft;
            }
        }

        public IBinaryAcceptor Detect(MathSymbol s)
        {
            if (s is BinarySymbol)
            {
                if (s.Symbol == '\u2270')
                {
                    return this;
                }
            }
            return null;
        }

        #endregion
    }
}
