using Cryville.Common.Pdt;
using System;
using RBeatTime = Cryville.Crtr.BeatTime;

namespace Cryville.Crtr {
	public abstract class PropSrc {
		int _type;
		protected byte[] buf = null;
		protected virtual bool Invalidated { get { return buf == null; } }
		public virtual void Invalidate() { buf = null; }
		public void Get(out int type, out byte[] value) {
			if (Invalidated) _type = InternalGet();
			type = _type;
			value = buf;
		}
		protected abstract int InternalGet();
		public class Arbitrary : PropSrc {
			public int Type { get; private set; }
			readonly byte[] _value;
			public Arbitrary(int type, byte[] value) {
				Type = type;
				_value = value;
			}
			protected override int InternalGet() {
				buf = _value;
				return Type;
			}
		}
		public class Boolean : PropSrc {
			readonly Func<bool> _cb;
			bool m_invalidated = true;
			protected override bool Invalidated { get { return m_invalidated; } }
			public override void Invalidate() { m_invalidated = true; }
			public Boolean(Func<bool> cb) { _cb = cb; buf = new byte[4]; }
			protected override int InternalGet() {
				m_invalidated = false;
				buf[0] = _cb() ? (byte)1 : (byte)0;
				return PdtInternalType.Number;
			}
		}
		public class Float : PropSrc {
			readonly Func<float> _cb;
			bool m_invalidated = true;
			protected override bool Invalidated { get { return m_invalidated; } }
			public override void Invalidate() { m_invalidated = true; }
			public Float(Func<float> cb) { _cb = cb; buf = new byte[4]; }
			protected override unsafe int InternalGet() {
				m_invalidated = false;
				fixed (byte* _ptr = buf) {
					*(float*)_ptr = _cb();
				}
				return PdtInternalType.Number;
			}
		}
		public class String : PropSrc {
			readonly Func<string> _cb;
			public String(Func<string> cb) { _cb = cb; }
			protected override unsafe int InternalGet() {
				var v = _cb();
				int strlen = v.Length;
				buf = new byte[strlen * sizeof(char) + sizeof(int)];
				fixed (byte* _ptr = buf) {
					char* ptr = (char*)(_ptr + sizeof(int));
					*(int*)_ptr = strlen;
					int i = 0;
					foreach (var c in v) ptr[i++] = c;
				}
				return PdtInternalType.String;
			}
		}
		public class Identifier : PropSrc {
			readonly Func<int> _cb;
			public Identifier(Func<int> cb) { _cb = cb; }
			protected override int InternalGet() {
				buf = BitConverter.GetBytes(_cb());
				return PdtInternalType.Undefined;
			}
		}
		public class BeatTime : PropSrc {
			readonly Func<RBeatTime> _cb;
			public BeatTime(Func<RBeatTime> cb) { _cb = cb; }
			protected override unsafe int InternalGet() {
				var bt = _cb();
				buf = new byte[4 * sizeof(int)];
				fixed (byte* _ptr = buf) {
					int* ptr = (int*)_ptr;
					*ptr++ = bt.b;
					*ptr++ = bt.n;
					*ptr++ = bt.d;
					*ptr++ = PdtInternalType.Number;
				}
				return PdtInternalType.Vector;
			}
		}
	}
}
