//
// The Rubix cube program 
// Copyright c Brian P. Vogl
// October 3 - 6, 2018
// Revised JS version 
// Started June 14 2018

var CD = [  //new int[6][9]; Color of each square
	[ 1, 1, 1, 1, 1, 1, 1, 1, 1 ],	// Green face
	[ 2, 2, 2, 2, 2, 2, 2, 2, 2 ],	// Yellow face
	[ 3, 3, 3, 3, 3, 3, 3, 3, 3 ],	// Red face
	[ 4, 4, 4, 4, 4, 4, 4, 4, 4 ],	// Blue face
	[ 5, 5, 5, 5, 5, 5, 5, 5, 5 ],	// White face
	[ 6, 6, 6, 6, 6, 6, 6, 6, 6 ] ];	// Orange face
var AP = [	//new int[12][6][2];  Rotation Rules
	[[4,6], [3,6], [3,0], [4,2], [3,2], [3,8]],	
	[[4,7], [3,7], [3,3], [4,1], [3,1], [3,5]],
	[[4,8], [3,8], [3,6], [4,0], [3,0], [3,2]],
	[[2,6], [5,0], [1,0], [5,2], [2,0], [4,0]],
	[[2,7], [5,3], [1,3], [5,1], [2,3], [4,3]],
	[[2,8], [5,6], [1,6], [5,0], [2,6], [4,6]],
	[[1,6], [0,6], [0,8], [1,2], [0,2], [0,0]],
	[[1,7], [0,7], [0,5], [1,1], [0,1], [0,3]],
	[[1,8], [0,8], [0,2], [1,0], [0,0], [0,6]],
	[[5,6], [2,8], [4,8], [2,2], [5,8], [1,8]],
	[[5,7], [2,5], [4,5], [2,1], [5,5], [1,5]],
	[[5,8], [2,2], [4,2], [2,0], [5,2], [1,2]]	];
// Polygon vertices, (X,Y) polygon number (0-2) and index into CD array.

var QP = [  //new int[5][54];
	[139,473,475, 93,185,427,521, 47,139,231,381,473,475,567,  2, 93,185,276,	// X
	 427,521, 48,139,230,381,473,475,567,  2, 94,184,276,427,474,521, 48,230,
	 381,428,520,567,  2, 94,184,276,382,474,566, 48,230,428,520, 94,184,474 ],
	[ -8,-10,-10,  8,  8,  6,  6, 24, 24, 24, 22, 20, 20, 22, 40, 40, 40, 40,	// Y
	  36, 36, 56, 56, 56, 52, 50, 50, 52, 70, 72, 72, 70, 66, 80, 66, 86, 86,
	  82, 96, 96, 82,100,102,102,100,112,112,112,116,116,128,128,132,132,144 ],
	[0,2,1,0,0,2,1,0,0,0,2,2,1,1,1,0,0,2,2,1,1,0,2,2,2,1,1,		// Polygon type
	 1,1,2,2,2,0,1,1,2,2,0,0,1,1,1,2,2,0,0,0,1,2,0,0,1,2,0  ],
	[0,5,4,0,0,5,4,0,0,0,5,5,4,4,1,0,0,2,5,4,1,0,2,5,5,4,4,		// X index into CD
	 1,1,2,2,5,3,4,1,2,5,3,3,4,1,1,2,2,3,3,3,1,2,3,3,1,2,3  ],
	[0,8,6,3,1,7,7,6,4,2,6,5,3,8,8,7,5,6,4,4,7,8,7,3,2,0,5,		// Y index into CD
	 5,6,8,3,1,2,1,4,4,0,5,1,2,2,3,5,0,8,4,0,1,1,7,3,0,2,6  ]  ];

