//
// HitoriPoker.java
// Copyright (c) 1997 by Hidetaka Manu- Masuda
// This program requires PokerCard.java, PokerCardDeck.java and PokerRole.java.
// Non-Commercial use only.
// 

import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import java.awt.image.*;
import java.applet.Applet;

public class HitoriPoker extends Applet implements Runnable {
final short rows = 5, cols = 5;

Panel field; // 5x5 buttons' container
Panel horizontalScores, resultScores; // scoreLabels' container
Panel verticalScores, functionButtons; 

Image diamondImage;
Image heartImage;
Image spadeImage;
Image clubImage;

static final int spade = 0;
static final int heart = 1;
static final int diamond = 2;
static final int club = 3;

PokerCardDeck deck; // aCardDeck  
PokerCard[][] board; // card models array

Font aFont;
Color originalBackground, backColor;

JanneButton cardButtons[][]; // for card field buttons
Label	lblx1, lblx2, lblx3, lblx4, lblx0, lblrd,
	lblru, lbly1, lbly2, lbly3, lbly4, lbly0; // score labels
Button	bNew, bEnd; // function buttons 
Label	lblNext, lblxscore, lblyscore, lblxyscore, lblTotal, lblName; // other labels
JanneButton	btnNextCard; // displaying next card 
TextField	txtName; // input name field

PokerCard	current; // current card
int		total; // total score
String		playerName; // player name
PokerRole	roles[][]; // containing poker roles for rows, colums and diagonals

String rankingScore; // for score ranking 
int ranking;
String newRecord;
        
public void initField() { // creating 5x5 field buttons

	field= new Panel();
    	field.setLayout(new GridLayout(rows, cols)); 
    	cardButtons = new JanneButton[rows][cols];
    
	int i, j;
	aFont = new Font("Helvetica", Font.BOLD, 18);
	board = new PokerCard[rows][cols];
	roles = new PokerRole[6][2];
	for (i=0;i<rows;i++) {
		for (j=0;j<cols;j++) {
			cardButtons[i][j] = new JanneButton(null,  "", true, true);
			cardButtons[i][j].setFont(aFont); 
			field.add(cardButtons[i][j]);
        }
    }
}

public void initHorizontalScores() {
    
	horizontalScores= new Panel();
	horizontalScores.setLayout(new GridLayout(1, cols+1));
	lblrd = new Label("R.S.Flush", Label.CENTER);
	horizontalScores.add(lblrd);
	lblx0 = new Label("lblx0", Label.LEFT);
	horizontalScores.add(lblx0);
	lblx1 = new Label("lblx1", Label.LEFT);
	horizontalScores.add(lblx1);
	lblx2 = new Label("lblx2", Label.LEFT);
	horizontalScores.add(lblx2);
	lblx3 = new Label("lblx3", Label.LEFT);
	horizontalScores.add(lblx3);
	lblx4 = new Label("lblx4", Label.LEFT);
	horizontalScores.add(lblx4);
	lblru = new Label("lblru", Label.LEFT);
	horizontalScores.add(lblru);
}

public void init() { // initialize 
	initField();
	initHorizontalScores();
    	initResultScores();
    	initVerticalScores();
    	initFunctionButtons();
    	setLayout(new BorderLayout());
    	add("Center", field);
    	add("North", horizontalScores);
    	add("West", verticalScores);
    	add("South", resultScores);
    	add("East", functionButtons);  
     	initialize();
     	initName();
     	created();
    	initImage();
	loadRankingScore();
}

public void initImage() { // initializing images
	clubImage();
	diamondImage();
	heartImage();
	spadeImage();
}

public void initVerticalScores() { // creating vertical score labels
    	verticalScores= new Panel();
    	verticalScores.setLayout(new GridLayout(rows, 1));
    	lbly0 = new Label("visitor", Label.CENTER);
    	verticalScores.add(lbly0);
    	lbly1 = new Label("lbly1", Label.CENTER);
    	verticalScores.add(lbly1);
    	lbly2 = new Label("lbly2", Label.CENTER);
    	verticalScores.add(lbly2);
    	lbly3 = new Label("lbly3", Label.CENTER);
    	verticalScores.add(lbly3);
    	lbly4 = new Label("lbly4", Label.CENTER);
    	verticalScores.add(lbly4);
}

public void initResultScores() { // creating result score labels
    	resultScores= new Panel();
    	resultScores.setLayout(new GridLayout(2, 2));
     	lblyscore = new Label("lblyscore");
    	resultScores.add(lblyscore);
	lblxyscore = new Label("lblxyscore");
    	resultScores.add(lblxyscore);
	lblxscore = new Label("lblxscore");
    	resultScores.add(lblxscore);
	lblTotal = new Label("lblTotal");
    	resultScores.add(lblTotal);
}

public void initFunctionButtons() { // creating function buttons, next card field, name field
	Panel p[];
	int i, j;
	j = 5;
	p = new Panel[j];
	for (i=0; i<j; i++) {
		p[i] = new Panel();
	}
    	functionButtons= new Panel();
    	functionButtons.setLayout(new GridLayout(j, 1));

    	bNew = new Button("New");
    	backColor = bNew.getBackground();
	p[0].setLayout(new GridLayout(3, 1));
    	p[0].add(bNew);
    	bEnd = new Button("End");
    	p[0].add(bEnd);
	p[0].add(new Label(""));

	p[1].setLayout(new GridLayout(1, 1));
	p[2].setLayout(new GridLayout(1, 1));
	p[3].setLayout(new GridLayout(3, 1));
	lblName = new Label("Name");
    	p[3].add(lblName);
	txtName = new TextField("Visitor");
    	p[3].add(txtName);
	lblNext = new Label("Next");
	lblNext.setAlignment(Label.CENTER);
    	p[3].add(lblNext);

	p[4].setLayout(new GridLayout(1, 1));
	btnNextCard = new JanneButton(null, "NextC", true, true);
	btnNextCard.setFont(new Font("Helvetica", Font.BOLD, 18));
	originalBackground = btnNextCard.getBackground();
	btnNextCard.setBackground(Color.white);

	p[4].add(btnNextCard);

	for (i=0; i<j; i++) {
		functionButtons.add(p[i]);
	}

}

Image diamondImage()  {
	if (diamondImage == null) {
		String aName = "dia.gif";    
        	diamondImage= getImage(getCodeBase(), aName);
        }
        return diamondImage;
}

Image clubImage()  {
	if (clubImage == null) {
		String aName = "club.gif";    
        	clubImage= getImage(getCodeBase(), aName);
        }
        return clubImage;
}


Image spadeImage()  {
	if (spadeImage == null) {
		String aName = "spade.gif";    
        	spadeImage= getImage(getCodeBase(), aName);
        }
        return spadeImage;
}



Image heartImage()  {
	if (heartImage == null) {
		String aName = "heart.gif";    
        	heartImage= getImage(getCodeBase(), aName);
        }
        return heartImage;
}

Image getMarkImage(PokerCard aCard)  {
        int mark;
        mark = aCard.getMark();
        switch(mark) {
            case spade:
                return spadeImage();
            case heart:
                return heartImage();
            case diamond:
                return diamondImage();
            case club:
                return clubImage();
            default:
            	System.out.println("gif file not found");
                return null;
            }
}

public boolean action(Event evt, Object arg)  { // event handler
	PokerCard tmp;
	JanneButton aButton;
	if (evt.target instanceof JanneButton) {
		pushed((JanneButton)evt.target);
	}
	if (evt.target instanceof Button) {
		pushed((Button)evt.target);	
	}
	return true;
}

//
// logics, application body
//

Point nameToPoint(JanneButton aButton) { // get aJanneButton from x, y 
int i, j;
    	for (i=0;i<rows;i++) {
        	for (j=0;j<cols;j++) {
      			if (cardButtons[i][j] == aButton) {
				return new Point(i, j);
			}
        	}
    	}
	return new Point(-1, -1);
}


void displayLabel(Label aLabel, String labelString) {
     	aLabel.setText(labelString);
     	aLabel.show();
}

boolean isFilled(PokerCard[] aHand) { // has five cards?
int i;
     	for (i=0; i<5; i++) {
         	if ((aHand[i] instanceof PokerCard) == false) {
            		return false;
         	}
     	}
     	return true;
}

PokerRole checkHand(PokerCard[] aHand) {
PokerRole newRole;
     	newRole = new PokerRole();
     	newRole.evaluate(aHand);
     	return newRole;
}

PokerCard[] getX(Point aPoint) {
int xx, yy;
PokerCard[]   aHand;
     	aHand = new PokerCard[5];
     	for (xx=0; xx<5; xx++) {
          	aHand[xx] = board[xx][aPoint.y];
     	}
     	return aHand;
}

PokerCard[] getY(Point aPoint) {
int xx, yy;
PokerCard[]   aHand;
     	aHand = new PokerCard[5];
     	for (yy=0; yy<5; yy++) {
          	aHand[yy] = board[aPoint.x][yy];
     	}
     	return aHand;
}


PokerCard[] getRD(Point aPoint) { // get right down 
int xx, yy;
PokerCard[]  aHand;
     	aHand = new PokerCard[5];
     	for (xx=0; xx<5; xx++) {
          	aHand[xx] = board[xx][xx];
     }
     return aHand;
}

PokerCard[] getRU(Point aPoint) { // get right up
int xx, yy;
PokerCard[]  aHand;
     	aHand = new PokerCard[5];
     	for (xx=0; xx<5; xx++) {
          	aHand[xx] = board[xx][4-xx];
     	}
     	return aHand;
}

void checkRD(Point aPoint) { // check right down
PokerCard[] aHand;
PokerRole    aRole;
	aHand = getRD(aPoint);
	if (isFilled(aHand)) {
             	aRole = checkHand(aHand);
             	roles[5][0] = aRole;
	     	displayLabel(lblrd, aRole.getRoleName());
        }
}
 
void checkRU(Point aPoint) { // check right up
PokerCard[] aHand;
PokerRole    aRole;
	aHand = getRU(aPoint);
	if (isFilled(aHand)) {
             	aRole = checkHand(aHand);
             	roles[5][1] = aRole;
	     	displayLabel(lblru, aRole.getRoleName());
	}
}

Label getLabelFromX(int xx) {
	switch (xx) {
		case 0:
			return lblx0;
		case 1:
			return lblx1;
		case 2: 
			return lblx2;
		case 3:
			return lblx3;
		case 4: 
			return lblx4;
		default:
			return null;
	}
}


Label getLabelFromY(int yy) {
	switch (yy) {
		case 0:
			return lbly0;
		case 1:
			return lbly1;
		case 2: 
			return lbly2;
		case 3:
			return lbly3;
		case 4: 
			return lbly4;
		default:
			return null;
	}
}

void checkX(Point aPoint) { // X but treat Y
PokerCard[] aHand;
PokerRole    aRole;
Label aLabel;
	aHand = getX(aPoint);
	if (isFilled(aHand)) {
             	aRole = checkHand(aHand);
             	aLabel = getLabelFromX(aPoint.y);
             	roles[aPoint.y][1] = aRole;
	     	displayLabel(aLabel, aRole.getRoleName());
	}
}

void checkY(Point aPoint) { // Y but treat X
PokerCard[] aHand;
Label    aLabel;
PokerRole    aRole;
	aHand = getY(aPoint);
	if (isFilled(aHand)) {
             	aRole = checkHand(aHand);
             	aLabel = getLabelFromY(aPoint.x);
             	roles[aPoint.x][0] = aRole;
	     	displayLabel(aLabel, aRole.getRoleName());
        }
}

void checkRole(Point aPoint) {
     	checkX(aPoint);
     	checkY(aPoint);
     	checkRU(aPoint);
     	checkRD(aPoint);
}

void storeCard(Point aPoint) {
     	board[aPoint.x][aPoint.y] = current;
}

void activateButtons() {
int  xx, yy;
JanneButton   aBtn;
	for (yy=0; yy<5; yy++) {
        	for (xx=0; xx<5; xx++) {
              		aBtn = cardButtons[xx][yy];
              		aBtn.enable();
              		aBtn.setImage(null);
              		aBtn.setLabel("");
			aBtn.setBackground(originalBackground);
		}
	}
}

void inactivateButton(JanneButton aBtn) {
     	aBtn.disable();
     	aBtn.setBackground(Color.white);
}

void inactivateButtons() {
int  xx, yy;
JanneButton   aBtn;
	for (yy=0; yy<5; yy++) {
        	for (xx=0; xx<5; xx++) {
              		inactivateButton(cardButtons[xx][yy]);
		}
	}
}

void invisibleLabel(Label aLabel) {
     aLabel.hide();
}

void invisibleLabels() {
int i;
	for (i=0; i<5; i++) {
        	invisibleLabel(getLabelFromX(i));
          	invisibleLabel(getLabelFromY(i));
     	};
     	invisibleLabel(lblru);
     	invisibleLabel(lblrd);
     	invisibleLabel(lblxscore);
     	invisibleLabel(lblyscore);
     	invisibleLabel(lblxyscore);
}

void setCurrentCard() {
     	btnNextCard.disable();
	btnNextCard.setImage(getMarkImage(current));
	btnNextCard.setLabel(current.printNumber());
}

void setNextCard() {
     	current = deck.getNext();
     	setCurrentCard();
}

void showNextCard() {
     	setNextCard();
}

void gameOver() { // display scores
String xLabel, yLabel, xyLabel;
int    xTotal, yTotal, xyTotal, i;
PokerRole    xRole, yRole, rdRole, ruRole;

     	total = 0; xTotal = 0; yTotal = 0; xyTotal = 0;
     	xLabel = "Y = ";
     	yLabel = "X = ";
     	for (i=0; i<5; i++) {
          	xRole = roles[i][0];
	  	yRole = roles[i][1];
          	xLabel = xLabel + xRole.printPoint() + " + ";
          	yLabel = yLabel + yRole.printPoint() + " + ";
          	xTotal = xTotal + xRole.getPoint();
          	yTotal = yTotal + yRole.getPoint();
     	}
     	xLabel = xLabel.substring(0, xLabel.length()-3);
     	xLabel = xLabel + " = " + xTotal;
     	yLabel = yLabel.substring(0, yLabel.length()-3);
     	yLabel = yLabel + " = " + yTotal;
     	rdRole = roles[5][0];
     	ruRole = roles[5][1];
     	xyTotal = rdRole.getPoint() + ruRole.getPoint();
     	xyLabel = "XY = "+rdRole.printPoint()+" + "+ruRole.printPoint()+" = "+xyTotal;
     	total = xyTotal + xTotal + yTotal;

     	displayLabel(lblxscore, xLabel);
     	displayLabel(lblyscore, yLabel);
     	displayLabel(lblxyscore, xyLabel);
     	displayLabel(lblTotal, "Total = "+total);
}

void initialize() { // initialize a game
     	playerName = txtName.getText();
     	setBoard();
     	deck = new PokerCardDeck();
     	deck.shuffle();
     	current = deck.getCurrent();
     	total = 0;
}

void setPlayerName(String aString) {
     	playerName = aString;
	txtName.setText(aString);
}

void initName() { // init player name
     	playerName = txtName.getText();
	setPlayerName(playerName);
}

void created() { // init 
     	setPlayerName(playerName);
     	displayLabel(lblNext, "Next");
     	displayLabel(lblTotal, "Total=  0");
     	setCurrentCard();
     	invisibleLabels();
     	activateButtons();
}

void setBoard() { // clear card fields (aModel)
board = new PokerCard[rows][cols];
int xx, yy;
    	for (yy=0; yy<cols; yy++) {
         	for (xx=0; xx<rows; xx++) {
             	board[xx][yy]=null;
         	}
    	}
}

void release() { // release roles
int xx, yy;
     	for (yy=0; yy<=1; yy++) {
         	for (xx=0; xx<rows; xx++) {
                	roles[xx][yy]=null;
         	}
     	}
}

void pushed(JanneButton aBtn) { // janne button event handling
Point aPoint;
	aBtn.setImage(getMarkImage(current));
	aBtn.setLabel(current.printNumber());
     	inactivateButton(aBtn);
	aPoint = nameToPoint(aBtn);
     	storeCard(aPoint);
     	checkRole(aPoint);
     	showNextCard();
     	if (deck.getCount() == 25) {
		gameOver();
		if (total > ranking ) {
			newRecord = makeNewRecord();
			Thread sendScore = new Thread(this);
			sendScore.start();
		}
	}
}

void pushed(Button aBtn) { // button event handling 
Point aPoint;
boolean    bool;
	if ((aBtn.getLabel()).equals("New")) {
		newGame();	
	}
	if ((aBtn.getLabel()).equals("End")) {
		quitGame();	
	}
}

void newGame() { // play new game
     	release();
     	initialize();
     	created();
}

void quitGame() {
// actually, do nothing 
}

int loadRankingScore() { // load the lowest score from URL server
	int i, range;
	range = 20;
	try {
        	URL url = new URL(getDocumentBase(), "p_best.dat");
                DataInputStream in = new DataInputStream(url.openStream());
                String s;
		for (i=0; i<range; i++) {
			s = in.readLine();
			rankingScore= s;
		}
                in.close();
		ranking = Integer.parseInt(rankingScore.substring(0, 3));
		return ranking;
	} catch(MalformedURLException e) {
		System.out.println("MalformedURLException!!");
        } catch(IOException e) {
		System.out.println("Read IOException!!");
        }
	ranking = 200;
	return ranking;
}

String makeNewRecord() { // create new record string
	String newRecord, totalString, nameString;
	Date today;
	today = new Date();
	totalString = "00"+total;
	nameString = txtName.getText()+"         ";
	newRecord = totalString.substring(totalString.length()-3, totalString.length())
 + " " + nameString.substring(0,9) + today.toString();
	return newRecord;
}

public void run() { // send total score to URL server
	int    PORT = XXXX /* secret */, i ;
	String hostname;
	Socket           socket ;
	OutputStream out;
	URL url;
        url = getCodeBase();
        hostname = url.getHost();
	try {
		System.out.println("rank in "+total);
		socket = new Socket( hostname, PORT ) ;
      		out = socket.getOutputStream();
		System.out.println(newRecord);
		byte b[] = new byte[newRecord.length()];
		newRecord.getBytes(0, newRecord.length(), b, 0);
		out.write(b);
		out.flush();
                out.close();
		socket.close();
		System.out.println("sent it");
	} catch(MalformedURLException e) {
		System.out.println("MalformedURLException!!");
        } catch(IOException e) {
		System.out.println("Write IOException!!");
	}
}

}
