function app1(p,a,c1,c2){
	var l = Math.cos(a)*p[c1]+Math.sin(a)*p[c2]
	var k = -Math.sin(a)*p[c1]+Math.cos(a)*p[c2]
	p[c1] = l
	p[c2] = k
}

function app2(p,a,c1,c2){
	var l = Math.cos(a)*p[c1]-Math.sin(a)*p[c2]
	var k = Math.sin(a)*p[c1]+Math.cos(a)*p[c2]
	p[c1] = l
	p[c2] = k
}

var _edges
function tesseractedges(){
	if(!_edges){
		var m = tesseractwithrotation(0,0,0,0,0,0)
		var edges = []
		var indicies = ['x','y','z','w']
		for (var i = 0; i < m.length; i++) {
			for (var j = i+1; j < m.length; j++) {
				var count = 0
				for (var k = 0; k < 4; k++) {
					if (m[i][indicies[k]] === m[j][indicies[k]]) count++
				};
				if (count === 3) edges.push([i,j])
			}
		}
		_edges = edges
	}
	return _edges	
}

function tesseractwithrotation(a,b,c,d,e,f) {
	var verticies = []
	for (var i = 0; i < 16; i++) {
		var p = {
			x: (i&1)*2 - 1,
			y: ((i>>1)&1)*2 - 1,
			z: ((i>>2)&1)*2 - 1,
			w: ((i>>3)&1)*2 - 1
		}
		app1(p,a,'x','y')
		app1(p,b,'y','z')
		app1(p,c,'x','w')
		app2(p,d,'x','z')
		app2(p,e,'y','w')
		app2(p,f,'z','w')
		verticies.push(p)
	}
	return verticies
}

function project(point, size){
	return {
		x: (point.x+Math.SQRT2*point.z)*size,
		y: (point.y+Math.SQRT2*point.w)*size
	}
}

function drawtesseract(ctx, tesseract, opts){
	var edges = tesseractedges()
	for (var i = 0; i < tesseract.length; i++) {
		var proj = project(tesseract[i], opts.size)
		ctx.beginPath()
		ctx.arc(proj.x + opts.x, proj.y + opts.y, opts.corner_radius, 0, 2 * Math.PI)
		ctx.fill()
	};
	ctx.lineWidth = opts.line_width || 1
	ctx.beginPath()
	for (var i = 0; i < edges.length; i++) {
		var v1 = project(tesseract[edges[i][0]], opts.size), 
			v2 = project(tesseract[edges[i][1]], opts.size)
		ctx.moveTo(v1.x+opts.x,v1.y+opts.y)
		ctx.lineTo(v2.x+opts.x,v2.y+opts.y)
	};
	ctx.stroke()
}