var RP = [  //new int[4][42];  Points (X1,Y1)-(X2,Y2) lines
	[  1,  1,139,277,277,139,  1,139,231, 93,185, 47, 93,231,	// X1
	  47,185,139,  1,139,  1,139,336,474,612,612,474,336,336,
	 474,566,428,520,382,428,566,382,520,474,336,474,336,474 ],
	[ 39,129,177,129, 39, -9, 39, 87, 23, 71,  7, 55,  7, 55,	// Y1
	  23, 71, 87, 69,117, 99,147,127,175,127, 37,-11, 37,127,
	  79,143, 95,159,111,159,111,143, 95, 79, 67, 19, 97, 49 ],
	[  1,139,277,277,139,  1,139,277, 93, 93, 47, 47,231,231,	// X2
	 185,185,139,139,277,139,277,474,612,612,474,336,336,474,
	 612,428,428,382,382,566,566,520,520,474,474,612,474,612 ],
	[129,177,129, 39, -9, 39, 87, 39, 71,161, 55,145, 55,145,	// Y2
	  71,161,177,117, 69,147, 99,175,127, 37,-11, 37,127, 79,
	 127, 95,  5,111, 21,111, 21, 95,  5,-11, 19, 67, 49, 97 ] ];

var PP = [ 0,2,8,6,1,5,7,3 ];

var canvas = document.getElementById("thecanvas");
canvas.style.backgroundColor = "white";
var ctx;
if(ctx = canvas.getContext('2d'))
{	canvas.oncontextmenu = function (event) {
		event.preventDefault();
		MousePos(event);
	};
	do_display(ctx);
	document.addEventListener("click", MousePos);
}

function leftofline(rp, xc, yc)
{    // Returns true if point is left of or below the RP line
     if(RP[2][rp] == RP[0][rp]) return ( xc < RP[0][rp] );
     var m = ((RP[3][rp] - RP[1][rp]) / (RP[2][rp] - RP[0][rp]));
     var b = RP[1][rp] - parseInt(RP[0][rp] * m);
     return ( yc < ( m * xc + b ));
}

function incenter(rp1, rp2, rp3, rp4, xc, yc)
{	// Returns true if point is in the center of the box bounded by the 4 RP lines.
	return( leftofline(rp1, xc, yc) && !leftofline(rp2, xc, yc) &&
		  leftofline(rp3, xc, yc) && !leftofline(rp4, xc, yc));
}

function MousePos(event) 
{    // Determine which face and which button was pressed over it
     var bbox = canvas.getBoundingClientRect();
     var xs = event.clientX - 20 - bbox.left;
     var ys = event.clientY / 2 - 35 - bbox.top;
     var buttstate = event.which > 1 ? 1 : 0;
     var fc = -1;
     if(incenter( 6, 5, 7, 4, xs, ys)) fc = 0; // GREEN Face
     if(incenter( 1, 6,16, 0, xs, ys)) fc = 1; // YELLOW Face
     if(incenter( 2, 7, 3,16, xs, ys)) fc = 2; // RED Face
     if(incenter(21,27,22,28, xs, ys)) fc = 3; // BLUE Face
     if(incenter(28,24,23,37, xs, ys)) fc = 4; // WHITE Face
     if(incenter(27,25,37,26, xs, ys)) fc = 5; // ORANGE Face
     if(fc >= 0)
     {    if(buttstate == 0)
          {	   rotateDn(fc);
          }
          if(buttstate == 1)
          {    rotateUp(fc);
          }
	    do_display();
     }
}

function rotateUp(fc)		// An upper button was desired
{    var TCD = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 
     var n, t, p, tmp;
     for(n=0; n<=1; n++)  // Translate the face of the cube
     {   tmp = CD[fc][PP[n*4]];
          for(t=0; t<=2; t++) CD[fc][PP[n*4+t]] = CD[fc][PP[n*4+t+1]];
          CD[fc][PP[n*4+3]] = tmp;
     }	// Translate the sides of the cube
     for(p=0; p<12; p++) TCD[p] = CD[AP[p][fc][0]][AP[p][fc][1]];
     for(n=0; n<=2; n++)
     {   tmp = TCD[n];
          for(t=0; t<=2; t++) TCD[n+t*3] = TCD[n+(t+1)*3];
          TCD[n+9] = tmp;
     } for(p=0; p<12; p++) CD[AP[p][fc][0]][AP[p][fc][1]] = TCD[p];
}

