/*
 * Version 0.04 Peter Scholl
 * 
 * Todo:
 * done! - Teamfähig (linke und rechte Maustaste)
 * done! - Feldergrenzen neu berechnet
 * done! - Testfunktion (bestimmung maximaler Paarloser karten)
 *         existiert aber nur im Quelltext :-)
 * done! - Nur Anzahl der vorhandenen Karten darstellen (Bug)
 * Java-Imports minimieren
 * 
 * Version 0.03 Peter Scholl
 * 
 * Todo :
 * done! - bei mehr als Zwölf Karten wieder aufräumen - done!
 * done! - Klick auf leere Felder nicht zulassen
 * done! - Reaktion auf mehrfachklick auf ein Feld anpassen
 * done! - Buttons für "Finde nichts"
 * done! - Was tun wenn alle Karten ausgespielt
 * done! - Anzeige für Failures / Founds und verbleibende Karten
 * done! - Tipp anzeigen lassen
 */

import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Arrays;  // Nur fürs sortieren von klicked

//import java.awt.*;
import java.awt.event.*;
//import java.awt.image.*;
//import java.net.*;
//import java.applet.*;
//import java.util.Arrays; // Nur fürs sortieren von klicked

/**
 */
public
class Set extends Applet implements MouseListener {
    /**
     * Dubble Buffering
     */
     private Image dbImage;
     private Graphics dbg;

     /**
     * fürs debuggen
     */
     
     String tempresult = "";
     boolean testrunning = false;
     int testlastmax = 0;
     int testcount = 0;

    /**
     * Zähler für gefundene Sets
     */
    int setcount=0;

    /**
     * Setkarten auf dem Brett
     */

    int spielfeld[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int spielfeldkarten = 0;
    
    /**
     * gemischte Karten und oberste Karte
     */

    int kartenstapel[];
    int topkarte=1;
    
    /**
     * Ausgewählte Felder und Zugnummer
     */

    int klicked[] = {0,0,0};
    int lastchose[] = {0,0,0};  //eigentlich auch nur fürs debuggen
    int zugnummer = 0;
    
    /**
     * Zähler für erfolgreiches Spiel
     */
    int won;         // Zähler für gefundene Sets
    int lost;        // Zähler für fehlschläge
    int won2;	     // Zähler für gefundene Sets (Team 2)
    int lost2;       // Zähler für fehlschläge (Team 2)

    /**
     * Spiel- und Darstellungsstatus
     */
    boolean showsets = false;
    String foundsets = "";
    
    static final int RUNNING = 0;
    static final int WON = 1;
    int status = RUNNING;

    /**
     * Die Bilder für die Setkarten
     */
    Image setkarte[];

    /**
     * Initialize the applet. Resize and load images.
     */
    public void init() {
	status = RUNNING;
	
        setkarte = new Image[82];
        for (int i=1;i<82;i++) {
          setkarte[i] = getImage(getCodeBase(), "bilder/"+i+".gif");
	}
 
        //zufallszahl Mischen
	kartenstapel = new int[82];
	for (int i=1;i<82;i++) {
	  kartenstapel[i]=i;
	}
	for (int i=81;i>0;i--) {
	int zuf = (int)(Math.random()*i)+1;
	int tkarte = kartenstapel[i];
	kartenstapel[i]=kartenstapel[zuf];
	kartenstapel[zuf]=tkarte;
	}
	
        //zahl = (int)(Math.random()*12)+1;
        //wert = (int)(Math.random()*2);
        //gewicht[zahl]=2+2*wert;
    
    	//Karten ausgeben
	for (int i=1;i<13;i++) {
	  spielfeld[i]=kartenstapel[topkarte];
	  topkarte++;
	}
	spielfeldkarten=12;
	
	addMouseListener(this);
    }

    public void myinit() {
	status = RUNNING;

	testrunning = false;
	testlastmax = 0;
	testcount = 0;

	// Karten mischen
	for (int i=81;i>0;i--) {
	  int zuf = (int)(Math.random()*i)+1;
	  int tkarte = kartenstapel[i];
	  kartenstapel[i]=kartenstapel[zuf];
	  kartenstapel[zuf]=tkarte;
	}
       	
    	//Karten ausgeben
	topkarte=1;
	for (int i=1;i<13;i++) {
	  spielfeld[i]=kartenstapel[topkarte++];
	}
	for (int i=13;i<22;i++) {
	  spielfeld[i]=0;
	}
	spielfeldkarten=12;

	//Spielvariablen zurücksetzen
	zugnummer = 0;
	won = 0;
	won2 = 0;
	lost = 0;
	lost2 = 0;
	tempresult = "";
    }

    public void destroy() {
        removeMouseListener(this);
    }

    /**
     * Paint it.
     */
    public void paint(Graphics g) {
	Dimension d = getSize();
          g.setColor(Color.blue);
	  g.fillRect(0,0,d.width,d.height);
	  //g.fill3DRect(75,  0, 60, 20, true);  //MyTestButton
          g.fill3DRect(75, 20, 60, 20, true);  //RESTART
          g.fill3DRect(155,20, 60, 20, true);  //Neue Karten
	  g.fill3DRect(235,20, 60, 20, true);  //Num of Sets
          g.setColor(Color.LIGHT_GRAY);
	  //g.drawString("Petersein", 77, 18);
          g.drawString("RESTART", 77, 38);
          g.drawString("Kein Set!", 157, 38);
	  g.drawString("Sets?", 237, 38);
          g.drawString("Gefunden:"+won+"  Fehler:"+lost, 77, 65);
	  if (won2+lost2 > 0) {
	    g.drawString("Team2: Gefunden:"+won2+"  Fehler:"+lost2, 77,100);
	  }
	  g.drawString("verbleibende Karten:"+(82-topkarte), 300,38);
	  if (showsets) { g.drawString(foundsets,300,80); }
	  g.drawString(tempresult,300,100);  //Dient zur Fehlersuche
	if (status == WON) {
	  g.setColor(Color.red);
          g.drawString("Gewonnen", 100,80);
        } 
	g.setColor(Color.black);

	// Bilder und Feldnummern anzeigen
	for (int i = 0 ; i < spielfeldkarten ; i++) {
	  int r = (int)i/3;
	  int c = i - 3*r;
	  g.drawImage(setkarte[spielfeld[3*r+1+c]], r*97+8,280-c*70, this);
          g.drawString(""+(3*r+c+1),r*97+10,340-c*70);
        }   

	// ausgewählte Felder anzeigen
	for (int i = 0 ; i < zugnummer; i++) {
            int r = (int) (klicked[i]-1)/3;
	    int c = klicked[i]-1-3*r;
	       g.drawString("x",r*97+10,290-c*70);
        }
    }

    /** Update - Method, implements double buffering */
    /** Wenn die Graphikdarstellung über den Rand hinausgeht kann
     * es zu Problemen mit der Auffrischung kommen
     */
    public void update (Graphics g)
    {
    // für die Analyse
    //showsets = true;
    //numberofsets();

    // initialize buffer
    if (dbImage == null)
    {
    dbImage = createImage (this.getSize().width, this.getSize().height);
    dbg = dbImage.getGraphics ();
    
    }
    
    // clear screen in background
    //dbg.setColor (getBackground ());
    dbg.setColor (Color.blue);
    dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);
    
    // draw elements in background
    dbg.setColor (getForeground());
    paint (dbg);
    
    // draw image on the screen
    g.drawImage (dbImage, 0, 0, this);
    
    }
    
