var Aufgaben = new Array();
var aufgabenIndex;
var spalten;
var zeilen;
var zuege;
var anzahlElemente;

var aktiv = 0;
var fallschritte = 0;
var fallzeit = 100;
var Zeilengruppen;
var Spaltengruppen;
var zeilenIndex = 0;

var AlleFarben = new Array;
AlleFarben[ "red" ] = Math.random();
AlleFarben[ "lime" ] = Math.random();
AlleFarben[ "blue" ] = Math.random();
AlleFarben[ "fuchsia" ] = Math.random();
AlleFarben[ "yellow" ] = Math.random();
AlleFarben[ "aqua" ] = Math.random();
AlleFarben[ "maroon" ] = Math.random();
AlleFarben[ "green" ] = Math.random();
AlleFarben[ "navy" ] = Math.random();
AlleFarben[ "purple" ] = Math.random();
AlleFarben[ "olive" ] = Math.random();
AlleFarben[ "teal" ] = Math.random();
AlleFarben[ "black" ] = Math.random();

var GemischteFarben;
var AktuelleFarben;
var farbindex = 0;

function Element( zeile, spalte, farbe ){
  this.fehler = 0;
  this.zeile = parseInt( zeile );
  this.spalte = parseInt( spalte );
  this.farbe = farbe;
  if( isNaN( this.zeile ) ) {
    this.fehler = "zeile: '" + zeile + "' ist keine Zahl.";
    return;
  }
  if( this.zeile < 1 ){
    this.fehler = "zeile: '" + zeile + "'. Kleinster Zeilenindex ist 1.";
    return;    
  }
  if( isNaN( this.spalte ) ) {
    this.fehler = "spalte: '" + spalte + "' ist keine Zahl.";
    return;
  }
  if( this.spalte < 1 ){
    this.fehler = "spalte: '" + spalte + "'. Kleinster Spaltenindex ist 1.";
    return;    
  }
} 

function Aufgabe( spaltenAnzahl, zuegeAnzahl, Elemente ){
  this.fehler = 0;
  this.zeilen = 0;
  this.spalten = parseInt( spaltenAnzahl );
  this.zuege = parseInt( zuegeAnzahl );
  this.Elemente = new Array();
  this.anzahlElemente = 0;
  this.Farben = new Object();
  this.anzahlFarben = 0;
  if( isNaN( this.spalten ) ) {
    this.fehler = "spalten: '" + spaltenAnzahl + "' ist keine Zahl.";
    return;
  }
  if( this.spalten < 1 ){
    this.fehler = "spalten: '" + spaltenAnzahl + "'. Mindestens 1.";
    return;    
  }
  if( isNaN( this.zuege ) ) {
    this.fehler = "zuege: '" + zuegeAnzahl + "' ist keine Zahl.";
    return;
  }
  if( this.zuege < 1 ){
    this.fehler = "zuege: '" + zuegeAnzahl + "'. Mindestens 1.";
    return;    
  }
  if( ! Elemente ){
    this.fehler = "Elemente ist nicht definiert.";
    return;
  }
  if( Elemente.length == 0 ){
    this.fehler = "Es wurden keine Elemente definiert.";
    return;
  }
  var id;
  var Zwischenfarben = new Object();
  for( var el in Elemente ){
    if( Elemente[ el ].fehler ){
      this.fehler = "Fehler in Elemente[ " + el + " ]: " + Elemente[ el ].fehler;
      return;
    }
    if( Elemente[ el ].spalte > this.spalten ){
      this.fehler = "Fehler in Elemente[ " + el + " ]: spalte au&szlig;erhalb des Bereichs: '" + Elemente[ el ].spalte + "' > " + this.spalten;
      return;
    }
    if( Elemente[ el ].zeile > this.zeilen ){
      this.zeilen = Elemente[ el ].zeile;
    }
    this.anzahlElemente += 1;
    if( Zwischenfarben[ Elemente[ el ].farbe ] ){
      Zwischenfarben[ Elemente[ el ].farbe ] +=1;
    } else {
      Zwischenfarben[ Elemente[ el ].farbe ] = 1;
      this.anzahlFarben += 1;
    }
  }
  farbenZuweisen( Zwischenfarben, this.Farben );
  for( var el in Elemente ){
    id = ( this.zeilen - Elemente[ el ].zeile ) * this.spalten + Elemente[ el ].spalte - 1;
    if( this.Elemente[ id ] ){
      this.fehler = "Fehler in Elemente. Zeile " + Elemente[ el ].zeile + ", Spalte " + Elemente[ el ].spalte + " wird von Elemente[ " + el + " ] zum zweiten mal belegt.";
      return;
    }
    if( ! AlleFarben[ Zwischenfarben[ Elemente[ el ].farbe ] ] ){
      this.fehler = "Fehler in Farben. Elemente[ " + el + " ].farbe: " + Elemente[ el ].farbe + " Zwischenfarben[ " + Elemente[ el ].farbe + "]: " + Zwischenfarben[ Elemente[ el ].farbe ];
      return;
    }
    this.Elemente[ id ] = Zwischenfarben[ Elemente[ el ].farbe ];
  }
}

