/*           +------------+
             | 00  01  02 |
             |            |
 Cima   >    | 03  04  05 |
             |            |
             | 06  07  08 |   Direita     Traseira
+------------+------------+------------+------------+
| 09  10  11 | 18  19  20 | 27  28  29 | 36  37  38 |
|            |            |            |            |
| 12  13  14 | 21  22  23 | 30  31  32 | 39  40  41 |
|            |            |            |            |
| 15  16  17 | 24  25  26 | 33  34  35 | 42  43  44 |
+------------+------------+------------+------------+
 Esquerda    | 45  46  47 |
             |            |
             | 48  49  50 |  < Baixo
             |            |
             | 51  52  53 |
             +------------+
                                                   
*/
 
// Bad Practice
String.prototype.replaceAt = function(index, replacement) {
    return this.substr(0, index) + replacement+ this.substr(index + replacement.length);
}
 
module.exports = {
 
  newCube: function () {
    let cube = 'UUUUUUUUULLLLLLLLLFFFFFFFFFRRRRRRRRRBBBBBBBBBDDDDDDDDD'
    return badScramble(cube);
  },
 
  // -----------------------------------
  // Rotations
  // -----------------------------------
 
  rotUpFaceCW: function (cube, times) {
    return rotateFace(cube, times, 0);
  },
 
  rotUpFaceCCW: function (cube, times) {
    return this.rotUpFaceCW(cube, times + 2);
  },
 
  rotLeftFaceCW: function (cube, times) {
    return rotateFace(cube, times, 9);
  },
 
  rotLeftFaceCCW: function (cube, times) {
    return this.rotLeftFaceCW(cube, times + 2);
  },
 
  rotFrontFaceCW: function (cube, times) {
    return rotateFace(cube, times, 18);
  },
 
  rotFrontFaceCCW: function (cube, times) {
    return this.rotFrontFaceCW(cube, times + 2);
  },
 
  rotRightFaceCW: function (cube, times) {
    return rotateFace(cube, times, 27);
  },
 
  rotRightFaceCCW: function (cube, times) {
    return this.rotRightFaceCW(cube, times + 2);
  },
 
  rotBackFaceCW: function (cube, times) {
    return rotateFace(cube, times, 36);
  },
 
  rotBackFaceCCW: function (cube, times) {
    return this.rotBackFaceCW(cube, times + 2);
  },
 
  rotDownFaceCW: function (cube, times) {
    return rotateFace(cube, times, 45);
  },
 
  rotDownFaceCCW: function (cube, times) {
    return this.rotDownFaceCW(cube, times + 2);
  },
}
 
function rotateFace(cube, times, constant) {
  var aux = cube;
  console.log("calling rotateFace(cube="+cube+",times="+times+",constant="+constant+")");
  switch (times) {
    case 1:
      {
        aux = aux.replaceAt(00 + constant, cube[06 + constant]);      
        console.log("replacing", aux[0 + constant], "by", cube[6 + constant]);
        aux = aux.replaceAt(01 + constant, cube[03 + constant]);  
        aux = aux.replaceAt(02 + constant, cube[00 + constant]);    
        aux = aux.replaceAt(03 + constant, cube[07 + constant]);      
        aux = aux.replaceAt(05 + constant, cube[01 + constant]);  
        aux = aux.replaceAt(06 + constant, cube[08 + constant]);
        console.log("replacing", aux[6 + constant], "by", cube[8 + constant]);
        aux = aux.replaceAt(07 + constant, cube[05 + constant]);
        console.log("replacing", aux[7 + constant], "by", cube[5 + constant]);
        aux = aux.replaceAt(08 + constant, cube[02 + constant]);
        console.log("replacing", aux[8 + constant], "by", cube[2 + constant]);
        break;
      }
    case 2:
      {
        aux = aux.replaceAt(00 + constant, cube[08 + constant]);      
        aux = aux.replaceAt(01 + constant, cube[07 + constant]);  
        aux = aux.replaceAt(02 + constant, cube[06 + constant]);    
        aux = aux.replaceAt(03 + constant, cube[05 + constant]);      
        aux = aux.replaceAt(05 + constant, cube[03 + constant]);  
        aux = aux.replaceAt(06 + constant, cube[02 + constant]);
        aux = aux.replaceAt(07 + constant, cube[01 + constant]);
        aux = aux.replaceAt(08 + constant, cube[00 + constant]);
        break;
      }
    case 3:
      {
        aux = aux.replaceAt(00 + constant, cube[02 + constant]);      
        aux = aux.replaceAt(01 + constant, cube[05 + constant]);  
        aux = aux.replaceAt(02 + constant, cube[08 + constant]);    
        aux = aux.replaceAt(03 + constant, cube[01 + constant]);      
        aux = aux.replaceAt(05 + constant, cube[07 + constant]);  
        aux = aux.replaceAt(06 + constant, cube[00 + constant]);
        aux = aux.replaceAt(07 + constant, cube[03 + constant]);
        aux = aux.replaceAt(08 + constant, cube[06 + constant]);
        break;
      }
    default:
      {
        console.log('Defaulting to cube...');
        return cube;
      }
  }
  return aux;
}
 
function badScramble(cube) {
  var scrumbled = cube;
  for (let i = 0; i < 35; i++) {
    let random = Math.random();
    let z = random % 2 ? 1 : 3;
    if (random < 0.16)
      scrumbled = module.exports.rotUpFaceCW(scrumbled, z);
    else if (random < 0.32)
      scrumbled = module.exports.rotLeftFaceCW(scrumbled, z);
    else if (random < 0.48)
      scrumbled = module.exports.rotFrontFaceCW(scrumbled, z);
    else if (random < 0.64)
      scrumbled = module.exports.rotRightFaceCW(scrumbled, z);
    else if (random < 0.80)
      scrumbled = module.exports.rotBackFaceCW(scrumbled, z);
    else if (random < 0.96)
      scrumbled = module.exports.rotDownFaceCW(scrumbled, z);
  }
  return scrumbled;
}
 
(() => {
  console.log('Vamos começar com um cubo nessa formação: UUUUUUUUULLLLLLLLLFFFFFFFFFRRRRRRRRRBBBBBBBBBDDDDDDDDD');
  console.log('Vamos embaralhar!')
  console.log(`Cubo embaralhado: ${module.exports.newCube()}`)
})();
