using System; using System.Collections.Generic; namespace Server.Commands.Generic { public sealed class ObjectConditional { private static readonly Type typeofItem = typeof(Item); private static readonly Type typeofMobile = typeof(Mobile); private readonly Type m_ObjectType; private readonly ICondition[][] m_Conditions; private IConditional[] m_Conditionals; public Type Type { get { return this.m_ObjectType; } } public bool IsItem { get { return (this.m_ObjectType == null || this.m_ObjectType == typeofItem || this.m_ObjectType.IsSubclassOf(typeofItem)); } } public bool IsMobile { get { return (this.m_ObjectType == null || this.m_ObjectType == typeofMobile || this.m_ObjectType.IsSubclassOf(typeofMobile)); } } public static readonly ObjectConditional Empty = new ObjectConditional(null, null); public bool HasCompiled { get { return (this.m_Conditionals != null); } } public void Compile(ref AssemblyEmitter emitter) { if (emitter == null) emitter = new AssemblyEmitter("__dynamic", false); this.m_Conditionals = new IConditional[this.m_Conditions.Length]; for (int i = 0; i < this.m_Conditionals.Length; ++i) this.m_Conditionals[i] = ConditionalCompiler.Compile(emitter, this.m_ObjectType, this.m_Conditions[i], i); } public bool CheckCondition(object obj) { if (this.m_ObjectType == null) return true; // null type means no condition if (!this.HasCompiled) { AssemblyEmitter emitter = null; this.Compile(ref emitter); } for (int i = 0; i < this.m_Conditionals.Length; ++i) { if (this.m_Conditionals[i].Verify(obj)) return true; } return false; // all conditions false } public static ObjectConditional Parse(Mobile from, ref string[] args) { string[] conditionArgs = null; for (int i = 0; i < args.Length; ++i) { if (Insensitive.Equals(args[i], "where")) { string[] origArgs = args; args = new string[i]; for (int j = 0; j < args.Length; ++j) args[j] = origArgs[j]; conditionArgs = new string[origArgs.Length - i - 1]; for (int j = 0; j < conditionArgs.Length; ++j) conditionArgs[j] = origArgs[i + j + 1]; break; } } return ParseDirect(from, conditionArgs, 0, conditionArgs.Length); } public static ObjectConditional ParseDirect(Mobile from, string[] args, int offset, int size) { if (args == null || size == 0) return ObjectConditional.Empty; int index = 0; Type objectType = ScriptCompiler.FindTypeByName(args[offset + index], true); if (objectType == null) throw new Exception(String.Format("No type with that name ({0}) was found.", args[offset + index])); ++index; List conditions = new List(); List current = new List(); current.Add(TypeCondition.Default); while (index < size) { string cur = args[offset + index]; bool inverse = false; if (Insensitive.Equals(cur, "not") || cur == "!") { inverse = true; ++index; if (index >= size) throw new Exception("Improperly formatted object conditional."); } else if (Insensitive.Equals(cur, "or") || cur == "||") { if (current.Count > 1) { conditions.Add(current.ToArray()); current.Clear(); current.Add(TypeCondition.Default); } ++index; continue; } string binding = args[offset + index]; index++; if (index >= size) throw new Exception("Improperly formatted object conditional."); string oper = args[offset + index]; index++; if (index >= size) throw new Exception("Improperly formatted object conditional."); string val = args[offset + index]; index++; Property prop = new Property(binding); prop.BindTo(objectType, PropertyAccess.Read); prop.CheckAccess(from); ICondition condition = null; switch ( oper ) { #region Equality case "=": case "==": case "is": condition = new ComparisonCondition(prop, inverse, ComparisonOperator.Equal, val); break; case "!=": condition = new ComparisonCondition(prop, inverse, ComparisonOperator.NotEqual, val); break; #endregion #region Relational case ">": condition = new ComparisonCondition(prop, inverse, ComparisonOperator.Greater, val); break; case "<": condition = new ComparisonCondition(prop, inverse, ComparisonOperator.Lesser, val); break; case ">=": condition = new ComparisonCondition(prop, inverse, ComparisonOperator.GreaterEqual, val); break; case "<=": condition = new ComparisonCondition(prop, inverse, ComparisonOperator.LesserEqual, val); break; #endregion #region Strings case "==~": case "~==": case "=~": case "~=": case "is~": case "~is": condition = new StringCondition(prop, inverse, StringOperator.Equal, val, true); break; case "!=~": case "~!=": condition = new StringCondition(prop, inverse, StringOperator.NotEqual, val, true); break; case "starts": condition = new StringCondition(prop, inverse, StringOperator.StartsWith, val, false); break; case "starts~": case "~starts": condition = new StringCondition(prop, inverse, StringOperator.StartsWith, val, true); break; case "ends": condition = new StringCondition(prop, inverse, StringOperator.EndsWith, val, false); break; case "ends~": case "~ends": condition = new StringCondition(prop, inverse, StringOperator.EndsWith, val, true); break; case "contains": condition = new StringCondition(prop, inverse, StringOperator.Contains, val, false); break; case "contains~": case "~contains": condition = new StringCondition(prop, inverse, StringOperator.Contains, val, true); break; #endregion } if (condition == null) throw new InvalidOperationException(String.Format("Unrecognized operator (\"{0}\").", oper)); current.Add(condition); } conditions.Add(current.ToArray()); return new ObjectConditional(objectType, conditions.ToArray()); } public ObjectConditional(Type objectType, ICondition[][] conditions) { this.m_ObjectType = objectType; this.m_Conditions = conditions; } } }