var red = "#DC143C"; //rosso
var white = "#FFFFFF"; //bianco
var blue = "#0000CD"; //blu
var green = "#008800"; //verde
var orange = "#FFA500"; //arancione
var yellow = "#FFFF00"; //giallo
var black = "#000000"; //nero
var blue_chiaro = "#6495ED"; //blu chiaro

function Cubo(dim,lavagna_canvas)
{
   /*Private:*/

   /*La dimensione puo' variare tra 2x2x2 3x3x3 [..] NxNxN*/
   this.dimensione = dim;

   /*Lunghezza di ogni Cubetto che forma il Cubo*/
   this.length_cubetto = null;
   /*Lunghezza del Cubo*/
   /*Non strettamente necessaria (ma conveniente)*/
   this.length_cubo = null;

   /*Lavagna su cui Renderizzare il Cubo e sue proprieta'. Si tratta di un contenitore Canvas*/
   /*Formato [obj_canvas,lato,colore_sfondo]*/
   this.lavagna = null;

   /*Lavgana Temporanea. In fase di Renderizzazione la Lavagna viene settata con il suo contenuto*/
   this.lavagna_tmp = lavagna_canvas;

   /*Contiene il riferimento alla Funzione che Risolve il Cubo*/
   this.avvia_risolutore = null;

   /*Contiene il riferimento ad un Oggetto Barra che Implementa i Metodi Pubblici Richiesti dal Cubo*/
   this.barra = null;

   /*Colore Iniziale delle Facce*/
   /*Formato deve essere [[Colori Non Attivo],[Colori Attivo]]*/
   /*Formato dei Colori deve essere [B,F,N,S,E,O]*/
   /*B-->Back F-->Front N-->Nord S-->Sud E-->Est O-->Ovest*/
   this.colore_faccia = null;

   /*Colore Bordo attorno agli Adesivi*/
   /*Formato deve essere [SottoCubo Non Attivo,SottoCubo Attivo]*/
   this.colore_bordo = null;

   /*Matrice RAW contenente Mappatura Adesivi*/
   /*Formato deve essere [B,F,N,S,E,O]*/
   /*B-->Back F-->Front N-->Nord S-->Sud E-->Est O-->Ovest*/
   /*B e F si mappano a partire da Adesivo in Alto a Sinistra*/
   /*N e S si mappano a partire da Adesivo in Fondo a Sinistra*/
   /*E e O si mappano a partire da Adesivo in Alto e Vicino*/
   this.matrix_adesivi = null;

   /*Normale Originale al Cubo che descrive l'Orientamento Iniziale del Cubo*/
   this.normale_originale = null;

   /*Normale al Cubo che descrive l'Orientamento del Cubo*/
   this.normale_ruotata = null;

   /*SottoCubi che formano il Cubo*/
   this.sottocubo = new Array(3);
   /*I SottoCubi possono essere 3 o 2*/
   this.num_sottocubi = null;
   /*SottoCubo Selezionato*/
   this.sottocubo_attivo = null;

   /*Normale al "Set di Blocchi" Attuale nella forma [1,0,0] o [1,0,0] o [0,0,1]*/
   this.normale_blocchi = null;
   /*Blocco Selezionato*/
   this.blocco_attivo = null;

   /*Contiene lo Stato Attuale della Rotazione del Blocco durante l'Animazione*/
   this.StatoRotazioneBlocco = null;

   /*Contiene il Livello di Qualita' delle Animazioni*/
   /*Se vale 0 la qualita' è bassa ossia una rotazione viene Renderizzata nel minor tempo possibile*/
   /*Se vale 1 la qualita' è mediobassa*/
   /*Se vale 2 la qualita' è medioalta*/
   /*Se vale 3 la qualita' è alta ossia una rotazione viene Renderizzata in un tempo accettabile*/
   this.Qualita_Animazione = null;

   /*Contiene il Livello di Qualita' delle Animazioni Richiesto*/
   /*Appena possibile il Cubo settera' il Nuovo valore di Qualita'*/
   this.Qualita_Animazione_Richiesta = null;

   /*Coda delle Mosse da Renderizzare*/
   this.coda_mosse = null;

   /*Indice dell'ultima mossa in Coda Mosse*/
   this.coda_testa = null;

   /*Indica il Tipo di Coda. Puo' essere una Coda di Mescolamento o di Risoluzione*/
   this.coda_tipo = null;

   /*Indice della mossa da Renderizzare in Coda Mosse*/
   this.coda_mossa_attuale = null;

   /*Matrice RAW contenente Mappatura Adesivi su cui agiranno le mosse in Coda Mosse*/
   this.coda_matrix_adesivi = null;

   /*Metodo per Settare la Mossa Attuale della Coda Mosse*/
   /*Deve essere passato il valore della nuova mossa attuale*/
   this.coda_setta_mossa_attuale = Cubo_Setta_Mossa_Attuale_Coda;

   /*Contiene lo Stato Attuale del Mouse*/
   this.StatoMouse = null;

   /*Contiene il Punto della Lavagna dove è stato Pigiato il Mouse*/
   this.Mouse_Punto_Down = null;

   /*Contiene informazioni sull'Adesivo Pigiato nel formato [faccia,x,y]*/
   this.Adesivo_Pigiato = null;

   /*Contiene informazioni sui tentativi da provare per far funzionare il mouse*/
   /*Formato [[asse,blocco],[asse,blocco],evento]*/
   this.Mouse_Tentativo = null;

   /*Sequenza di mosse utilizzata da ruota_sequenza*/
   this.seq;

   /*Metodo per copiare il contenuto di matrice_adesivi in coda_matrice_adesivi o viceversa*/
   /*Devono essere passate 2 matrici. La prima diventera' uguale alla seconda*/
   this.eguaglia_matrici = Rende_Uguali_Matrici;

   /*Metodo per Generare i SottoCubi in base al "Set di Blocchi" e al Blocco Selezionati*/
   this.genera_sottocubi = GeneraSottoCubi;

   /*Metodo per Rigenerare i SottoCubi e ristabilire il giusto Orientamento*/
   this.rigenera_sottocubi = RigeneraSottoCubi;

   /*Metodo per la rotazione del SottoCubo Attivo sulla sua Normale*/
   /*La rotazione relativa al Cubo deve essere di un angolo compreso tra 0 e 90 o tra 0 e -90*/
   this.ruota_sottocubo = ruotaSottoCubo; //attorno alla Normale

   /*Renderizza Animazione rotazione di 90 o 180 gradi a seconda del tipo passato*/
   /*Deve essere passato un tipo (0 per "up",1 per "down",2 per "double"*/
   this.ruota_blocco = ruotaBlocco; //attorno alla Normale

   /*Metodo che serve a ruotare la matrice di una faccia*/
   /*E' utilizzato dal metodo "cubo_mossa"*/
   this.cubo_mossa_ruota_matrice = Cubo_Mossa_Ruota_Matrice;

   /*Metodo per l'esecuzione di una Mossa*/
   this.cubo_mossa = Cubo_Esegui_Mossa;

   /*Matodo per ruotare una sequenza di mosse*/
   /*Devono essere passati il numero di mosse della sequenza, un asse e un tipo*/
   /*La sequenza elaborata e' contenuta in "seq"*/
   this.sequenza_ruota = Cubo_Sequenza_Ruota;

   /*Metodo per Renderizzare la Coda di Mosse*/
   this.esegui_coda_mosse = Cubo_Esegui_Coda_Mosse;

   /*Metodo per Calcolare il Punto di intersezione di un Raggio Visuale con il Piano su cui giace una Faccia*/
   /*Deve essere passato un indice di sottocubo e di faccia e un punto nel formato [x,y]*/
   /*Il metodo ritorna il Punto di Intersezione col Piano su cui giace la Faccia indicata nel formato [x,y,z]*/
   this.intersezione_faccia = Calc_Intersezione_Faccia;

   /*Metodo che implementa l'interfaccia tra Cubo e Mouse o Tastiera*/
   /*Deve essere passato l'evento appropriato e il tipo ossia mouse o tastiera*/
   this.mouse_tastiera = Cubo_Mouse_Tastiera;

   /*Public:*/

   /*Contiene lo Stato Attuale del Cubo*/
   /*Serve a gestire la Sincronizzazione delle varie operazioni richieste da eseguire*/
   this.StatoCubo = null;

   /*Contiene lo Stato Attuale dell'Animazione della Coda*/
   this.StatoAnimazioneCoda = null;

   /*Metodo di Inizializzazione*/
   this.init = InitCubo;

   /*Metodi per la rotazione del Cubo*/
   this.ruotaX = ruotaXCubo; //attorno all'asse x
   this.ruotaY = ruotaYCubo; //attorno all'asse y

   /*Metodo per Settare la Normale al "Set di Blocchi" Attuale*/
   /*Normale nella forma [0,-1,0] [1,0,0] ecc.*/
   this.SetNormale_SetBlocchi = SettaNormale_Set_Blocchi;

   /*Metodo per Settare il Blocco Attivo nel "Set di Blocchi" Attuale*/
   this.Set_Blocco = Setta_Blocco_Attivo;

   /*Metodi per la Selezione del Blocco Attivo nel "Set di Blocchi" Attuale*/
   /*Seleziona il Blocco Successivo (se ultimo+1 --> primo)*/
   this.select_blocco_up = Select_Block_UP;
   /*Seleziona il Blocco Precedente (se primo-1 --> ultimo)*/
   this.select_blocco_down = Select_Block_DOWN;

   /*Metodi per la rotazione del Blocco Attivo sulla sua Normale*/
   /*Renderizza Animazione rotazione di 90 gradi*/
   this.ruota_blocco_up = ruotaBlocco_UP; //attorno alla Normale
   /*Renderizza Animazione rotazione di -90 gradi*/
   this.ruota_blocco_down = ruotaBlocco_DOWN; //attorno alla Normale
   /*Renderizza Animazione rotazione di 180 gradi*/
   this.ruota_blocco_double = ruotaBlocco_DOUBLE; //attorno alla Normale

   /*Metodi di Interfaccia alla Tastiera*/
   this.freccia_up = Cubo_freccia_UP;
   this.freccia_down = Cubo_freccia_DOWN;
   this.freccia_left = Cubo_freccia_LEFT;
   this.freccia_right = Cubo_freccia_RIGHT;

   /*Metodi di Interfaccia al Mouse*/
   /*Devono essere passate le coordinate X,Y dell'evento*/
   this.mouse_down = Cubo_Mouse_DOWN;
   this.mouse_up = Cubo_Mouse_UP;
   this.mouse_move = Cubo_Mouse_MOVE;

   /*Metodo per Settare la Lavagna su cui Renderizzare il Cubo*/
   /*Devono essere passato un vettore con Formato [obj_canvas,lunghezza,altezza,colore_sfondo]*/
   this.Setta_Lavagna = Set_Lavagna;

   /*Metodo per Settare la Qualita' delle Animazioni*/
   /*Deve essere passato il valore di qualita'*/
   this.Setta_Qualita_Animazione = Set_Qualita_Animazione;

   /*Metodo per Assegnare un Risolutore*/
   /*Deve essere passata una funzione che ha il compito di risolvere il Cubo*/
   /*Al momento della Risoluzione il Cubo passa il riferimento a se stesso alla Funzione di Risoluzione*/
   this.assegna_risolutore = AssegnaRisolutore;

   /*Metodo per Assegnare un Oggetto Barra che gestisca l'Animazione delle Mosse*/
   /*Deve essere passato un riferimento dell'Oggetto Barra*/
   this.assegna_barra = AssegnaBarra;

   /*Metodo per Mescolare il Cubo*/
   /*Deve essere passato il numero di mosse da eseguire e un valore per attivare/disattivare l'Animazione*/
   /*Se il valore e' 1 il Mescolamento è Animato se 0 Non Animato*/
   this.mescola = Cubo_Mescola;

   /*Metodo per Risolvere il Cubo*/
   this.risolvi = Cubo_Risolvi;

   /*Metodo per la Renderizzazione*/
   this.draw = drawCubo;
}