    public boolean isklicked(int k1) {
      for (int i=0; i < zugnummer; i++) {
	if (klicked[i]==k1) { return true; }
      }
      return false;
    }

    void removefromklicked(int k1) {
      for (int i=0; i< zugnummer; i++) {
	if (klicked[i]==k1) { klicked[i]=klicked[zugnummer--];}
      }
    }
    
    public int missingsetcard(int k1, int k2) {
      // Berechnet die zu k1 und k2 zu einem Set passende Karte
      int r1, r2;
      int v1 = k1-1;
      int v2 = k2-1;
      int v3 = 0;
      for (int i=1; i<81; i*=3) {
	 r1 = v1 - ((int) v1/3 )*3;
	 r2 = v2 - ((int) v2/3 )*3;
	 if ( r1 == r2 ) {
	   v3+=r1*i;
	 } else {
	   v3+=(3-r1-r2)*i;
	 }
	 v1 = (v1-r1)/3;
	 v2 = (v2-r2)/3;
      }
      return v3+1;
    }

    public int numberofsets() {
      int numofsets = 0;
      foundsets = "";
      for (int i=0; i<spielfeldkarten-2; i++) {
	for (int j=i+1; j<spielfeldkarten-1; j++) {
	  int skarte=missingsetcard(spielfeld[i+1],spielfeld[j+1]);
	  for (int k=j+1; k<spielfeldkarten; k++) {
	    if (spielfeld[k+1] == skarte) {
	      numofsets++;
	      foundsets+=""+(i+1)+","+(j+1)+","+(k+1)+" - ";
	      break;
	    }	      
	  }
	}
      }
      foundsets+="("+numofsets+")";
      return numofsets;
    }

    public boolean isset(int k1, int k2, int k3) {
      int r1, r2, r3;
      int v1 = k1-1;
      int v2 = k2-1;
      int v3 = k3-1;
      for (int i=0; i<4; i++) {
	 r1 = v1 - ((int) v1/3 )*3;
	 r2 = v2 - ((int) v2/3 )*3;
	 r3 = v3 - ((int) v3/3 )*3;
	 if (!( ( (r1 == r2) && (r2 == r3) ) || (r1+r2+r3==3))) {
		 return false;
	 }
	 v1 = (v1-r1)/3;
	 v2 = (v2-r2)/3;
	 v3 = (v3-r3)/3;
      }	 
      return true;
    }
    
