using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Ruleset;
using System;
using System.Globalization;
using SIdentifier = Cryville.Common.Identifier;

namespace Cryville.Crtr {
	public class PdtBinder : EmptyBinder {
		public override object ChangeType(object value, Type type, CultureInfo culture) {
			if (value is PdtExpression) {
				var exp = (PdtExpression)value;
				if (type.Equals(typeof(bool))) {
					bool result = false;
					PdtEvaluator.Instance.Evaluate(new PropOp.Boolean(r => result = r), exp);
					return result;
				}
				else if (type.Equals(typeof(int))) {
					int result = 0;
					PdtEvaluator.Instance.Evaluate(new PropOp.Integer(r => result = r), exp);
					return result;
				}
				else if (type.Equals(typeof(float))) {
					float result = 0;
					PdtEvaluator.Instance.Evaluate(new PropOp.Float(r => result = r), exp);
					return result;
				}
				else if (type.Equals(typeof(string))) {
					string result = default(string);
					PdtEvaluator.Instance.Evaluate(new PropOp.String(r => result = r), exp);
					return result;
				}
				else if (type.IsEnum) {
					object result = null;
					PdtEvaluator.Instance.Evaluate(new PropOp.Enum(type, r => result = r), exp);
					return result;
				}
				else if (type.Equals(typeof(Clip))) {
					Clip result = default(Clip);
					PdtEvaluator.Instance.Evaluate(new PropOp.Clip(r => result = r), exp);
					return result;
				}
				else if (type.Equals(typeof(Identifier))) {
					Identifier result = default(Identifier);
					PdtEvaluator.Instance.Evaluate(new pop_identstr(r => result = r), exp);
					return result;
				}
				else if (type.Equals(typeof(Identifier[]))) {
					Identifier[] result = null;
					PdtEvaluator.Instance.Evaluate(new pop_identstrarr(r => result = r), exp);
					return result;
				}
			}
			else if (value is string) {
				var exp = (string)value;
				if (type.Equals(typeof(Identifier))) {
					return new Identifier(exp);
				}
				else if (type == typeof(ScoreOperation)) {
					return new ScoreOperation(exp);
				}
			}
			return base.ChangeType(value, type, culture);
		}
#pragma warning disable IDE1006
		class pop_identstr : PropOp {
			readonly Action<SIdentifier> _cb;
			public pop_identstr(Action<SIdentifier> cb) { _cb = cb; }
			protected override void Execute() {
				var op = GetOperand(0);
				if (op.Type == PdtInternalType.Undefined) _cb(new SIdentifier(op.AsIdentifier()));
				else if (op.Type == PdtInternalType.String) _cb(new SIdentifier(op.AsString()));
				else throw new InvalidCastException("Not an identifier or string");
			}
		}
		class pop_identstrarr : PdtOperator {
			readonly Action<SIdentifier[]> _cb;
			public pop_identstrarr(Action<SIdentifier[]> cb) : base(16) { _cb = cb; }
			protected override void Execute() {
				var result = new SIdentifier[LoadedOperandCount];
				for (int i = 0; i < LoadedOperandCount; i++) {
					var op = GetOperand(i);
					result[i] = new SIdentifier(op.AsIdentifier());
				}
				_cb(result);
			}
		}
#pragma warning restore IDE1006
	}
}