function rotateDn(fc)       // A lower button was desired 
{    var TCD = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 
     var n, t, p, tmp;
     for(n=1; n>=0; n--)  // Translate the face of the cube
     {    tmp = CD[fc][PP[n*4+3]];
          for(t=2; t>=0; t--) CD[fc][PP[n*4+t+1]] = CD[fc][PP[n*4+t]];
          CD[fc][PP[n*4]] = tmp;
     }    // Translate the sides of the cube
	for(p=0; p<12; p++) TCD[p] = CD[AP[p][fc][0]][AP[p][fc][1]];
     for(n=2; n>=0; n--)
     {    tmp = TCD[n+9];
          for(t=2; t>=0; t--) TCD[n+(t+1)*3] = TCD[n+t*3];
          TCD[n] = tmp;
     } for(p=0; p<12; p++) CD[AP[p][fc][0]][AP[p][fc][1]] = TCD[p];
}

function do_display()
{   var k, Xo, Yo;
    ctx.beginPath();
    ctx.lineWidth=3;
    ctx.strokeStyle = '#000000';     
    var polyX = [ 0, 0, 0, 0, 0 ];
    var polyY = [ 0, 0, 0, 0, 0 ];

    for(k=0; k < 42; k++)		// Draw the cube grid first
    {    ctx.moveTo(RP[0][k]+20, (RP[1][k]+35)*2);
         ctx.lineTo(RP[2][k]+20, (RP[3][k]+35)*2);
    }
    ctx.stroke();

    ctx.lineWidth=1;
    for(var k=0; k<54; k++)
    {   Xo = QP[0][k]+20;		// Determine the offset of the polygons
        Yo = QP[1][k]+35;
        polyX[0] = Xo;	polyY[0] = 2*Yo; 
        polyX[4] = Xo; polyY[4] = 2*Yo;

        switch(QP[2][k])
        {    // Select the polygon to draw
             case 0: polyX[1] = Xo-45;	polyY[1] = 2*(Yo+15);
                     polyX[2] = Xo; 	polyY[2] = 2*(Yo+30);
                     polyX[3] = Xo+45;	polyY[3] = 2*(Yo+15);	break;
             case 1: polyX[1] = Xo;	polyY[1] = 2*(Yo+28);
                     polyX[2] = Xo+44;	polyY[2] = 2*(Yo+44);
                     polyX[3] = Xo+44;	polyY[3] = 2*(Yo+16);	break;
             case 2: polyX[1] = Xo-44;	polyY[1] = 2*(Yo+16);
                     polyX[2] = Xo-44;	polyY[2] = 2*(Yo+44);
                     polyX[3] = Xo;	polyY[3] = 2*(Yo+28);	break;
        }
         ctx.beginPath();
         ctx.moveTo(polyX[0], polyY[0]);
         ctx.lineTo(polyX[1], polyY[1]);
         ctx.lineTo(polyX[2], polyY[2]);
         ctx.lineTo(polyX[3], polyY[3]);
         ctx.closePath();
         switch(CD[QP[3][k]][QP[4][k]])
         {   // Select the color to appear on the face of the polygon
             case 1 : ctx.fillStyle = 'green';	break;
             case 2 : ctx.fillStyle = 'yellow';	break;
             case 3 : ctx.fillStyle = 'red';		break;
             case 4 : ctx.fillStyle = 'blue';		break;
             case 5 : ctx.fillStyle = 'white';	break;
             case 6 : ctx.fillStyle = 'orange';	break;
         }	// Finally draw the polygon.
         ctx.fill();
         ctx.stroke();
	}
}