function InitCubo()
{
   /*Contiene lo Stato Attuale del Cubo*/
   /*Serve a gestire la Sincronizzazione delle varie operazioni richieste da eseguire*/
   this.StatoCubo = "Occupato";

   /*Lavagna su cui Renderizzare il Cubo e sue proprieta'. Si tratta di un contenitore Canvas*/
   /*Formato [obj_canvas,lato,colore_sfondo]*/
   this.lavagna = null;

   /*Lavgana Temporanea. In fase di Renderizzazione la Lavagna viene settata con il suo contenuto*/
   this.lavagna_tmp[0] = this.lavagna_tmp[0].getContext('2d');

   /*Lunghezza di ogni Cubetto che forma il Cubo*/
   this.length_cubetto = Math.round((this.lavagna_tmp[1]/2)*100/this.dimensione)/100;
   /*Lunghezza del Cubo*/
   /*Non strettamente necessaria (ma conveniente)*/
   this.length_cubo = this.length_cubetto*this.dimensione;

   /*Contiene il riferimento alla Funzione che Risolve il Cubo*/
   this.avvia_risolutore = null;

   /*Contiene il riferimento ad un Oggetto Barra che Implementa i Metodi Pubblici Richiesti dal Cubo*/
   this.barra = null;

   /*Colore Iniziale delle Facce*/
   /*Formato deve essere [[Colori Non Attivo],[Colori Attivo]]*/
   /*Formato dei Colori deve essere [B,F,N,S,E,O]*/
   /*B-->Back F-->Front N-->Nord S-->Sud E-->Est O-->Ovest*/
   this.colore_faccia = new Array(2);
   this.colore_faccia[0] = [yellow,green,orange,red,white,blue];
   this.colore_faccia[1] = [yellow,green,orange,red,white,blue];

   /*Colore Bordo attorno agli Adesivi*/
   /*Formato deve essere [SottoCubo Non Attivo,SottoCubo Attivo]*/
   this.colore_bordo = [black,blue_chiaro];

   /*Matrice RAW contenente Mappatura Adesivi e Matrice Coda Mosse*/
   /*Formato deve essere [B,F,N,S,E,O]*/
   /*B-->Back F-->Front N-->Nord S-->Sud E-->Est O-->Ovest*/
   this.matrix_adesivi = new Array(6);
   this.coda_matrix_adesivi = new Array(6);

   for(var f=0;f<6;f++)
   {
      this.matrix_adesivi[f] = new Array(this.dimensione);
      this.coda_matrix_adesivi[f] = new Array(this.dimensione);

      for(var a=0;a<this.dimensione;a++)
      {
         this.matrix_adesivi[f][a] = new Array(this.dimensione);
         this.coda_matrix_adesivi[f][a] = new Array(this.dimensione);

         for(var b=0;b<this.dimensione;b++)
         {
            this.matrix_adesivi[f][a][b] = f;
            this.coda_matrix_adesivi[f][a][b] = f;
         }
      }
   }

   /*Normale Originale al Cubo che descrive l'Orientamento Iniziale del Cubo*/
   this.normale_originale = [0,1,0];

   /*Normale al Cubo che descrive l'Orientamento del Cubo*/
   this.normale_ruotata = new Coord([0,1,0]);
   this.normale_ruotata.init();

   /*Inizialmente abbiamo 2 SottoCubi*/
   this.num_sottocubi = (this.dimensione != 2)?3:2;
   /*SottoCubo Selezionato*/
   this.sottocubo_attivo = (this.dimensione != 2)?1:0;

   /*Normale di Selezione Blocchi Attuale*/
   this.normale_blocchi = [0,1,0];
   /*Blocco Selezionato*/
   this.blocco_attivo = (this.dimensione%2 == 0)?(this.dimensione/2-1):((this.dimensione-1)/2);

   /*Genero i 2 Sottocubi Iniziali*/
   this.genera_sottocubi();

   /*Coda delle Mosse da Renderizzare*/
   this.coda_mosse = new Array();

   /*Indice dell'ultima mossa in Coda Mosse*/
   this.coda_testa = 0;

   /*Indice della mossa da Renderizzare in Coda Mosse*/
   this.coda_mossa_attuale = -1;

   /*Indica il Tipo di Coda. Puo' essere una Coda di Mescolamento o di Risoluzione*/
   this.coda_tipo = null;

   /*Contiene lo Stato Attuale della Rotazione del Blocco durante l'Animazione*/
   this.StatoRotazioneBlocco = 0;

   /*Contiene lo Stato Attuale dell'Animazione della Coda*/
   this.StatoAnimazioneCoda = "Stop";

   /*Contiene il Livello di Qualita' delle Animazioni*/
   /*Se vale 0 la qualita' è bassa ossia una rotazione viene Renderizzata nel minor tempo possibile*/
   /*Se vale 1 la qualita' è mediobassa*/
   /*Se vale 2 la qualita' è medioalta*/
   /*Se vale 3 la qualita' è alta ossia una rotazione viene Renderizzata in un tempo accettabile*/
   this.Qualita_Animazione = 3;

   /*Contiene il Livello di Qualita' delle Animazioni Richiesto*/
   /*Appena possibile il Cubo settera' il Nuovo valore di Qualita'*/
   this.Qualita_Animazione_Richiesta = 3;

   /*Contiene lo Stato Attuale del Mouse*/
   this.StatoMouse = "Non Pigiato";

   /*Contiene il Punto della Lavagna dove è stato Pigiato il Mouse*/
   this.Mouse_Punto_Down = new Array(2);

   /*Contiene informazioni sull'Adesivo Pigiato nel formato [faccia,x,y]*/
   this.Adesivo_Pigiato = new Array(3);

   /*Contiene informazioni sui tentativi da provare per far funzionare il mouse*/
   /*Formato [[asse,blocco],[asse,blocco],evento]*/
   this.Mouse_Tentativo = new Array(3);

   this.StatoCubo = "Libero";
}