function farbenZuweisen( Zwischenfarben, Farben ){
  AktuelleFarben = new Object();
  for( var zfa in Zwischenfarben ){
    if( AlleFarben[ zfa ] ){
      AktuelleFarben[ zfa ] = zfa;
      Farben[ zfa ] = Zwischenfarben[ zfa ];
      Zwischenfarben[ zfa ] = zfa;
    } else {
      var farbe = naechsteFarbe();
      AktuelleFarben[ farbe ] = zfa;
      Farben[ farbe ] = Zwischenfarben[ zfa ];
      Zwischenfarben[ zfa ] = farbe;
    }
  }
  AktuelleFarben = "";
}

function naechsteFarbe(){
  if( ! GemischteFarben ) {
    farbenMischen();
  }
  if( AktuelleFarben ) {
    var aktFarben = 0;
    while( AktuelleFarben[ GemischteFarben[ farbindex ] ] ){
      farbindex += 1;
      if( farbindex == GemischteFarben.length ){
        farbindex = 0;
      }
      aktFarben += 1;
      if( aktFarben == GemischteFarben.length ){
        throw "Es wurden schon zu viele Farben definiert";
      }
    }
  }
  var farbe = GemischteFarben[ farbindex ];
  farbindex += 1;
  if( farbindex == GemischteFarben.length ){
    farbindex = 0;
  }
  return farbe;
}

function farbenMischen(){
  if( GemischteFarben ) return;
  GemischteFarben = new Array;
  var ende = 0;
  var index = 0;
  while( ! ende ){
    var obergrenze = 1.0;
    ende = 1;
    for( var fa in AlleFarben ){
      if( AlleFarben[ fa ] < obergrenze ){
        GemischteFarben[ index ] = fa;
        obergrenze = AlleFarben[ fa ];
        ende = 0;
      }
    }
    AlleFarben[ GemischteFarben[ index ] ] = index + 1;
    index += 1;
  }
  farbindex = 0;
}