    /**
     * The user has clicked in the applet. Figure out where
     * and see if a legal move is possible. If it is a legal
     * move, respond with a legal move (if possible).
     */
    public void mouseReleased(MouseEvent e) {
	int x = e.getX();
	int y = e.getY();

	showsets = false;

	// Wähle Karte
	if ((zugnummer < 3) && (x < 700) && (x > 3) && (y > 140) && (y < 350)) {
	  int posx = (x-3);
          int posy = (350-y);
          int row = (int)posx/97;
          int col = (int)posy/70;
	  int feld = 3*row+col+1;
	  if (feld <= spielfeldkarten) {
	    if (isklicked(feld)) {
	      removefromklicked(feld);
	    } else {
              klicked[zugnummer] = feld;
              zugnummer++;
	    }
          }	    
	  if (zugnummer == 3) {
	    //Spielsituation prüfen
	    int karte1 = spielfeld[klicked[0]];
	    int karte2 = spielfeld[klicked[1]];
	    int karte3 = spielfeld[klicked[2]];
	    lastchose[0] = karte1;
	    lastchose[1] = karte2;
	    lastchose[2] = karte3;
	    if ( isset(karte1,karte2,karte3) ) {
		if (spielfeldkarten>12 || topkarte >= 81) {
		  Arrays.sort(klicked);
		  for (int i=2; i>=0; i--) {
		    spielfeld[klicked[i]]=spielfeld[spielfeldkarten];
		    spielfeld[spielfeldkarten--]=0;
		  }
		} else {
		  // Neue Karten
		  spielfeld[klicked[0]]=kartenstapel[topkarte++];
		  spielfeld[klicked[1]]=kartenstapel[topkarte++];
		  spielfeld[klicked[2]]=kartenstapel[topkarte++];
		} 
		zugnummer = 0;
		// Set gefunden
		if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
		  won++;
		} else {
		  won2++;
		}
	    } else { 
		// Kein Set;
		zugnummer = 0;
		if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
		  lost++;
		} else {
		  lost2++;
		}
	    }
          }
	} else if ((x < 215) && (x > 155) && (y > 20) && (y < 40)) { // Kein Set gefunden (Button)
	  if ( (topkarte > 81) && (numberofsets() == 0) ) {
	    status = WON;
          } else if ((topkarte < 81) && (spielfeldkarten < 21)) {
            if (numberofsets() > 0) { 
	      if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
		lost++;
	      } else {
	        lost2++;
  	      }		
	    }
	    for (int i=0; i<3; i++) {
	      spielfeld[++spielfeldkarten]=kartenstapel[topkarte++];
	    }
	  } else if (numberofsets() == 0) {
	    tempresult = " HEY - Impossible - Call scholl@unix-ag.org ! ";
	  }
	} else if ((x < 135) && (x > 75) && (y > 20) && (y < 40)) { // Restart
	  myinit();
	  repaint();
	} else if ((x < 295) && (x > 235) && (y > 20) && (y < 40)) { // Sets?
	  showsets = true; 
	  if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
	    lost++;
	  } else {
	    lost2++;
	  }
	  numberofsets();
	} /* else if ((x < 135) && (x > 75) && (y > 0) && (y < 20)) { // My Test
          // Hier kann ich Testfunktionen einbauen
	  if (testrunning) {
            spielfeldkarten++;
	    spielfeld[spielfeldkarten]=spielfeld[spielfeldkarten-1]+1;
	  } else {
	    spielfeldkarten = 1;
	    spielfeld[1] = 1;
	    testrunning = true;
	  }
	  while (spielfeld[1] < 80) {
	    testcount++;
            if (spielfeld[spielfeldkarten]==81) {
	      spielfeldkarten--;
	      spielfeld[spielfeldkarten]++;
	    } else if (numberofsets()==0) {
	      if ((spielfeldkarten==20) || (spielfeldkarten>testlastmax)) {
	        tempresult="Max: "+spielfeldkarten+" bei "+testcount+"Tests";
	        showsets = true;
	        repaint();
		testlastmax=spielfeldkarten;
		return;
	      }
	      spielfeldkarten++;
	      spielfeld[spielfeldkarten]=spielfeld[spielfeldkarten-1]+1;
	    } else if (numberofsets() > 0) {
	      spielfeld[spielfeldkarten]++;
	    }
	  }
	  testrunning = false;
	} */
    }

    public void mousePressed(MouseEvent e) {
	repaint();
    }

    public void mouseClicked(MouseEvent e) {
	    repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public String getAppletInfo() {
	return "Modified the TicTacToe Applet";
    }
}

