module math.vector;

private enum options : bool {
	name_xyzw	= true,
}

struct vector(T, uint N) {
	
	this(U...)(U values) if (U.length == N) {
		assign!(N)(values);
	}
	
	void assign(uint P, U...)(U values) {
		elems_[P - 1] = values[P - 1];
		static if(P > 1)
			assign!(P-1)(values);
	}
	
	void swizzle(string s, uint P, U)(ref U m) {
			static if(s[P-1] == 'x'	|| s[P-1] == 'r')	m.elems_[P-1] = elems_[0];
		else	static if(s[P-1] == 'y'	|| s[P-1] == 'g')	m.elems_[P-1] = elems_[1];
		else	static if(s[P-1] == 'z'	|| s[P-1] == 'b')	m.elems_[P-1] = elems_[2];
		else	static if(s[P-1] == 'w'	|| s[P-1] == 'a')	m.elems_[P-1] = elems_[3];
		else	static assert(0);
		
		static if(P > 1)
			swizzle!(s, P-1)(m);
	}
	
	vector!(T, s.length) opDispatch(string s)() {
		typeof(return) m;
		swizzle!(s, s.length)(m);
		return m;
	}
	
	private T[N] elems_;
}

alias vector!(float, 2) vec2;
alias vector!(float, 3) vec3;
alias vector!(float, 4) vec4;
alias vector!(float, 9) vec9;

private import std.stdio : writeln;

unittest {
	vec2 a = vec2(1.0f, 2.0f);
	vec3 b = vec3(1.0f, 2.0f, 3.0f);
	vec4 c = vec4(1.0f, 2.0f, 3.0f, 4.0f);
	vec4 d = b.zzzz;
	vec4 e = a.xyxy;
	vec9 f = c.wwwwwwwww;
	vec9 g = c.bbbbbbbbb;
	
	assert(a != b.xx);
	assert(a == b.xy);
	assert(b.xyz == c.xyz);
	assert(c.wwzy == vec4(4, 4, 3, 2));
	assert(c.zzz == vec3(3, 3, 3));
	assert(f == vec9(4, 4, 4, 4, 4, 4, 4, 4, 4));
	assert(g == vec9(3, 3, 3, 3, 3, 3, 3, 3, 3));
	
	writeln("a: ", 	a.tupleof);
	writeln("b: ", 	b.tupleof);
	writeln("c: ", 	c.tupleof);
	writeln("d: ", 	d.tupleof);
	writeln("e: ", 	e.tupleof);
	writeln("f: ",  	f.tupleof);
	writeln("g: ", 	g.tupleof);
}

int main() {
	return 0;
}