function erzeugeAufgabe( index ){
  if( aktiv ) return;
  var hElement;
  var divElement;

  if( document.getElementById( "HDOS" ) == null ){
    document.write( "<p>Fehler: HTML-Element 'HDOS' nicht vorhanden.</p>" );
    return;
  }

  if( document.getElementById( "HDOS_H1" ) == null ){
    hElement = document.createElement( "h1" );
    hElement.id = "HDOS_H1";
    hElement.className = "erstezeile";
    hElement.position = "relative";
    document.getElementById( "HDOS" ).appendChild( hElement ); 
  }
  document.getElementById( "HDOS_H1" ).innerHTML = "Aufgabe " + index;

  if( document.getElementById( "HDOS_ZUEGE" ) == null ) {
    divElement = document.createElement( "div" );
    divElement.id = "HDOS_ZUEGE";
    divElement.style.position = "relative";
    divElement.style.top = "0em";
    divElement.style.left = "1em";
    document.getElementById( "HDOS" ).appendChild( divElement );
  }

  if( document.getElementById( "HDOS_DIV" ) == null ) {
    divElement = document.createElement( "div" );
    divElement.id = "HDOS_DIV";
    divElement.style.position = "relative";
    divElement.style.top = "1em";
    divElement.style.left = "1em";
    document.getElementById( "HDOS" ).appendChild( divElement );
  }
  document.getElementById( "HDOS_DIV" ).style.height = "4em";

  if( document.getElementById( "HDOS_AUFGABE" ) == null ) {
    divElement = document.createElement( "div" );
    divElement.id = "HDOS_AUFGABE";
    divElement.style.position = "relative";
    divElement.style.top = "0em";
    divElement.style.left = "0em";
    document.getElementById( "HDOS_DIV" ).appendChild( divElement );
  }
  document.getElementById( "HDOS_AUFGABE" ).innerHTML = "";

  if( document.getElementById( "HDOS_MENUE" ) == null ) {
    divElement = document.createElement( "div" );
    divElement.id = "HDOS_MENUE";
    divElement.style.position = "relative";
    document.getElementById( "HDOS_DIV" ).appendChild( divElement );
  }
  document.getElementById( "HDOS_MENUE" ).style.top = "0em";
  document.getElementById( "HDOS_MENUE" ).innerHTML = "";

  aufgabenIndex = parseInt( index ) - 1;
  if( isNaN( aufgabenIndex ) ){
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "... wird nicht erzeugt, da '" + index + "' keine Zahl ist.";
    return;
  }   
  if( aufgabenIndex < 0 ){
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "... existiert nicht. Die erste Aufgabe ist Aufgabe 1.";
    return;
  }
  if( aufgabenIndex >= Aufgaben.length ){
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "... existiert nicht.";
    return;
  }
  
  if( Aufgaben[ aufgabenIndex ].fehler ){
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "... wird nicht erzeugt: " + Aufgaben[ aufgabenIndex ].fehler;
    return;
  }

  spalten = Aufgaben[ aufgabenIndex ].spalten;
  zeilen = Aufgaben[ aufgabenIndex ].zeilen;
  zuege = Aufgaben[ aufgabenIndex ].zuege;
  document.getElementById( "HDOS_ZUEGE" ).innerHTML = zuege + " mal tauschen!";

  anzahlElemente = Aufgaben[ aufgabenIndex ].anzahlElemente;

  document.getElementById( "HDOS_DIV" ).style.height = (zeilen * 3.2 + 4) + "em";
  document.getElementById( "HDOS_MENUE" ).style.top = (zeilen * 3.2 + 1.5) + "em";
  document.getElementById( "HDOS_MENUE" ).innerHTML = "<a href='javascript:erzeugeAufgabe(" + (aufgabenIndex + 1) + ")'>Aufgabe " + (aufgabenIndex + 1) + " noch einmal versuchen</a>";
  for( var zeile = 0; zeile < zeilen; zeile++ ){
    for( var spalte = 0; spalte < spalten - 1; spalte++ ){
      divElement = document.createElement( "div" );
      divElement.id = (zeile * spalten) + spalte;
      divElement.style.position = "absolute";
      divElement.style.top = (zeile * 3.2) + "em";
      divElement.style.left = (spalte * 3.2) + "em";
      divElement.style.width = "3em";
      divElement.style.height = "3em";
      divElement.style.borderStyle = "solid";
      divElement.style.borderWidth = "0.15em";
      divElement.style.borderColor = "silver";
      divElement.onmousemove = elementMouseMove;
      divElement.onmouseout = elementMouseOut;
      divElement.onclick = elementClick;
      document.getElementById( "HDOS_AUFGABE" ).appendChild( divElement );
    }
    divElement = document.createElement( "div" );
    divElement.id = (zeile + 1) * spalten - 1;
    divElement.style.position = "absolute";
    divElement.style.top = (zeile * 3.2) + "em";
    divElement.style.left = ((spalten - 1) * 3.2) + "em";
    divElement.style.width = "3em";
    divElement.style.height = "3em";
    divElement.style.borderStyle = "solid";
    divElement.style.borderWidth = "0.15em";
    divElement.style.borderColor = "silver";
    document.getElementById( "HDOS_AUFGABE" ).appendChild( divElement ); 
  }
  for( var el in Aufgaben[ aufgabenIndex ].Elemente ){
    document.getElementById( el ).style.backgroundColor = Aufgaben[ aufgabenIndex ].Elemente[ el ];
  }
  aktiv = 1;
  zeilenIndex = 0;
  zeilenFallen();
}

