using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace FormulaEditor
{
/// <summary>
/// Tree of object formula
/// </summary>
public class ObjectFormulaTree : ICloneable
{
/// <summary>
/// Children formulas
/// </summary>
protected List<ObjectFormulaTree> children = new List<ObjectFormulaTree>();
/// <summary>
/// Operation of this formula
/// </summary>
protected IObjectOperation operation;
/// <summary>
/// Temporary variables
/// </summary>
protected object[] y;
/// <summary>
/// Creator of formulas
/// </summary>
static protected IFormulaObjectCreator creator;
/// <summary>
/// Constructor
/// </summary>
protected ObjectFormulaTree()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="operation">Tree operation</param>
/// <param name="children">Children trees</param>
public ObjectFormulaTree(IObjectOperation operation, List<ObjectFormulaTree> children)
{
if (operation is ICloneable)
{
ICloneable c = operation as ICloneable;
this.operation = c.Clone() as IObjectOperation;
}
else
{
this.operation = operation;
}
if (operation.Arity != 0)
{
if (children == null)
{
this.children = children;
}
if (children.Count != operation.Arity)
{
this.children = children;
}
}
this.children = children;
y = new object[operation.Arity];
}
/// <summary>
/// Consructor from formula
/// </summary>
/// <param name="formula">The formula</param>
/// <param name="creator">The formula object creator</param>
public ObjectFormulaTree(MathFormula formula, IFormulaObjectCreator creator)
{
init(formula, creator);
}
/// <summary>
/// Consructor from formula
/// </summary>
/// <param name="formula">The formula</param>
public ObjectFormulaTree(MathFormula formula) : this(formula, creator)
{
}
public object Clone()
{
ObjectFormulaTree t = new ObjectFormulaTree();
if (operation is ICloneable)
{
ICloneable c = operation as ICloneable;
t.operation = c.Clone() as IObjectOperation;
}
else
{
t.operation = operation;
}
foreach (ObjectFormulaTree tree in children)
{
t.children.Add(tree.Clone() as ObjectFormulaTree);
}
if (t.children.Count != t.operation.Arity)
{
y = y;
}
if (y != null)
{
t.y = new object[y.Length];
}
return t;
}
public static IFormulaObjectCreator Creator
{
set
{
creator = value;
}
}
private void init(MathFormula formula, IFormulaObjectCreator creator)
{
if (creator.IsBra(formula[0]) & creator.IsKet(formula[formula.Count - 1]))
{
if (formula[formula.Count - 1].Count >= 0)
{
if(formula.Count > 2)
{
int m = 1;
for (int i = 1; i < formula.Count - 1; i++)
{
if (creator.IsBra(formula[i]))
{
++m;
}
else if (creator.IsKet(formula[i]))
{
--m;
}
if (m == 0)
{
goto calc;
}
}
MathFormula f = new MathFormula(formula, 1, formula.Count - 2);
init(f, creator);
return;
}
}
}
calc:
if (processMultiOperation(formula, creator))
{
return;
}
if (processBinary(formula, creator))
{
return;
}
if (processOperation(formula, creator))
{
return;
}
}
/// <summary>
/// Result of calculation
/// </summary>
public object Result
{
get
{
if (operation is OptionalOperation)
{
object o = this[0].Result;
if (o == null)
{
return null;
}
bool b = (bool)o;
if (b)
{
return this[1].Result;
}
return this[2].Result;
}
for (int i = 0; i < operation.Arity; i++)
{
object o = this[i].Result;
if (o == null | o is DBNull)
{
return null;
}
y[i] = o;
}
return operation[y];
}
}
/// <summary>
/// Access to i - th child
/// </summary>
public ObjectFormulaTree this[int i]
{
get
{
if (children.Count <= i | i < 0 | children == null)
{
return null;
}
return children[i] as ObjectFormulaTree;
}
}
/// <summary>
/// Sets null arity objects
/// </summary>
/// <param name="x">The object to set</param>
public void SetNullArityObjects(object x)
{
for (int i = 0; i < Count; i++)
{
this[i].SetNullArityObjects(x);
}
if (!(operation is INullArityOperation))
{
return;
}
INullArityOperation n = operation as INullArityOperation;
n.Object = x;
}
/// <summary>
/// Calculates result by argument
/// </summary>
/// <param name="x">The argument</param>
/// <returns>The result</returns>
public object GetResult(object x)
{
SetNullArityObjects(x);
return Result;
}
/// <summary>
/// Children count
/// </summary>
public int Count
{
get
{
if (children == null)
{
return 0;
}
return children.Count;
}
}
/// <summary>
/// Return type
/// </summary>
public object ReturnType
{
get
{
return operation.ReturnType;
}
}
/// <summary>
/// Tree root operation
/// </summary>
public IObjectOperation Operation
{
get
{
return operation;
}
}
/// <summary>
/// Processes binary operation
/// </summary>
/// <param name="formula">Input formula</param>
/// <param name="creator">Creator of tree</param>
protected bool processBinary(MathFormula formula, IFormulaObjectCreator creator)
{
for (int i = 0; i < creator.BinaryCount; i++)
{
IBinaryDetector detector = creator.GetBinaryDetector(i);
ObjectFormulaTree tA = null;
ObjectFormulaTree tB = null;
if (detector.AssociationDirection == BinaryAssociationDirection.LeftRight)
{
int m = 0;
for (int j = 0; j < formula.Count - 1; j++)
{
MathSymbol symbol = formula[j];
if (creator.IsBra(symbol))
{
++m;
continue;
}
if (creator.IsKet(symbol))
{
--m;
continue;
}
if (m < 0)
{
//FormulaEditorPerformer.ThrowErrorException(FormulaTree.ERRORS[1]);
}
if (j == 0 | m != 0)
{
continue;
}
IBinaryAcceptor acceptor = detector.Detect(symbol);
if (acceptor == null)
{
continue;
}
tA = new ObjectFormulaTree(new MathFormula(formula, 0, j - 1), creator);
tB = new ObjectFormulaTree(new MathFormula(formula, j + 1, formula.Count - 1), creator);
operation = acceptor.Accept(tA.ReturnType, tB.ReturnType);
if (operation != null)
{
goto start;
}
}
}
else
{
int m = 0;
for (int j = formula.Count - 1; j > 0; j--)
{
MathSymbol symbol = formula[j];
if (creator.IsKet(symbol))
{
++m;
continue;
}
if (creator.IsBra(symbol))
{
--m;
continue;
}
if (m < 0)
{
//FormulaEditorPerformer.ThrowErrorException(FormulaTree.ERRORS[1]);
}
if (m != 0)
{
continue;
}
IBinaryAcceptor acceptor = detector.Detect(symbol);
if (acceptor == null)
{
continue;
}
tA = new ObjectFormulaTree(new MathFormula(formula, 0, j - 1), creator);
tB = new ObjectFormulaTree(new MathFormula(formula, j + 1, formula.Count - 1), creator);
operation = acceptor.Accept(tA.ReturnType, tB.ReturnType);
if (operation != null)
{
goto start;
}
}
}
start:
if (operation != null)
{
children.Add(tA);
children.Add(tB);
y = new object[2];
return true;
}
}
return false;
}
/// <summary>
/// Processes multi operation
/// </summary>
/// <param name="formula">Formula</param>
/// <param name="creator">Formula creator</param>
/// <returns>True if operation exists and false otherwise</returns>
protected bool processMultiOperation(MathFormula formula, IFormulaObjectCreator creator)
{
for (int n = 0; n < creator.MultiOperationCount; n++)
{
IMultiOperationDetector detector = creator.GetMultiOperationDetector(n);
int j = 0;
int m = 0;
int i = 0;
//int opened = 0;
int k = 0;
List<ObjectFormulaTree> list = null;
for(;i < formula.Count; i++)
{
MathSymbol symbol = formula[i];
if (creator.IsBra(symbol))
{
++m;
continue;
}
if (creator.IsKet(symbol))
{
--m;
continue;
}
if (m != 0)
{
continue;
}
if (!detector.Detect(k, symbol))
{
continue;
}
if (list == null)
{
list = new List<ObjectFormulaTree>();
}
MathFormula f = new MathFormula(formula, j, i - 1);
list.Add(new ObjectFormulaTree(f, creator));
++k;
j = i + 1;
if (k == detector.Count)
{
f = new MathFormula(formula, j, formula.Count - 1);
list.Add(new ObjectFormulaTree(f, creator));
object[] types = new object[list.Count];
int nOp = 0;
foreach (ObjectFormulaTree tree in list)
{
types[nOp] = tree.ReturnType;
++nOp;
}
IObjectOperation op = detector.Accept(types);
if (op != null)
{
operation = op;
children = list;
y = new object[list.Count];
return true;
}
}
}
}
return false;
}
/// <summary>
/// Processes ordinary operation
/// </summary>
/// <param name="formula">Formula</param>
/// <param name="creator">Formula creator</param>
/// <returns>True if operation exists and false otherwise</returns>
protected bool processOperation(MathFormula formula, IFormulaObjectCreator creator)
{
for (int i = 0; i < creator.OperationCount; i++)
{
IOperationDetector detector = creator.GetDetector(i);
IOperationAcceptor acceptor = detector.Detect(formula[0]);
if (acceptor == null)
{
continue;
}
object type = null;
ObjectFormulaTree tree = null;
if (formula.Count > 1)
{
tree = new ObjectFormulaTree(new MathFormula(formula, 1, formula.Count - 1), creator);
type = tree.ReturnType;
}
if (acceptor is IMultiVariableOperationAcceptor)
{
IMultiVariableOperationAcceptor ma = acceptor as IMultiVariableOperationAcceptor;
IMultiVariableOperation multiOp = ma.AcceptOperation(formula[0]);
MathSymbol s = formula[0];
ObjectFormulaTree[] trees = null;
object[] types = null;
if (s.HasChildren)
{
int n = 0;
for (int j = 0; j < s.Count; j++)
{
if (s[j] != null)
{
if (!s[j].IsEmpty)
{
++n;
}
}
}
trees = new ObjectFormulaTree[n];
types = new object[n];
n = 0;
for (int j = 0; j < s.Count; j++)
{
if (s[j] != null)
{
if (!s[j].IsEmpty)
{
trees[j] = new ObjectFormulaTree(s[j], creator);
types[j] = trees[j].ReturnType;
++n;
}
}
}
}
operation = multiOp.Accept(types);
if (operation == null)
{
return false;
}
y = new object[types.Length];
if (trees != null)
{
foreach (ObjectFormulaTree t in trees)
{
if (t != null)
{
children.Add(t);
}
}
}
return true;
}
IObjectOperation op = acceptor.Accept(type);
if (op != null)
{
if (op.IsPowered)
{
if (formula.First.HasChildren)
{
ObjectFormulaTree pow = new ObjectFormulaTree(formula.First[0], creator);
ObjectFormulaTree val = new ObjectFormulaTree();
val.operation = op;
val.y = new object[op.Arity];
if (tree != null)
{
val.children.Add(tree);
}
IObjectOperation powOp = creator.GetPowerOperation(val.ReturnType, pow.ReturnType);
if (powOp == null)
{
return false;
}
operation = powOp;
children.Add(val);
children.Add(pow);
y = new object[2];
return true;
}
}
operation = op;
if (tree != null)
{
children.Add(tree);
y = new object[1];
}
return true;
}
}
return false;
}
/// <summary>
/// Selects operations
/// </summary>
/// <param name="selector">Selector</param>
/// <param name="list">Result list</param>
private void selectOperations(IObjectSelector selector, ArrayList list)
{
object o = selector.Select(operation);
if (o != null)
{
if (!list.Contains(o))
{
list.Add(o);
}
}
for (int i = 0; i < Count; i++)
{
this[i].selectOperations(selector, list);
}
}
}
}