1 module Engine.Component;
2 
3 
4 import t = Engine.Transform;
5 import std.traits;
6 import e = Engine.Entity;
7 import std.traits;
8 import std.typetuple;
9 
10 abstract class Component
11 {
12 	package e.Entity _entity;
13 
14 	final @property public e.Entity entity() {
15 		return _entity;	
16 	};
17 
18 	final @property public t.Transform transform() {
19 		return _entity.transform;
20 	};
21 
22 	this()
23 	{
24 		
25 	}
26 
27 	final package void bind(e.Entity entity) {
28 		this._entity = entity;
29 	};
30 		
31 	public T Cast(T)() if (is(T == class)) {
32 		auto tptr = cast(T)CastType(typeid(T));
33 		if (tptr)	
34 			return tptr;
35 		return cast(T)this;			
36 	}	
37 
38 	public void* CastType(TypeInfo targetType) {
39 		return null;
40 	}		
41 	
42 	public auto Cast(T)() if (is(T == struct)) {
43 		auto cit = cast(ComponentImpl!T)this;
44 		if (cit)
45 			return cit.Cast!T();
46 		return null;
47 	}	
48 
49 	public auto Cast(T : T*)() if (is(T == struct)) {
50 		auto cit = cast(ComponentImpl!T)this;
51 		if (cit)
52 			return cit.Cast!T();
53 		return null;
54 	}		
55 		
56 
57 	public void OnComponentAdd() {};
58 	public void Awake() {};
59 	public void Start() {};
60 	public void Update() {};
61 	public void LateUpdate() {};
62 
63 	public void OnMessage(string op, void* arg) {
64 
65 	}
66 
67 	final @property public bool hasUpdate() {
68 		return ((&Update).funcptr != (&Component.Update).funcptr);
69 	};
70 
71 	final @property public bool hasStart() {
72 		return ((&Start).funcptr != (&Component.Start).funcptr);
73 	};
74 
75 	final @property public bool hasLateUpdate() {
76 		return ((&LateUpdate).funcptr != (&Component.LateUpdate).funcptr);
77 	};
78 }
79 
80 
81 template ComponentBase()
82 {
83 	
84 	e.Entity _entity;
85 	
86 	final @property public e.Entity entity() {
87 		return _entity;	
88 	};
89 
90 	final @property public t.Transform transform() {
91 		return entity.transform;
92 	};
93 }
94 
95 public class ComponentImpl(T) : Component {
96 
97 	static if (is(T == class)) {
98 		private byte[__traits(classInstanceSize, T)] raw;
99 	} 		
100 	T component;
101 
102 	this()() {
103 		static if (is(T == class)) {
104 			component = cast(T)&raw;
105 			auto l = raw.length;
106 			raw[0..l] = T.classinfo.init[0..l];
107 			static if (__traits(compiles, component.__ctor())) {
108 				component.__ctor();
109 			}
110 		}	
111 	}
112 
113 	this(Args...)(Args args) if (args.length > 0) {
114 		static if (is(T == class)) {
115 			component = cast(T)&raw;
116 			auto l = raw.length;		
117 			raw[0..l] = T.classinfo.init[0..l];
118 			component.__ctor(args);	
119 		} else {	
120 			component = T(args);
121 		}
122 	}
123 
124 	pure T Cast(T)() if (is(T == class)) {
125 		return cast(T)component;
126 	}	
127 
128 	public auto Cast(T)() if (is(T == struct)) {
129 		static if (__traits(compiles, cast(T)&component))
130 			return cast(T)&component;
131 		else
132 			return cast(T*)&component;
133 	}	
134 		
135 	static if(hasMember!(T, "OnMessage"))
136 	public override void OnMessage(string op, void* arg) {
137 		component.OnMessage(op,arg);
138 	}
139 
140 	static if(hasMember!(T, "Awake"))
141 		public override void Awake() {
142 			component.Awake();
143 		}
144 
145 	static if(hasMember!(T, "Update"))
146 	public override void Update() {
147 		component.Update();
148 	}
149 
150 	static if(hasMember!(T, "OnComponentAdd"))
151 	public override void OnComponentAdd() {
152 		component.OnComponentAdd();
153 	}
154 
155 	final package void bind(e.Entity entity) {
156 		super.bind(entity);
157 		(cast(e.Entity)component._entity) = entity;
158 	}
159 
160 	static if(is(T == class))
161     public override void* CastType(TypeInfo targetType)
162     {
163 		alias TypeTuple!(T, ImplicitConversionTargets!T) AllTypes;
164 		foreach (F ; AllTypes)
165 		{
166 			if (targetType != typeid(F) &&
167 				targetType != typeid(const(F)))
168 			{ 
169 				static if (isImplicitlyConvertible!(F, immutable(F)))
170 				{
171 					if (targetType != typeid(immutable(F)))
172 					{
173 						continue;
174 					}
175 				}
176 				else
177 				{
178 					continue;
179 				}
180 			}
181 			return cast(void*)cast(F)component;
182 		}
183 		return null;
184     }
185 }