function elementMouseMove(){
  if( aktiv ) return;
  this.style.borderColor = "black";
  var nachbar = parseInt( this.id ) + 1;
  document.getElementById( nachbar ).style.borderColor = "black";
}

function elementMouseOut(){
  if( aktiv ) return;
  this.style.borderColor = "silver";
  var nachbar = parseInt( this.id ) + 1;
  document.getElementById( nachbar ).style.borderColor = "silver";
}

function elementClick(){
  if( aktiv ) return;
  zuege -= 1;
  if( zuege >= 0 ){
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "Noch " + zuege + " mal tauschen!";
  } else {
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "Noch nicht fertig?";
  }
  var id = parseInt( this.id );
  var nachbar = id + 1;
  if( this.style.backgroundColor == document.getElementById( nachbar ).style.backgroundColor ) return;
  aktiv = 1;
  this.style.borderColor = "silver";
  document.getElementById( nachbar ).style.borderColor = "silver";
  var farbe = this.style.backgroundColor;
  this.style.backgroundColor = document.getElementById( nachbar ).style.backgroundColor;
  document.getElementById( nachbar ).style.backgroundColor = farbe;
  zeilenIndex = 0;
  zeilenFallen();
}

function zeilenFallen(){
  if( zeilenIndex == zeilen - 1 ){
    if( fallschritte == 0 ){
      gruppensuchen();
    } else {
      zeilenIndex = zeilen;
    }
    return;
  }
  zeilenIndex += 1;
  var geholt = 0;
  for( var id = zeilenIndex * spalten; id < (zeilenIndex + 1) * spalten; id++ ){
    if( document.getElementById( id ).style.backgroundColor == ""
      && document.getElementById( id - spalten ).style.backgroundColor != "" ){
      geholt = 1;
      fallschritte += 1;
      setTimeout( "fallen(" + id + ")", fallzeit );
    }
  }
  if( geholt ){
    setTimeout( "zeilenFallen()", fallzeit + 10 );
  } else {
    zeilenFallen()
  }
}

function fallen( id ){
  var oben = id - spalten;
  if( document.getElementById( oben ).style.backgroundColor != "" ){
    document.getElementById( id ).style.backgroundColor = document.getElementById( oben ).style.backgroundColor;
    document.getElementById( oben ).style.backgroundColor = "";
    if( oben >= spalten ){   
      fallschritte += 1;
      setTimeout( "fallen(" + oben + ")", fallzeit );
    }
  }
  fallschritte -= 1;
  if( zeilenIndex == zeilen && fallschritte == 0 ){
    gruppensuchen();
  }
}

function Gruppe( anfang, anzahl ){
  this.anfang = anfang;
  this.anzahl = anzahl;
}