function GeneraSottoCubi()
{
   var matSC = new Array(this.num_sottocubi);
   var blocco_partenza;

   /*Raggio = (length_cubo/2)*/
   var r = this.length_cubo/2;

   if(this.num_sottocubi == 2)
   {
      if(this.blocco_attivo == 0)
      {
         var num_blocchi_SC = [1,this.dimensione-1];
         var num_primo_blocco_SC = [0,1];

         /*Soglia = (Raggio-length_cubetto)*/
         var s = r-this.length_cubetto;
      }
      else //this.blocco_attivo==ultimo
      {
         var num_blocchi_SC = [this.dimensione-1,1];
         var num_primo_blocco_SC = [0,this.dimensione-1];

         /*Soglia = (-Raggio+length_cubetto)*/
         var s = this.length_cubetto-r;
      }

      if(this.normale_blocchi[0] != 0)
      {
         var v = [[r,r,-r],[r,r,r],[r,-r,r],[r,-r,-r],[s,r,-r],[s,r,r],[s,-r,r],[s,-r,-r],[-r,r,-r],[-r,r,r],[-r,-r,r],[-r,-r,-r]];
         var f_sopra=4;
         var f_sotto=5;
      }

      if(this.normale_blocchi[1] != 0)
      {
         var v = [[-r,r,r],[r,r,r],[r,r,-r],[-r,r,-r],[-r,s,r],[r,s,r],[r,s,-r],[-r,s,-r],[-r,-r,r],[r,-r,r],[r,-r,-r],[-r,-r,-r]];
         var f_sopra=2;
         var f_sotto=3;
      }

      if(this.normale_blocchi[2] != 0)
      {
         var v = [[-r,r,r],[r,r,r],[r,-r,r],[-r,-r,r],[-r,r,s],[r,r,s],[r,-r,s],[-r,-r,s],[-r,r,-r],[r,r,-r],[r,-r,-r],[-r,-r,-r]];
         var f_sopra=0;
         var f_sotto=1;
      }
   }
   else //num_sottoocubi==3
   {
      var num_blocchi_SC = [this.blocco_attivo,1,this.dimensione-this.blocco_attivo-1];
      var num_primo_blocco_SC = [0,this.blocco_attivo,this.blocco_attivo+1];

      /*Prima Soglia = (Raggio-length_cubetto*blocco_attivo)*/
      var s0 = r-(this.length_cubetto*this.blocco_attivo);
      /*Seconda Soglia = (Prima Soglia-length_cubetto)*/
      var s1 = s0-this.length_cubetto;

      if(this.normale_blocchi[0] != 0)
      {
         var v = [[r,r,-r],[r,r,r],[r,-r,r],[r,-r,-r],[s0,r,-r],[s0,r,r],[s0,-r,r],[s0,-r,-r],[s1,r,-r],[s1,r,r],[s1,-r,r],[s1,-r,-r],[-r,r,-r],[-r,r,r],[-r,-r,r],[-r,-r,-r]];
         var f_sopra=4;
         var f_sotto=5;
      }

      if(this.normale_blocchi[1] != 0)
      {
         var v = [[-r,r,r],[r,r,r],[r,r,-r],[-r,r,-r],[-r,s0,r],[r,s0,r],[r,s0,-r],[-r,s0,-r],[-r,s1,r],[r,s1,r],[r,s1,-r],[-r,s1,-r],[-r,-r,r],[r,-r,r],[r,-r,-r],[-r,-r,-r]];
         var f_sopra=2;
         var f_sotto=3;
      }

      if(this.normale_blocchi[2] != 0)
      {
         var v = [[-r,r,r],[r,r,r],[r,-r,r],[-r,-r,r],[-r,r,s0],[r,r,s0],[r,-r,s0],[-r,-r,s0],[-r,r,s1],[r,r,s1],[r,-r,s1],[-r,-r,s1],[-r,r,-r],[r,r,-r],[r,-r,-r],[-r,-r,-r]];
         var f_sopra=0;
         var f_sotto=1;
      }
   }

   for(var i=0;i<this.num_sottocubi;i++)
   {
      if(this.normale_blocchi[0] != 0)
      {
         matSC[i] = [v[5+i*4],v[1+i*4],v[2+i*4],v[6+i*4],[0,0,1],
                     v[4+i*4],v[0+i*4],v[3+i*4],v[7+i*4],[0,0,-1],
                     v[5+i*4],v[1+i*4],v[0+i*4],v[4+i*4],[0,1,0],
                     v[6+i*4],v[2+i*4],v[3+i*4],v[7+i*4],[0,-1,0],
                     v[0+i*4],v[1+i*4],v[2+i*4],v[3+i*4],[1,0,0],
                     v[4+i*4],v[5+i*4],v[6+i*4],v[7+i*4],[-1,0,0]];
      }

      if(this.normale_blocchi[1] != 0)
      {
         matSC[i] = [v[0+i*4],v[1+i*4],v[5+i*4],v[4+i*4],[0,0,1],
                     v[3+i*4],v[2+i*4],v[6+i*4],v[7+i*4],[0,0,-1],
                     v[0+i*4],v[1+i*4],v[2+i*4],v[3+i*4],[0,1,0],
                     v[4+i*4],v[5+i*4],v[6+i*4],v[7+i*4],[0,-1,0],
                     v[2+i*4],v[1+i*4],v[5+i*4],v[6+i*4],[1,0,0],
                     v[3+i*4],v[0+i*4],v[4+i*4],v[7+i*4],[-1,0,0]];
      }

      if(this.normale_blocchi[2] != 0)
      {
         matSC[i] = [v[0+i*4],v[1+i*4],v[2+i*4],v[3+i*4],[0,0,1],
                     v[4+i*4],v[5+i*4],v[6+i*4],v[7+i*4],[0,0,-1],
                     v[0+i*4],v[1+i*4],v[5+i*4],v[4+i*4],[0,1,0],
                     v[3+i*4],v[2+i*4],v[6+i*4],v[7+i*4],[0,-1,0],
                     v[5+i*4],v[1+i*4],v[2+i*4],v[6+i*4],[1,0,0],
                     v[4+i*4],v[0+i*4],v[3+i*4],v[7+i*4],[-1,0,0]];
      }
   }

   if(this.normale_blocchi[0] != 0)
   {
      var vett = new Array(this.num_sottocubi);

      for(var i=0;i<this.num_sottocubi;i++)
      {
         vett[i] = new Array(6);

         var col = (i == this.sottocubo_attivo)?1:0;

         for(var ii=0;ii<4;ii++) vett[i][ii] = [num_blocchi_SC[i],this.dimensione,col];
         vett[i][4] = (i == 0)?[this.dimensione,this.dimensione,col]:null;
         vett[i][5] = (i == (this.num_sottocubi-1))?[this.dimensione,this.dimensione,col]:null;
      }
   }

   if(this.normale_blocchi[1] != 0)
   {
      var vett = new Array(this.num_sottocubi);

      for(var i=0;i<this.num_sottocubi;i++)
      {
         vett[i] = new Array(6);

         var col = (i == this.sottocubo_attivo)?1:0;

         vett[i][0] = [this.dimensione,num_blocchi_SC[i],col];
         vett[i][1] = [this.dimensione,num_blocchi_SC[i],col];
         vett[i][2] = (i==0)?[this.dimensione,this.dimensione,col]:null;
         vett[i][3] = (i == (this.num_sottocubi-1))?[this.dimensione,this.dimensione,col]:null;
         vett[i][4] = [this.dimensione,num_blocchi_SC[i],col];
         vett[i][5] = [this.dimensione,num_blocchi_SC[i],col];
      }
   }

   if(this.normale_blocchi[2] != 0)
   {
      var vett = new Array(this.num_sottocubi);

      for(var i=0;i<this.num_sottocubi;i++)
      {
         vett[i] = new Array(6);

         var col = (i == this.sottocubo_attivo)?1:0;

         vett[i][0] = (i == 0)?[this.dimensione,this.dimensione,col]:null;
         vett[i][1] = (i == (this.num_sottocubi-1))?[this.dimensione,this.dimensione,col]:null;
         vett[i][2] = [this.dimensione,num_blocchi_SC[i],col];
         vett[i][3] = [this.dimensione,num_blocchi_SC[i],col];
         vett[i][4] = [num_blocchi_SC[i],this.dimensione,col];
         vett[i][5] = [num_blocchi_SC[i],this.dimensione,col];
      }
   }

   var matTextureSC = new Array(this.num_sottocubi);

   for(var s=0;s<this.num_sottocubi;s++)
   {
      matTextureSC[s] = new Array(6);

      for(var f=0;f<6;f++)
      {
         matTextureSC[s][f] = new Array(2);

         matTextureSC[s][f][1] = (vett[s][f] != null)?[vett[s][f][0],vett[s][f][1],this.length_cubetto,this.colore_bordo[vett[s][f][2]]]:null;

         if((vett[s][f] != null) && ((vett[s][f][0] == 1) || (vett[s][f][1] == 1)))
         {
            matTextureSC[s][f][0] = new Array(this.dimensione);

            for(var i=0;i<this.dimensione;i++)
            {
               if(this.normale_blocchi[0] != 0)
               {
                  matTextureSC[s][f][0][i] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][i][this.dimensione-1-num_primo_blocco_SC[s]]];
               }

               if(this.normale_blocchi[1] != 0)
               {
                  matTextureSC[s][f][0][i] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][num_primo_blocco_SC[s]][i]];
               }

               if(this.normale_blocchi[2] != 0)
               {
                  if((f == 2) || (f == 3))
                  {
                     matTextureSC[s][f][0][i] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][num_primo_blocco_SC[s]][i]];
                  }
                  else //f==4 o f==5
                  {
                     matTextureSC[s][f][0][i] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][i][this.dimensione-1-num_primo_blocco_SC[s]]];
                  }
               }
            }
         }
         else //+ di 1 blocco da mappare
         {
            if(vett[s][f] != null)
            {
               if((f == f_sopra) || (f == f_sotto))
               {
                  matTextureSC[s][f][0] = new Array(this.dimensione);

                  for(var a=0;a<this.dimensione;a++)
                  {
                     matTextureSC[s][f][0][a] = new Array(this.dimensione);

                     for(var b=0;b<this.dimensione;b++)
                     {
                        matTextureSC[s][f][0][a][b] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][a][b]];
                     }
                  }
               }
               else //non si sta' mappando una faccia intera
               {
                  if(this.normale_blocchi[0] != 0)
                  {
                     matTextureSC[s][f][0] = new Array(this.dimensione);

                     for(var a=0;a<this.dimensione;a++)
                     {
                        matTextureSC[s][f][0][a] = new Array(num_blocchi_SC[s]);
                        blocco_partenza = this.dimensione-num_primo_blocco_SC[s]-num_blocchi_SC[s];

                        for(var b=0;b<num_blocchi_SC[s];b++)
                        {
                           matTextureSC[s][f][0][a][b] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][a][blocco_partenza+b]];
                        }
                     }
                  }
                  if(this.normale_blocchi[1] != 0)
                  {
                     matTextureSC[s][f][0] = new Array(num_blocchi_SC[s]);

                     for(var a=0;a<num_blocchi_SC[s];a++)
                     {
                        matTextureSC[s][f][0][a] = new Array(this.dimensione);
                        blocco_partenza = num_primo_blocco_SC[s];

                        for(var b=0;b<this.dimensione;b++)
                        {
                           matTextureSC[s][f][0][a][b] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][blocco_partenza+a][b]];
                        }
                     }
                  }
                  if(this.normale_blocchi[2] != 0)
                  {
                     if((f == 2) || (f == 3))
                     {
                        matTextureSC[s][f][0] = new Array(num_blocchi_SC[s]);

                        for(var a=0;a<num_blocchi_SC[s];a++)
                        {
                           matTextureSC[s][f][0][a] = new Array(this.dimensione);
                           blocco_partenza = num_primo_blocco_SC[s];

                           for(var b=0;b<this.dimensione;b++)
                           {
                              matTextureSC[s][f][0][a][b] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][blocco_partenza+a][b]];
                           }
                        }
                     }
                     else //f==4 o f==5
                     {
                        matTextureSC[s][f][0] = new Array(this.dimensione);

                        for(var a=0;a<this.dimensione;a++)
                        {
                           matTextureSC[s][f][0][a] = new Array(num_blocchi_SC[s]);
                           blocco_partenza = this.dimensione-num_primo_blocco_SC[s]-num_blocchi_SC[s];

                           for(var b=0;b<num_blocchi_SC[s];b++)
                           {
                              matTextureSC[s][f][0][a][b] = this.colore_faccia[vett[s][f][2]][this.matrix_adesivi[f][a][blocco_partenza+b]];
                           }
                        }
                     }
                  }
               }
            }
            else //la faccia non deve essere mappata
            {
               //non e' necessaria nessuna operazione
            }
         }
      }
   }

   this.sottocubo[0] = new SottoCubo(matSC[0]);
   this.sottocubo[0].init();
   this.sottocubo[0].SetFacciaEsterna(f_sopra);
   this.sottocubo[0].SetNormaleOriginale(this.normale_blocchi);
   if(this.normale_blocchi[0] != 0) this.sottocubo[0].SetVettoreOriginale([0,1,0]);
   if(this.normale_blocchi[1] != 0) this.sottocubo[0].SetVettoreOriginale([1,0,0]);
   if(this.normale_blocchi[2] != 0) this.sottocubo[0].SetVettoreOriginale([1,0,0]);
   this.sottocubo[0].SetTexture(matTextureSC[0]);

   this.sottocubo[1] = new SottoCubo(matSC[1]);
   this.sottocubo[1].init();
   if(this.num_sottocubi == 2)
   {
      this.sottocubo[1].SetFacciaEsterna(f_sotto);
   }
   this.sottocubo[1].SetNormaleOriginale(this.normale_blocchi);
   if(this.normale_blocchi[0] != 0) this.sottocubo[1].SetVettoreOriginale([0,1,0]);
   if(this.normale_blocchi[1] != 0) this.sottocubo[1].SetVettoreOriginale([1,0,0]);
   if(this.normale_blocchi[2] != 0) this.sottocubo[1].SetVettoreOriginale([1,0,0]);
   this.sottocubo[1].SetTexture(matTextureSC[1]);

   if(this.num_sottocubi == 3)
   {
      this.sottocubo[2] = new SottoCubo(matSC[2]);
      this.sottocubo[2].init();
      this.sottocubo[2].SetFacciaEsterna(f_sotto);
      this.sottocubo[2].SetNormaleOriginale(this.normale_blocchi);
      if(this.normale_blocchi[0] != 0) this.sottocubo[2].SetVettoreOriginale([0,1,0]);
      if(this.normale_blocchi[1] != 0) this.sottocubo[2].SetVettoreOriginale([1,0,0]);
      if(this.normale_blocchi[2] != 0) this.sottocubo[2].SetVettoreOriginale([1,0,0]);
      this.sottocubo[2].SetTexture(matTextureSC[2]);
   }
}

function RigeneraSottoCubi()
{
   this.genera_sottocubi();

   /*Rioriento il Cubo all'Orientamento che aveva prima della Rigenerazione dei SottoCubi*/
   /*Forzatura Leggo e Scrivo membri Privati*/
   for(var s=0;s<this.num_sottocubi;s++)
   {
      this.sottocubo[s].normale_ruotata.matrix_rotazionale = this.normale_ruotata.matrix_rotazionale;
      this.sottocubo[s].vettore_ruotato.matrix_rotazionale = this.normale_ruotata.matrix_rotazionale;
      for(var f=0;f<6;f++)
      {
         this.sottocubo[s].faccia_ruotata[f].normale_ruotata.matrix_rotazionale = this.normale_ruotata.matrix_rotazionale;
         for(var v=0;v<4;v++) this.sottocubo[s].faccia_ruotata[f].vertice_ruotato[v].matrix_rotazionale = this.normale_ruotata.matrix_rotazionale;
      }
   }
}

function Cubo_Mossa_Ruota_Matrice(faccia,tipo)
{
   var swap;
   var num_col = Math.floor(this.dimensione/2);
   var num_rig;

   switch(tipo)
   {
      case 0: for(var b=0;b<num_col;b++)
              {
                 num_rig = this.dimensione-1-b;
                 for(var a=b;a<num_rig;a++)
                 {
                    swap = this.matrix_adesivi[faccia][a][b];
                    this.matrix_adesivi[faccia][a][b] = this.matrix_adesivi[faccia][b][this.dimensione-1-a];
                    this.matrix_adesivi[faccia][b][this.dimensione-1-a] = this.matrix_adesivi[faccia][this.dimensione-1-a][this.dimensione-1-b];
                    this.matrix_adesivi[faccia][this.dimensione-1-a][this.dimensione-1-b] = this.matrix_adesivi[faccia][this.dimensione-1-b][a];
                    this.matrix_adesivi[faccia][this.dimensione-1-b][a] = swap;
                 }
              }
              break;
      case 1: for(var b=0;b<num_col;b++)
              {
                 num_rig = this.dimensione-1-b;
                 for(var a=b;a<num_rig;a++)
                 {
                    swap = this.matrix_adesivi[faccia][a][b];
                    this.matrix_adesivi[faccia][a][b] = this.matrix_adesivi[faccia][this.dimensione-1-b][a];
                    this.matrix_adesivi[faccia][this.dimensione-1-b][a] = this.matrix_adesivi[faccia][this.dimensione-1-a][this.dimensione-1-b];
                    this.matrix_adesivi[faccia][this.dimensione-1-a][this.dimensione-1-b] = this.matrix_adesivi[faccia][b][this.dimensione-1-a];
                    this.matrix_adesivi[faccia][b][this.dimensione-1-a] = swap;
                 }
              }
              break;
      case 2: for(var b=0;b<num_col;b++)
              {
                 num_rig = this.dimensione-1-b;
                 for(var a=b;a<num_rig;a++)
                 {
                    swap = this.matrix_adesivi[faccia][a][b];
                    this.matrix_adesivi[faccia][a][b] = this.matrix_adesivi[faccia][this.dimensione-1-a][this.dimensione-1-b];
                    this.matrix_adesivi[faccia][this.dimensione-1-a][this.dimensione-1-b] = swap;
                    swap=this.matrix_adesivi[faccia][this.dimensione-1-b][a];
                    this.matrix_adesivi[faccia][this.dimensione-1-b][a] = this.matrix_adesivi[faccia][b][this.dimensione-1-a];
                    this.matrix_adesivi[faccia][b][this.dimensione-1-a] = swap;
                 }
              }
   }
}