function gruppensuchen(){
  Spaltengruppen = new Array;
  for( var spalte = 0; spalte < spalten; spalte++){
    var id = spalte;
    while( id < (zeilen - 2) * spalten ){
      var farbe = document.getElementById( id ).style.backgroundColor;
      if( farbe != "" ){
        var anfang = id;
        var anzahl = 1;
        while( id < (zeilen - 1) * spalten && document.getElementById( id + spalten ).style.backgroundColor == farbe ){
          id += spalten;
          anzahl += 1;
        }
        if( anzahl > 2 ){
          Spaltengruppen[ Spaltengruppen.length ] = new Gruppe( anfang, anzahl );
        }        
      }
      id += spalten;
    }
  }
  Zeilengruppen = new Array;
  for( var zeile = 0; zeile < zeilen; zeile++ ){
    var id = (zeile * spalten);
    while( id < (zeile + 1) * spalten - 2 ){
      var farbe = document.getElementById( id ).style.backgroundColor;
      if( farbe != "" ){
        var anfang = id;
        var anzahl = 1;
        while( id < (zeile + 1) * spalten - 1 && document.getElementById( id + 1 ).style.backgroundColor == farbe ){
          id += 1;
          anzahl += 1;
        }
        if( anzahl > 2 ){
          Zeilengruppen[ Zeilengruppen.length ] = new Gruppe( anfang, anzahl );
        }
      }
      id += 1;
    }
  }
  for( var index = 0; index < Spaltengruppen.length; index++ ){
    for( var id = Spaltengruppen[ index ].anfang; id < Spaltengruppen[ index ].anfang + Spaltengruppen[ index ].anzahl * spalten; id += spalten ){
      document.getElementById( id ).style.borderColor = "black";
    }
  }
  for( var index = 0; index < Zeilengruppen.length; index++ ){
    for( var id = Zeilengruppen[ index ].anfang; id < Zeilengruppen[ index ].anfang + Zeilengruppen[ index ].anzahl; id++ ){
      document.getElementById( id ).style.borderColor = "black";
    }
  }
  if( Spaltengruppen.length > 0 || Zeilengruppen.length > 0 ){
    setTimeout( "gruppenEntfernen()", 1000 );
  } else {
    if( anzahlElemente > 0 ){
      aktiv = 0;
    } else {
      geloest();
    }
  }
}

function gruppenEntfernen(){
  for( var index = 0; index < Spaltengruppen.length; index++ ){
    for( var id = Spaltengruppen[ index ].anfang; id < Spaltengruppen[ index ].anfang + Spaltengruppen[ index ].anzahl * spalten; id += spalten ){
      document.getElementById( id ).style.borderColor = "silver";
      document.getElementById( id ).style.backgroundColor = "";
      anzahlElemente -= 1;
    }
  }
  for( var index = 0; index < Zeilengruppen.length; index++ ){
    for( var id = Zeilengruppen[ index ].anfang; id < Zeilengruppen[ index ].anfang + Zeilengruppen[ index ].anzahl; id++ ){
      if( document.getElementById( id ).style.backgroundColor != "" ){
        document.getElementById( id ).style.borderColor = "silver";
        document.getElementById( id ).style.backgroundColor = "";
        anzahlElemente -= 1;
      }
    }
  }
  if( anzahlElemente > 0 ){
    zeilenIndex = 0;
    zeilenFallen();
  } else {
    geloest();
  }
}

function geloest(){
  document.getElementById( "HDOS_MENUE" ).innerHTML = "";
  setTimeout( "leeren()", 1000 );
  if( zuege < 0 ){
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "... muss in weniger Z&uuml;gen gel&ouml;st werden ...";
    setTimeout( "erzeugeAufgabe(" + (aufgabenIndex + 1) + ")", 2000 );
  } else {
    document.getElementById( "HDOS_H1" ).innerHTML += "&nbsp;gel&ouml;st!&nbsp;";    
    document.getElementById( "HDOS_ZUEGE" ).innerHTML = "n&auml;chste Aufgabe ...";
    if( Aufgaben.length - 1 > aufgabenIndex ){      
      setTimeout( "erzeugeAufgabe(" + (aufgabenIndex + 2) + ")", 2000 );
    } else {
      document.getElementById( "HDOS_ZUEGE" ).innerHTML = "Letzte Aufgabe gel&ouml;st.";
      setTimeout( "ende()", 2000 );    
    }
  }
}

function leeren(){
  aktiv = 0;
  document.getElementById( "HDOS_AUFGABE" ).innerHTML = "";  
}

function ende(){
  document.getElementById( "HDOS_DIV" ).style.height = "0em";
  document.getElementById( "HDOS_DIV" ).style.top = "0em";
}