function Cubo_Esegui_Mossa(asse,blocco,tipo)
{
   var swap;

   if(this.StatoAnimazioneCoda == "Registra")
   {
      this.coda_mosse[this.coda_testa] = new Array(3);
      this.coda_mosse[this.coda_testa][0] = asse;
      this.coda_mosse[this.coda_testa][1] = blocco;
      this.coda_mosse[this.coda_testa][2] = tipo;

      /*Evita di Registrare delle Mosse Inutili (Considera solamente i casi piu' ecclatanti ma che in realta' sono quelli piu' frequenti)*/
      for(var i=this.coda_testa-1;i>=0 && this.coda_mosse[i][0] == asse;i--)
      {
         if(this.coda_mosse[i][1] == blocco)
         {
            switch(this.coda_mosse[i][2])
            {
               case 0: switch(tipo)
                       {
                          case 0: this.coda_mosse[i][2] = 2; break;
                          case 1: for(var ii=i;ii<this.coda_testa-1;ii++)
                                  {
                                     this.coda_mosse[ii][1] = this.coda_mosse[ii+1][1];
                                     this.coda_mosse[ii][2] = this.coda_mosse[ii+1][2];
                                  }
                                  this.coda_testa--; 
                                  break;
                          case 2: this.coda_mosse[i][2] = 1;
                       }
                       break;
               case 1: switch(tipo)
                       {
                          case 0: for(var ii=i;ii<this.coda_testa-1;ii++)
                                  {
                                     this.coda_mosse[ii][1] = this.coda_mosse[ii+1][1];
                                     this.coda_mosse[ii][2] = this.coda_mosse[ii+1][2];
                                  }
                                  this.coda_testa--; 
                                  break;
                          case 1: this.coda_mosse[i][2] = 2; break;
                          case 2: this.coda_mosse[i][2] = 0;
                       }
                       break;
               case 2: switch(tipo)
                       {
                          case 0: this.coda_mosse[i][2] = 1; break;
                          case 1: this.coda_mosse[i][2] = 0; break;
                          case 2: for(var ii=i;ii<this.coda_testa-1;ii++)
                                  {
                                     this.coda_mosse[ii][1] = this.coda_mosse[ii+1][1];
                                     this.coda_mosse[ii][2] = this.coda_mosse[ii+1][2];
                                  }
                                  this.coda_testa--;
                       }
            }
            this.coda_testa--;
         }
      }

      this.coda_testa++;
   }

   switch(asse)
   {
      case 0: switch(tipo)
              {
                 case 0: for(var i=0;i<this.dimensione;i++) 
                         {
                            swap = this.matrix_adesivi[0][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[0][i][this.dimensione-1-blocco] = this.matrix_adesivi[3][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[3][i][this.dimensione-1-blocco] = this.matrix_adesivi[1][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[1][this.dimensione-1-i][this.dimensione-1-blocco] = this.matrix_adesivi[2][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[2][this.dimensione-1-i][this.dimensione-1-blocco] = swap;
                         }
                         break;
                 case 1: for(var i=0;i<this.dimensione;i++) 
                         {
                            swap = this.matrix_adesivi[0][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[0][i][this.dimensione-1-blocco] = this.matrix_adesivi[2][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[2][this.dimensione-1-i][this.dimensione-1-blocco] = this.matrix_adesivi[1][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[1][this.dimensione-1-i][this.dimensione-1-blocco] = this.matrix_adesivi[3][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[3][i][this.dimensione-1-blocco] = swap;
                         }
                         break;
                 case 2: for(var i=0;i<this.dimensione;i++) 
                         {
                            swap = this.matrix_adesivi[0][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[0][i][this.dimensione-1-blocco] = this.matrix_adesivi[1][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[1][this.dimensione-1-i][this.dimensione-1-blocco] = swap;
                            swap = this.matrix_adesivi[2][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[2][this.dimensione-1-i][this.dimensione-1-blocco] = this.matrix_adesivi[3][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[3][i][this.dimensione-1-blocco] = swap;
                         }
              }
              switch(blocco)
              {
                 case 0: this.cubo_mossa_ruota_matrice(4,tipo); break;
                 case this.dimensione-1: this.cubo_mossa_ruota_matrice(5,tipo);
              }
              break;
      case 1: switch(tipo)
              {
                 case 0: for(var i=0;i<this.dimensione;i++) 
                         {
                            swap = this.matrix_adesivi[0][blocco][i];
                            this.matrix_adesivi[0][blocco][i] = this.matrix_adesivi[4][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[4][blocco][this.dimensione-1-i] = this.matrix_adesivi[1][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[1][blocco][this.dimensione-1-i] = this.matrix_adesivi[5][blocco][i];
                            this.matrix_adesivi[5][blocco][i] = swap;
                         }
                         break;
                 case 1: for(var i=0;i<this.dimensione;i++) 
                         {
                            swap = this.matrix_adesivi[0][blocco][i];
                            this.matrix_adesivi[0][blocco][i] = this.matrix_adesivi[5][blocco][i];
                            this.matrix_adesivi[5][blocco][i] = this.matrix_adesivi[1][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[1][blocco][this.dimensione-1-i] = this.matrix_adesivi[4][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[4][blocco][this.dimensione-1-i] = swap;
                         }
                         break;
                 case 2: for(var i=0;i<this.dimensione;i++) 
                         {
                            swap=this.matrix_adesivi[0][blocco][i];
                            this.matrix_adesivi[0][blocco][i] = this.matrix_adesivi[1][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[1][blocco][this.dimensione-1-i] = swap;
                            swap = this.matrix_adesivi[4][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[4][blocco][this.dimensione-1-i] = this.matrix_adesivi[5][blocco][i];
                            this.matrix_adesivi[5][blocco][i] = swap;
                         }
              }
              switch(blocco)
              {
                 case 0: this.cubo_mossa_ruota_matrice(2,tipo); break;
                 case this.dimensione-1: this.cubo_mossa_ruota_matrice(3,tipo);
              }
              break;
      case 2: switch(tipo)
              {
                 case 0: for(var i=0;i<this.dimensione;i++)
                         {
                            swap = this.matrix_adesivi[2][blocco][i];
                            this.matrix_adesivi[2][blocco][i] = this.matrix_adesivi[4][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[4][i][this.dimensione-1-blocco] = this.matrix_adesivi[3][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[3][blocco][this.dimensione-1-i] = this.matrix_adesivi[5][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[5][this.dimensione-1-i][this.dimensione-1-blocco] = swap;
                         }
                         break;
                 case 1: for(var i=0;i<this.dimensione;i++)
                         {
                            swap = this.matrix_adesivi[2][blocco][i];
                            this.matrix_adesivi[2][blocco][i] = this.matrix_adesivi[5][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[5][this.dimensione-1-i][this.dimensione-1-blocco] = this.matrix_adesivi[3][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[3][blocco][this.dimensione-1-i] = this.matrix_adesivi[4][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[4][i][this.dimensione-1-blocco] = swap;
                         }
                         break;
                 case 2: for(var i=0;i<this.dimensione;i++)
                         {
                            swap = this.matrix_adesivi[2][blocco][i];
                            this.matrix_adesivi[2][blocco][i] = this.matrix_adesivi[3][blocco][this.dimensione-1-i];
                            this.matrix_adesivi[3][blocco][this.dimensione-1-i] = swap;
                            swap = this.matrix_adesivi[4][i][this.dimensione-1-blocco];
                            this.matrix_adesivi[4][i][this.dimensione-1-blocco] = this.matrix_adesivi[5][this.dimensione-1-i][this.dimensione-1-blocco];
                            this.matrix_adesivi[5][this.dimensione-1-i][this.dimensione-1-blocco] = swap;
                         }
              }
              switch(blocco)
              {
                 case 0: this.cubo_mossa_ruota_matrice(0,tipo); break;
                 case this.dimensione-1: this.cubo_mossa_ruota_matrice(1,tipo);
              }
   }
}

function Cubo_Sequenza_Ruota(num_mosse,asse,tipo)
{
   switch(asse)
   {
      case 0: switch(tipo)
              {
                 case 0: for(var i=0;i<num_mosse;i++)
                         {
                            switch(this.seq[i][0])
                            {
                               case 1: this.seq[i][0] = 2; this.seq[i][1] = this.dimensione-1-this.seq[i][1]; break;
                               case 2: this.seq[i][0] = 1; switch(this.seq[i][2])
                                                           {
                                                              case 0: this.seq[i][2] = 1; break;
                                                              case 1: this.seq[i][2] = 0;
                                                           }
                            }
                         }
                         break;
                 case 1: for(var i=0;i<num_mosse;i++)
                         {
                            switch(this.seq[i][0])
                            {
                               case 1: this.seq[i][0] = 2; switch(this.seq[i][2])
                                                           {
                                                              case 0: this.seq[i][2] = 1; break;
                                                              case 1: this.seq[i][2] = 0;
                                                           }
                                       break;
                               case 2: this.seq[i][0] = 1; this.seq[i][1] = this.dimensione-1-this.seq[i][1];
                            }
                         }
              }
              break;
      case 1: switch(tipo)
              {
                 case 0: for(var i=0;i<num_mosse;i++)
                         {
                            switch(this.seq[i][0])
                            {
                               case 0: this.seq[i][0] = 2; switch(this.seq[i][2])
                                                           {
                                                              case 0: this.seq[i][2] = 1; break;
                                                              case 1: this.seq[i][2] = 0;
                                                           }
                                       break;
                               case 2: this.seq[i][0] = 0; this.seq[i][1] = this.dimensione-1-this.seq[i][1]; break;
                            }
                         }
                         break;
                 case 1: for(var i=0;i<num_mosse;i++)
                         {
                            switch(this.seq[i][0])
                            {
                               case 0: this.seq[i][0] = 2; this.seq[i][1] = this.dimensione-1-this.seq[i][1]; break;
                               case 2: this.seq[i][0] = 0; switch(this.seq[i][2])
                                                           {
                                                              case 0: this.seq[i][2] = 1; break;
                                                              case 1: this.seq[i][2] = 0;
                                                           }
                            }
                         }
              }
              break;
      case 2: switch(tipo)
              {
                 case 0: for(var i=0;i<num_mosse;i++)
                         {
                            switch(this.seq[i][0])
                            {
                               case 0: this.seq[i][0] = 1; break;
                               case 1: this.seq[i][0] = 0; this.seq[i][1] = this.dimensione-1-this.seq[i][1]; switch(this.seq[i][2])
                                                                                                              {
                                                                                                                 case 0: this.seq[i][2] = 1; break;
                                                                                                                 case 1: this.seq[i][2] = 0;
                                                                                                              }
                            }
                         }
                         break;
                 case 1: for(var i=0;i<num_mosse;i++)
                         {
                            switch(this.seq[i][0])
                            {
                               case 0: this.seq[i][0] = 1; this.seq[i][1] = this.dimensione-1-this.seq[i][1]; switch(this.seq[i][2])
                                                                                                              {
                                                                                                                 case 0: this.seq[i][2] = 1; break;
                                                                                                                 case 1: this.seq[i][2] = 0;
                                                                                                              }
                                       break;
                               case 1: this.seq[i][0] = 0;
                            }
                         }
              }
   }

   if(tipo == 2)
   {
      for(var i=0;i<num_mosse;i++)
      {
         if(this.seq[i][0]!=asse)
         {
            this.seq[i][1] = this.dimensione-1-this.seq[i][1];

            switch(this.seq[i][2])
            {
               case 0: this.seq[i][2] = 1; break;
               case 1: this.seq[i][2] = 0;
            }
         }
      }
   }
}

function SettaNormale_Set_Blocchi(vettNormale)
{
   this.normale_blocchi = vettNormale;

   this.blocco_attivo = (this.dimensione%2 == 0)?(this.dimensione/2-1):((this.dimensione-1)/2);
   this.num_sottocubi = (this.dimensione != 2)?3:2;
   this.sottocubo_attivo = (this.dimensione != 2)?1:0;

   for(var i=0;i<this.num_sottocubi;i++)
   {
      delete this.sottocubo[i];
   }

   this.rigenera_sottocubi();
}

function Setta_Blocco_Attivo(numBlocco)
{
   for(var i=0;i<this.num_sottocubi;i++) delete this.sottocubo[i];

   this.blocco_attivo = numBlocco;
   this.num_sottocubi = (this.blocco_attivo == 0)?2:((this.blocco_attivo == this.dimensione-1)?2:3);
   this.sottocubo_attivo = (this.blocco_attivo == 0)?0:1;

   this.rigenera_sottocubi();
}

function Select_Block_UP()
{
   for(var i=0;i<this.num_sottocubi;i++) delete this.sottocubo[i];

   this.blocco_attivo = (this.blocco_attivo+1)%this.dimensione;
   this.num_sottocubi = (this.blocco_attivo == 0)?2:((this.blocco_attivo == this.dimensione-1)?2:3);
   this.sottocubo_attivo = (this.blocco_attivo == 0)?0:1;

   this.rigenera_sottocubi();
}

function Select_Block_DOWN()
{
   for(var i=0;i<this.num_sottocubi;i++) delete this.sottocubo[i];

   this.blocco_attivo = (this.dimensione+this.blocco_attivo-1)%this.dimensione;
   this.num_sottocubi = (this.blocco_attivo==0)?2:((this.blocco_attivo == this.dimensione-1)?2:3);
   this.sottocubo_attivo = (this.blocco_attivo==0)?0:1;

   this.rigenera_sottocubi();
}

function ruotaSottoCubo(omega)
{
   this.sottocubo[this.sottocubo_attivo].ruota_rel(omega);
}

function ruotaBlocco(tipo)
{
   if(this.StatoRotazioneBlocco == 0)
   {
      this.StatoCubo = "Occupato";
      this.Qualita_Animazione = this.Qualita_Animazione_Richiesta;
   }

   var angolo;
   switch(this.Qualita_Animazione)
   {
      case 0: angolo = 45; break;
      case 1: angolo = 30; break;
      case 2: angolo = 15; break;
      case 3: angolo = 5;
   }
   var pausa = 1;

   var e = (this.normale_blocchi[2] != 0)?((tipo != 0)?-1:1):((tipo != 0)?1:-1);

   this.ruota_sottocubo(e*angolo);
   this.draw();
   this.StatoCubo = "Occupato";
   this.StatoRotazioneBlocco = this.StatoRotazioneBlocco + e*angolo;

   var thisObj = this;

   if((tipo != 2 && this.StatoRotazioneBlocco == e*90) || (tipo == 2 && this.StatoRotazioneBlocco == e*180))
   {
      this.StatoRotazioneBlocco = 0;

      var asse = (this.normale_blocchi[0] != 0)?0:((this.normale_blocchi[1] != 0)?1:2);
      this.cubo_mossa(asse,this.blocco_attivo,tipo);

      switch(this.StatoAnimazioneCoda)
      {
         case "Stop": this.StatoCubo = "Libero";
                      break;
         case "Fermo": setTimeout(function(){thisObj.esegui_coda_mosse.call(thisObj);},pausa);
                      break;
         case "Play": setTimeout(function(){thisObj.esegui_coda_mosse.call(thisObj);},pausa);
      }
   }
   else 
   {
      switch(tipo)
      {
         case 0: setTimeout(function(){thisObj.ruota_blocco_up.call(thisObj);},pausa); break;
         case 1: setTimeout(function(){thisObj.ruota_blocco_down.call(thisObj);},pausa); break;
         case 2: setTimeout(function(){thisObj.ruota_blocco_double.call(thisObj);},pausa);
      }
   }
}

function ruotaBlocco_UP()
{
   this.ruota_blocco(0);
}

function ruotaBlocco_DOWN()
{
   this.ruota_blocco(1);
}

function ruotaBlocco_DOUBLE()
{
   this.ruota_blocco(2);
}

function Cubo_Mouse_Tastiera(evento,tipo)
{
   var normale_originale,vettore_originale;
   var normale_ruotata,vettore_ruotato;
   var n_arcotan_xy,n_arcotan_zy,n_arcotan_xz;
   var n_angolo_xy,n_angolo_zy,n_angolo_xz;
   var v_arcotan_xy,v_arcotan_zy,v_arcotan_xz;
   var v_angolo_xy,v_angolo_zy,v_angolo_xz;
   var vett_normale;

   for(var i=0;i<2;i++)
   {
      if(i == 1 && tipo == "tastiera") break;

      if(tipo == "mouse")
      {
         vett_normale = [0,0,0];
         vett_normale[this.Mouse_Tentativo[i][0]] = 1;
         this.SetNormale_SetBlocchi(vett_normale);
         this.Set_Blocco(this.Mouse_Tentativo[i][1]);
         evento = this.Mouse_Tentativo[2];
      }

      /*Forzatura Leggo e Utilizzo membri Privati*/
      this.sottocubo[this.sottocubo_attivo].normale_ruotata.applica_rotazioni();
      this.sottocubo[this.sottocubo_attivo].vettore_ruotato.applica_rotazioni();

      normale_originale = this.sottocubo[this.sottocubo_attivo].normale_originale;
      normale_ruotata = this.sottocubo[this.sottocubo_attivo].normale_ruotata.vett3D_ruotato;
      vettore_originale = this.sottocubo[this.sottocubo_attivo].vettore_originale;
      vettore_ruotato = this.sottocubo[this.sottocubo_attivo].vettore_ruotato.vett3D_ruotato;

      if(normale_ruotata[0] != 0)
      {
         n_arcotan_xy = Math.atan(normale_ruotata[1]/normale_ruotata[0]);
         n_angolo_xy = Math.abs(n_arcotan_xy)*180/Math.PI;

         n_arcotan_xz = Math.atan(normale_ruotata[2]/normale_ruotata[0]);
         n_angolo_xz = Math.abs(n_arcotan_xz)*180/Math.PI;
      }
      else
      {
         n_angolo_xy = 90;
         n_angolo_xz = 90;
      }

      if(normale_ruotata[2] != 0) 
      {
         n_arcotan_zy = Math.atan(normale_ruotata[1]/normale_ruotata[2]);
         n_angolo_zy = Math.abs(n_arcotan_zy)*180/Math.PI;
      }
      else n_angolo_zy = 90;

      if(vettore_ruotato[0] != 0)
      {
         v_arcotan_xy = Math.atan(vettore_ruotato[1]/vettore_ruotato[0]);
         v_angolo_xy = Math.abs(v_arcotan_xy)*180/Math.PI;

         v_arcotan_xz = Math.atan(vettore_ruotato[2]/vettore_ruotato[0]);
         v_angolo_xz = Math.abs(v_arcotan_xz)*180/Math.PI;
      }
      else
      {
         v_angolo_xy = 90;
         v_angolo_xz = 90;
      }

      if(vettore_ruotato[2] != 0) 
      {
         v_arcotan_zy = Math.atan(vettore_ruotato[1]/vettore_ruotato[2]);
         v_angolo_zy = Math.abs(v_arcotan_zy)*180/Math.PI;
      }
      else v_angolo_zy = 90;

      if(n_angolo_xy > 45 && n_angolo_zy > 45)
      {
         switch(evento)
         {
            case "up": if(tipo == "tastiera")
                       {
                          if(normale_ruotata[1] >= 0) this.select_blocco_down();
                          else this.select_blocco_up();
                          this.draw();
                       }
                       break;
            case "down": if(tipo == "tastiera")
                         {
                            if(normale_ruotata[1] >= 0) this.select_blocco_up();
                            else this.select_blocco_down();
                            this.draw();
                         }
                         break;
            case "left": if(tipo == "tastiera")
                         {
                            if(normale_ruotata[1] >= 0)
                            {
                               if(normale_originale[2] != 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                            }
                            else
                            {
                               if(normale_originale[2] != 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                            }
                            i = 2;
                         }
                         else
                         {
                            if(normale_originale[0] != 0)
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                            if(normale_originale[1] != 0)
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                            if(normale_originale[2] != 0)
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                         }
                         break;
            case "right": if(tipo == "tastiera")
                          {
                             if(normale_ruotata[1] >= 0)
                             {
                                if(normale_originale[2] != 0) this.ruota_blocco_down();
                                else this.ruota_blocco_up();
                             }
                             else
                             {
                                if(normale_originale[2] != 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                             }
                             i = 2;
                          }
                          else
                          {
                             if(normale_originale[0] != 0)
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                                i = 2;
                             }
                             if(normale_originale[1] != 0)
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                                i = 2;
                             }
                             if(normale_originale[2] != 0)
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                                else this.ruota_blocco_up();
                                i = 2;
                             }
                          }
         }
      }

      if(n_angolo_xz > 45 && n_angolo_zy <= 45)
      {
         switch(evento)
         {
            case "up": if(tipo == "tastiera")
                       {
                          if(normale_ruotata[1] >= 0) this.select_blocco_down();
                          else this.select_blocco_up();
                          this.draw();
                       }
                       else
                       {
                          if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                          {
                             if(normale_ruotata[0] < 0) this.ruota_blocco_up();
                             else this.ruota_blocco_down();
                             i = 2;
                          }
                          if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                          {
                             if(normale_ruotata[0] < 0) this.ruota_blocco_up();
                             else this.ruota_blocco_down();
                             i = 2;
                          }

                          if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                          {
                             if(normale_ruotata[0] < 0) this.ruota_blocco_up();
                             else this.ruota_blocco_down();
                             i = 2;
                          }
                          if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                          {
                             if(normale_ruotata[0] < 0) this.ruota_blocco_up();
                             else this.ruota_blocco_down();
                             i = 2;
                          }

                          if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                          {
                             if(normale_ruotata[0] < 0) this.ruota_blocco_down();
                             else this.ruota_blocco_up();
                             i = 2;
                          }
                          if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                          {
                             if(normale_ruotata[0] < 0) this.ruota_blocco_down();
                             else this.ruota_blocco_up();
                             i = 2;
                          }
                       }
                       break;
            case "down": if(tipo == "tastiera")
                         {
                            if(normale_ruotata[1] >= 0) this.select_blocco_up();
                            else this.select_blocco_down();
                            this.draw();
                         }
                         else
                         {
                            if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[0] < 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                            if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[0] < 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }

                            if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[0] < 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                            if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[0] < 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }

                            if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[0] < 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                            if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) &&  (v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[0] < 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                         }
                         break;
            case "left": if(tipo == "tastiera")
                         {
                            if(normale_ruotata[1] >= 0)
                            {
                               if(normale_originale[2] != 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                            }
                            else
                            {
                               if(normale_originale[2] != 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                            }
                            i = 2;
                         }
                         else
                         {
                            if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                            if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }

                            if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                            if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }

                            if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                            if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                            {
                               if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                         }
                         break;
            case "right": if(tipo == "tastiera")
                          {
                             if(normale_ruotata[1] >= 0)
                             {
                                if(normale_originale[2] != 0) this.ruota_blocco_down();
                                else this.ruota_blocco_up();
                             }
                             else
                             {
                                if(normale_originale[2] != 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                             }
                             i = 2;
                          }
                          else
                          {
                             if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                                i = 2;
                             }
                             if(normale_originale[0] != 0 && this.Mouse_Tentativo[i][0] == 0 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                                i = 2;
                             }

                             if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                                i = 2;
                             }
                             if(normale_originale[1] != 0 && this.Mouse_Tentativo[i][0] == 1 && (this.Mouse_Tentativo[0][0] == 2 || this.Mouse_Tentativo[1][0] == 2) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_up();
                                else this.ruota_blocco_down();
                                i = 2;
                             }

                             if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 0 || this.Mouse_Tentativo[1][0] == 0) && !(v_angolo_xy > 45 && v_angolo_zy > 45))
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                                else this.ruota_blocco_up();
                                i = 2;
                             }
                             if(normale_originale[2] != 0 && this.Mouse_Tentativo[i][0] == 2 && (this.Mouse_Tentativo[0][0] == 1 || this.Mouse_Tentativo[1][0] == 1) && (v_angolo_xy > 45 && v_angolo_zy > 45))
                             {
                                if(normale_ruotata[1] >= 0) this.ruota_blocco_down();
                                else this.ruota_blocco_up();
                                i = 2;
                             }
                          }
         }
      }

      if(n_angolo_xz <= 45 && n_angolo_xy <=45)
      {
         switch(evento)
         {
            case "up": if(tipo == "tastiera")
                       {
                          if(normale_ruotata[0] >= 0)
                          {
                             if(normale_originale[2] != 0) this.ruota_blocco_up();
                             else this.ruota_blocco_down();
                          }
                          else
                          {
                             if(normale_originale[2] != 0) this.ruota_blocco_down();
                             else this.ruota_blocco_up();
                          }
                          i = 2;
                       }
                       else
                       {
                          if(normale_originale[0] != 0)
                          {
                             if(normale_ruotata[0] >= 0) this.ruota_blocco_down();
                             else this.ruota_blocco_up();
                             i = 2;
                          }
                          if(normale_originale[1] != 0)
                          {
                             if(normale_ruotata[0] >= 0) this.ruota_blocco_down();
                             else this.ruota_blocco_up();
                             i = 2;
                          }
                          if(normale_originale[2] != 0)
                          {
                             if(normale_ruotata[0] >= 0) this.ruota_blocco_up();
                             else this.ruota_blocco_down();
                             i = 2;
                          }
                       }
                       break;
            case "down": if(tipo == "tastiera")
                         {
                            if(normale_ruotata[0] >= 0)
                            {
                               if(normale_originale[2] != 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                            }
                            else
                            {
                               if(normale_originale[2] != 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                            }
                            i = 2;
                         }
                         else
                         {
                            if(normale_originale[0] != 0)
                            {
                               if(normale_ruotata[0] >= 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                            if(normale_originale[1] != 0)
                            {
                               if(normale_ruotata[0] >= 0) this.ruota_blocco_up();
                               else this.ruota_blocco_down();
                               i = 2;
                            }
                            if(normale_originale[2] != 0)
                            {
                               if(normale_ruotata[0] >= 0) this.ruota_blocco_down();
                               else this.ruota_blocco_up();
                               i = 2;
                            }
                         }
                         break;
            case "left": if(tipo == "tastiera")
                         {
                            if(normale_ruotata[0] >= 0) this.select_blocco_up();
                            else this.select_blocco_down();
                            this.draw();
                         }
                         break;
            case "right": if(tipo == "tastiera")
                          {
                             if(normale_ruotata[0] >= 0) this.select_blocco_down();
                             else this.select_blocco_up();
                             this.draw();
                          }
         }
      }
   }
}

function Cubo_freccia_UP()
{
   if(this.StatoCubo == "Occupato") return false;

   this.mouse_tastiera("up","tastiera");
}

function Cubo_freccia_DOWN()
{
   if(this.StatoCubo == "Occupato") return false;

   this.mouse_tastiera("down","tastiera");
}

function Cubo_freccia_LEFT()
{
   if(this.StatoCubo == "Occupato") return false;

   this.mouse_tastiera("left","tastiera");
}

function Cubo_freccia_RIGHT()
{
   if(this.StatoCubo == "Occupato") return false;

   this.mouse_tastiera("right","tastiera");
}

function Calc_Intersezione_Faccia(sottocubo,faccia,punto)
{
   var punto_di_vista = new Coord([0,0,0]);
   punto_di_vista.init();
   var punto_pianovisuale = new Coord([0,0,0]);
   punto_pianovisuale.init();
   var alfa,beta,gamma,omega;
   var vertice_faccia;
   var t,tN,tD;
   var punto_intersezione = new Array(3);

   /*Calcolo il punto 3D giacente sul Piano di Visualizzazione*/
   punto_di_vista.get_punto_di_vista();

   /*Calcolo il punto 3D giacente sul Piano di Visualizzazione*/
   punto_pianovisuale.conv2D3D(punto);

   alfa = this.sottocubo[sottocubo].faccia_ruotata[faccia].normale_ruotata.vett3D_ruotato[0];
   beta = this.sottocubo[sottocubo].faccia_ruotata[faccia].normale_ruotata.vett3D_ruotato[1];
   gamma = this.sottocubo[sottocubo].faccia_ruotata[faccia].normale_ruotata.vett3D_ruotato[2];

   vertice_faccia = this.sottocubo[sottocubo].faccia_ruotata[faccia].vertice_ruotato[0].vett3D_ruotato;
   omega = -alfa*vertice_faccia[0]-beta*vertice_faccia[1]-gamma*vertice_faccia[2];

   tN = alfa*punto_di_vista.vett3D[0]+beta*punto_di_vista.vett3D[1]+gamma*punto_di_vista.vett3D[2]+omega;
   tD = alfa*(punto_di_vista.vett3D[0]-punto_pianovisuale.vett3D[0])+beta*(punto_di_vista.vett3D[1]-punto_pianovisuale.vett3D[1])+gamma*(punto_di_vista.vett3D[2]-punto_pianovisuale.vett3D[2]);

   t = tN/tD;

   punto_intersezione[0] = punto_di_vista.vett3D[0]+t*(punto_pianovisuale.vett3D[0]-punto_di_vista.vett3D[0]);
   punto_intersezione[1] = punto_di_vista.vett3D[1]+t*(punto_pianovisuale.vett3D[1]-punto_di_vista.vett3D[1]);
   punto_intersezione[2] = punto_di_vista.vett3D[2]+t*(punto_pianovisuale.vett3D[2]-punto_di_vista.vett3D[2]);

   return punto_intersezione;
}

function Cubo_Mouse_DOWN(posX,posY)
{
   if(this.StatoCubo == "Occupato") return false;

   /*Controlla che sia stato pigiato un punto sulla Lavagana*/
   if(posX > this.lavagna[1] || posY > this.lavagna[1] || posX < 0 || posY < 0) return false;

   /*E' necessario rigenerare i sottocubi per Mappare correttamente l'ultima Mossa eseguita*/
   for(var i=0;i<this.num_sottocubi;i++) delete this.sottocubo[i];
   this.rigenera_sottocubi();

   /*E' necessario riapplicare le rotazioni ai sottocubi*/
   /*Forzatura utilizzo un metodo privato*/
   for(var s=0;s<this.num_sottocubi;s++)
   {
      this.sottocubo[s].normale_ruotata.applica_rotazioni();
      this.sottocubo[s].vettore_ruotato.applica_rotazioni();
      for(var f=0;f<6;f++)
      {
         for(var v=0;v<4;v++) this.sottocubo[s].faccia_ruotata[f].vertice_ruotato[v].applica_rotazioni();
      }
   }

   var veraX = posX-(this.lavagna[1]/2);
   var veraY = (this.lavagna[1]/2)-posY;
   var faccia_esterna;
   var faccia_pigiata = null;
   var sottocubo_pigiato = null;
   var trovato;
   var vf = new Array(4);
   var vc = new Array(8);
   var punto_int;
   var alfa = new Array(2);
   var beta = new Array(2);
   var gamma = new Array(2);
   var omega = new Array(2);
   var dist = new Array(2);

   trovato = false;
   for(var s=0;s<this.num_sottocubi && !trovato;s++)
   {
      for(var f=0;f<6 && !trovato;f++)
      {
         this.sottocubo[s].faccia_ruotata[f].IsVisible();

         /*Forzatura leggo un membro privato*/
         if(this.sottocubo[s].faccia_ruotata[f].visibility)
         {
            this.sottocubo[s].faccia_ruotata[f].convFaccia3D2D();

            if(this.sottocubo[s].IsPuntoInternoFaccia(f,[veraX,veraY]))
            {
               faccia_esterna = this.sottocubo[s].index_faccia_esterna;

               if(this.normale_blocchi[0] != 0)
               {
                  if((faccia_esterna == 4 && f != 5) || (faccia_esterna == 5 && f != 4) || (faccia_esterna == null && f != 5 && f != 4))
                  {
                     faccia_pigiata = f;
                     sottocubo_pigiato = s;
                     trovato = true;
                  }
               }

               if(this.normale_blocchi[1] != 0)
               {
                  if((faccia_esterna == 2 && f != 3) || (faccia_esterna == 3 && f != 2) || (faccia_esterna == null && f != 2 && f != 3))
                  {
                     faccia_pigiata = f;
                     sottocubo_pigiato = s;
                     trovato = true;
                  }
               }

               if(this.normale_blocchi[2] != 0)
               {
                  if((faccia_esterna == 0 && f != 1) || (faccia_esterna == 1 && f != 0) || (faccia_esterna == null && f != 0 && f != 1))
                  {
                     faccia_pigiata = f;
                     sottocubo_pigiato = s;
                     trovato = true;
                  }
               }
            }
         }
      }
   }

   if(faccia_pigiata != null)
   {
      /*Calcolo i vertici della faccia_pigiata*/
      if(this.normale_blocchi[0] != 0)
      {
         vc[0] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[0].vertice_ruotato[0].vett3D_ruotato;
         vc[1] = this.sottocubo[0].faccia_ruotata[0].vertice_ruotato[1].vett3D_ruotato;
         vc[2] = this.sottocubo[0].faccia_ruotata[1].vertice_ruotato[1].vett3D_ruotato;
         vc[3] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[1].vertice_ruotato[0].vett3D_ruotato;
         vc[4] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[0].vertice_ruotato[3].vett3D_ruotato;
         vc[5] = this.sottocubo[0].faccia_ruotata[0].vertice_ruotato[2].vett3D_ruotato;
         vc[6] = this.sottocubo[0].faccia_ruotata[1].vertice_ruotato[2].vett3D_ruotato;
         vc[7] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[1].vertice_ruotato[3].vett3D_ruotato;
      }

      if(this.normale_blocchi[1] != 0)
      {
         vc[0] = this.sottocubo[0].faccia_ruotata[2].vertice_ruotato[0].vett3D_ruotato;
         vc[1] = this.sottocubo[0].faccia_ruotata[2].vertice_ruotato[1].vett3D_ruotato;
         vc[2] = this.sottocubo[0].faccia_ruotata[2].vertice_ruotato[2].vett3D_ruotato;
         vc[3] = this.sottocubo[0].faccia_ruotata[2].vertice_ruotato[3].vett3D_ruotato;
         vc[4] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[3].vertice_ruotato[0].vett3D_ruotato;
         vc[5] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[3].vertice_ruotato[1].vett3D_ruotato;
         vc[6] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[3].vertice_ruotato[2].vett3D_ruotato;
         vc[7] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[3].vertice_ruotato[3].vett3D_ruotato;
      }

      if(this.normale_blocchi[2] != 0)
      {
         vc[0] = this.sottocubo[0].faccia_ruotata[2].vertice_ruotato[0].vett3D_ruotato;
         vc[1] = this.sottocubo[0].faccia_ruotata[2].vertice_ruotato[1].vett3D_ruotato;
         vc[2] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[2].vertice_ruotato[2].vett3D_ruotato;
         vc[3] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[2].vertice_ruotato[3].vett3D_ruotato;
         vc[4] = this.sottocubo[0].faccia_ruotata[3].vertice_ruotato[0].vett3D_ruotato;
         vc[5] = this.sottocubo[0].faccia_ruotata[3].vertice_ruotato[1].vett3D_ruotato;
         vc[6] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[3].vertice_ruotato[2].vett3D_ruotato;
         vc[7] = this.sottocubo[this.num_sottocubi-1].faccia_ruotata[3].vertice_ruotato[3].vett3D_ruotato;
      }

      switch(faccia_pigiata)
      {
         case 0: vf[0] = vc[0];
                 vf[1] = vc[1];
                 vf[2] = vc[5];
                 vf[3] = vc[4];
                 break;
         case 1: vf[0] = vc[3];
                 vf[1] = vc[2];
                 vf[2] = vc[6];
                 vf[3] = vc[7];
                 break;
         case 2: vf[0] = vc[0];
                 vf[1] = vc[1];
                 vf[2] = vc[2];
                 vf[3] = vc[3];
                 break;
         case 3: vf[0] = vc[4];
                 vf[1] = vc[5];
                 vf[2] = vc[6];
                 vf[3] = vc[7];
                 break;
         case 4: vf[0] = vc[2];
                 vf[1] = vc[1];
                 vf[2] = vc[5];
                 vf[3] = vc[6];
                 break;
         case 5: vf[0] = vc[3];
                 vf[1] = vc[0];
                 vf[2] = vc[4];
                 vf[3] = vc[7];
      }

      /*Calcolo il punto 3D di intersezione del Raggio Visivo con la Faccia*/
      punto_int = this.intersezione_faccia(sottocubo_pigiato,faccia_pigiata,[veraX,veraY]);

      /*Calcolo la Distanza 3D tra punto_intersezione e lato vf[0]-vf[1] della Faccia e poi con il lato vf[0]-vf[3]*/
      alfa[0] = vf[3][0]-vf[0][0];
      beta[0] = vf[3][1]-vf[0][1];
      gamma[0] = vf[3][2]-vf[0][2];
      omega[0] = -alfa[0]*vf[0][0]-beta[0]*vf[0][1]-gamma[0]*vf[0][2];
      dist[0] = Math.abs(alfa[0]*punto_int[0]+beta[0]*punto_int[1]+gamma[0]*punto_int[2]+omega[0])/Math.sqrt(Math.pow(alfa[0],2)+Math.pow(beta[0],2)+Math.pow(gamma[0],2));

      alfa[1] = vf[1][0]-vf[0][0];
      beta[1] = vf[1][1]-vf[0][1];
      gamma[1] = vf[1][2]-vf[0][2];
      omega[1] = -alfa[1]*vf[0][0]-beta[1]*vf[0][1]-gamma[1]*vf[0][2];
      dist[1] = Math.abs(alfa[1]*punto_int[0]+beta[1]*punto_int[1]+gamma[1]*punto_int[2]+omega[1])/Math.sqrt(Math.pow(alfa[1],2)+Math.pow(beta[1],2)+Math.pow(gamma[1],2));

      var adesivo = new Array(2);
      adesivo[0] = Math.floor(dist[0]/this.length_cubetto);
      adesivo[1] = Math.floor(dist[1]/this.length_cubetto);

      if(adesivo[0] == 0 || adesivo[0] == this.dimensione-1 || adesivo[1] == 0 || adesivo[1] == this.dimensione-1)
      {
         this.StatoMouse = "Pigiato-Cubo";
         this.Adesivo_Pigiato = [faccia_pigiata,adesivo[1],adesivo[0]];
         this.Mouse_Punto_Down = [posX,posY];
      }
   }
   else //faccia_pigiata == null
   {
      this.StatoMouse = "Pigiato-Sfondo";
      this.Mouse_Punto_Down = [posX,posY];
   }
}

function Cubo_Mouse_UP(posX,posY)
{
   if(this.StatoCubo == "Occupato") return false;

   this.StatoMouse = "Non Pigiato";
}

function Cubo_Mouse_MOVE(posX,posY)
{
   if(this.StatoCubo == "Occupato" || this.StatoMouse == "Non Pigiato") return false;

   /*Controlla che il Mouse si trovi sulla Lavagana*/
   if(posX > this.lavagna[1] || posY > this.lavagna[1] || posX < 0 || posY < 0)
   {
      this.StatoMouse = "Non Pigiato";
      return false;
   }

   var dist = new Array(2);
   var angolo = new Array(2);
   var e = new Array(2);
   var mov_min;

   if(this.StatoMouse == "Pigiato-Sfondo")
   {
      dist[0] = Math.abs(posX-this.Mouse_Punto_Down[0]);
      dist[1] = Math.abs(posY-this.Mouse_Punto_Down[1]);

      mov_min = this.lavagna[1]/18;

      if(dist[0] > mov_min || dist[1] > mov_min)
      {
         angolo[0] = Math.floor(dist[0]/mov_min)*15;
         angolo[1] = Math.floor(dist[1]/mov_min)*15;

         if(posX-this.Mouse_Punto_Down[0] < 0) e[0] = 1;
         else e[0] = -1;
         if(posY-this.Mouse_Punto_Down[1] < 0) e[1] = 1;
         else e[1] = -1;

         this.ruotaY(e[0]*angolo[0]);
         this.ruotaX(e[1]*angolo[1]);
         this.draw();

         this.Mouse_Punto_Down = [posX,posY];
      }
   }

   if(this.StatoMouse == "Pigiato-Cubo")
   {
      dist[0] = Math.abs(posX-this.Mouse_Punto_Down[0]);
      dist[1] = Math.abs(posY-this.Mouse_Punto_Down[1]);

      mov_min = 10;

      if(dist[0] > mov_min || dist[1] > mov_min)
      {
         this.StatoMouse = "Non Pigiato";

         angolo[0] = Math.abs(Math.atan(dist[1]/dist[0]))*180/Math.PI;

         switch(this.Adesivo_Pigiato[0])
         {
            case 0: this.Mouse_Tentativo[0] = [0,this.dimensione-1-this.Adesivo_Pigiato[1]];
                    this.Mouse_Tentativo[1] = [1,this.Adesivo_Pigiato[2]];
                    break;
            case 1: this.Mouse_Tentativo[0] = [0,this.dimensione-1-this.Adesivo_Pigiato[1]];
                    this.Mouse_Tentativo[1] = [1,this.Adesivo_Pigiato[2]];
                    break;
            case 2: this.Mouse_Tentativo[0] = [0,this.dimensione-1-this.Adesivo_Pigiato[1]];
                    this.Mouse_Tentativo[1] = [2,this.Adesivo_Pigiato[2]];
                    break;
            case 3: this.Mouse_Tentativo[0] = [0,this.dimensione-1-this.Adesivo_Pigiato[1]];
                    this.Mouse_Tentativo[1] = [2,this.Adesivo_Pigiato[2]];
                    break;
            case 4: this.Mouse_Tentativo[0] = [1,this.Adesivo_Pigiato[2]];
                    this.Mouse_Tentativo[1] = [2,this.dimensione-1-this.Adesivo_Pigiato[1]];
                    break;
            case 5: this.Mouse_Tentativo[0] = [1,this.Adesivo_Pigiato[2]];
                    this.Mouse_Tentativo[1] = [2,this.dimensione-1-this.Adesivo_Pigiato[1]];
         }

         if(posY-this.Mouse_Punto_Down[1] < 0 && angolo[0] > 45) this.Mouse_Tentativo[2] = "up";
         if(posY-this.Mouse_Punto_Down[1] >= 0 && angolo[0] > 45) this.Mouse_Tentativo[2] = "down";
         if(posX-this.Mouse_Punto_Down[0] < 0 && angolo[0] <= 45) this.Mouse_Tentativo[2] = "left";
         if(posX-this.Mouse_Punto_Down[0] >= 0 && angolo[0] <= 45) this.Mouse_Tentativo[2] = "right";

         this.mouse_tastiera("","mouse");
      }
   }
}

function Rende_Uguali_Matrici(matA,matB)
{
   for(var f=0;f<6;f++)
   {
      for(var a=0;a<this.dimensione;a++)
      {
         for(var b=0;b<this.dimensione;b++) matA[f][a][b] = matB[f][a][b];
      }
   }
}

function Cubo_Setta_Mossa_Attuale_Coda(valore)
{
   this.eguaglia_matrici(this.matrix_adesivi,this.coda_matrix_adesivi);

   for(var i=0;i<valore;i++) this.cubo_mossa(this.coda_mosse[i][0],this.coda_mosse[i][1],this.coda_mosse[i][2]);
   this.coda_mossa_attuale = valore-1;
}

function Cubo_Esegui_Coda_Mosse()
{
   if(this.coda_testa == 0)
   {
      this.StatoAnimazioneCoda = "Stop";
      this.StatoCubo = "Libero";
      return false;
   }

   switch(this.StatoAnimazioneCoda)
   {
      case "Stop": this.eguaglia_matrici(this.matrix_adesivi,this.coda_matrix_adesivi);
                   this.StatoAnimazioneCoda = "Play";
                   if(this.barra != null) this.barra.draw();
                   break;
      case "Fermo": this.StatoCubo = "Libero";
   }

   if(this.barra != null && this.coda_tipo == "Risoluzione" && this.barra.valore-1 != this.coda_mossa_attuale)
   {
      this.coda_setta_mossa_attuale(this.barra.valore);

      this.barra.draw();
      this.barra.StatoBarra = "Libera";
   }

   if(this.coda_mossa_attuale == this.coda_testa-1)
   {
      if(this.coda_tipo == "Risoluzione")
      {
         this.StatoAnimazioneCoda = "Fermo";
         this.barra.draw();
      }
      else
      {
         this.StatoAnimazioneCoda = "Stop";
         this.coda_tipo = null;
      }

      this.StatoCubo = "Libero";
   }

   if(this.StatoAnimazioneCoda == "Play")
   {
      this.coda_mossa_attuale++;
      if(this.barra != null && this.coda_tipo == "Risoluzione")
      {
         this.barra.Setta_Valore(this.coda_mossa_attuale+1);
         this.barra.draw();
      }

      var vettAsse = [0,0,0];
      vettAsse[this.coda_mosse[this.coda_mossa_attuale][0]] = 1;

      this.SetNormale_SetBlocchi(vettAsse);
      this.Set_Blocco(this.coda_mosse[this.coda_mossa_attuale][1]);
      this.ruota_blocco(this.coda_mosse[this.coda_mossa_attuale][2]);
   }
}

function Cubo_Mescola(num_mosse,animazione_attiva)
{
   if(this.StatoCubo == "Occupato") return false;
   this.StatoCubo = "Occupato";

   if(animazione_attiva == 1) this.eguaglia_matrici(this.coda_matrix_adesivi,this.matrix_adesivi);

   var asse,blocco,tipo;

   this.coda_testa = 0;
   this.coda_mossa_attuale = -1;

   if(this.barra != null)
   {
      this.barra.Setta_Valore_Max(0);
      this.barra.Setta_Valore(0);
      this.barra.draw();
   }

   if(animazione_attiva == 1)
   {
      this.coda_tipo = "Mescolamento";
      this.StatoAnimazioneCoda = "Registra";
   }

   for(var i=0;i<num_mosse;i++)
   {
      asse = Math.floor(Math.random()*100)%3;
      blocco = Math.floor(Math.random()*100)%this.dimensione;
      tipo = Math.floor(Math.random()*100)%2;

      this.cubo_mossa(asse,blocco,tipo);
   }

   if(animazione_attiva == 1)
   {
      this.StatoAnimazioneCoda = "Stop";

      this.esegui_coda_mosse();
   }
   else
   {
      this.rigenera_sottocubi();
      this.draw();
      this.StatoCubo = "Libero";
   }
}

function Cubo_Risolvi()
{
   if(this.StatoCubo == "Occupato" || this.avvia_risolutore == null) return false;
   this.StatoCubo = "Occupato";

   this.eguaglia_matrici(this.coda_matrix_adesivi,this.matrix_adesivi);

   this.coda_tipo = "Risoluzione";
   this.StatoAnimazioneCoda = "Registra";

   this.coda_testa = 0;
   this.coda_mossa_attuale = -1;

   this.avvia_risolutore(this);

   if(this.barra != null && this.coda_testa > 0)
   {
      this.barra.Setta_Valore_Max(this.coda_testa);
      this.barra.Setta_Valore(0);
      this.barra.draw();
   }

   this.StatoAnimazioneCoda = "Stop";

   this.esegui_coda_mosse();
}

function ruotaXCubo(omega)
{
   this.StatoCubo = "Occupato";

   for(var i=0;i<this.num_sottocubi;i++) this.sottocubo[i].ruotaX(omega);

   this.normale_ruotata.ruotaX(omega,1);

   this.StatoCubo = "Libero";
}

function ruotaYCubo(omega)
{
   this.StatoCubo = "Occupato";

   for(var i=0;i<this.num_sottocubi;i++) this.sottocubo[i].ruotaY(omega);

   this.normale_ruotata.ruotaY(omega,1);

   this.StatoCubo = "Libero";
}

function AssegnaRisolutore(funzione)
{
   this.avvia_risolutore = funzione;
}

function AssegnaBarra(objBarra)
{
   this.barra = objBarra;
   this.barra.cubo = this;
   this.barra.draw();
}

function Set_Lavagna(lavagna_canvas)
{
   this.StatoCubo = "Occupato";

   this.lavagna_tmp = lavagna_canvas;
   this.lavagna_tmp[0] = lavagna_canvas[0].getContext('2d');

   this.length_cubetto = Math.round((this.lavagna_tmp[1]/2)*100/this.dimensione)/100;
   this.length_cubo = this.length_cubetto*this.dimensione;

   for(var i=0;i<this.num_sottocubi;i++) delete this.sottocubo[i];
   this.rigenera_sottocubi();

   this.StatoCubo = "Libero";
}

function Set_Qualita_Animazione(qualita)
{
   this.Qualita_Animazione_Richiesta = qualita;
}

function drawCubo()
{
   this.StatoCubo = "Occupato";

   this.lavagna = this.lavagna_tmp;
   /*Cancella tutto ridisegnando lo sfondo*/
   this.lavagna[0].fillStyle = this.lavagna[2];
   this.lavagna[0].fillRect(0, 0, this.lavagna[1], this.lavagna[1]);
   /*Ridisegna Bordo Lavagna*/
   this.lavagna[0].fillStyle = black;
   this.lavagna[0].fillRect(0, 0, this.lavagna[1], 4);
   this.lavagna[0].fillRect(0, this.lavagna[1]-4, this.lavagna[1], 4);
   this.lavagna[0].fillRect(0, 0, 4, this.lavagna[1]);
   this.lavagna[0].fillRect(this.lavagna[1]-4,0, 4, this.lavagna[1]);

   /*Forzatura: Invoco un Metodo Privato (per convenienza)*/
   var indice_esterna = this.sottocubo[0].index_faccia_esterna;
   this.sottocubo[0].faccia_ruotata[indice_esterna].IsVisible();

   /*Forzatura: leggo un membro Privato (per convenienza)*/
   if(this.sottocubo[0].faccia_ruotata[indice_esterna].visibility) var sopra = true;

   if(this.num_sottocubi==2)
   {
      if(sopra)
      {
         this.sottocubo[1].draw(this.lavagna);
         this.sottocubo[0].draw(this.lavagna);
      }
      else
      {
         this.sottocubo[0].draw(this.lavagna);
         this.sottocubo[1].draw(this.lavagna);
      }
   }

   if(this.num_sottocubi == 3)
   {
      if(sopra)
      {
         this.sottocubo[2].draw(this.lavagna);
         this.sottocubo[1].draw(this.lavagna);
         this.sottocubo[0].draw(this.lavagna);
      }
      else
      {
         for(var i=0;i<3;i++) this.sottocubo[i].draw(this.lavagna);
      }
   }

   this.StatoCubo = "Libero";
}