import java.lang.*;
import tio.*;

/**
 * The class <code>Card</code> is a simple (ASCII) Representation 
 * of a standard playing card.
 * Designed to be useable by all card-playing programs.
 * Makes use of package tio
 * Makes use of Debug.class
 *<pre>
 *<br> Standard ranking uses "Ace-low" but this can be changed in the Constructor
 *<br> Assumes the following Mapping: <code><b>
 *<br>     SUIT 'C' = clubs = 0,
 *<br>          'S' = spades = 1,
 *<br>          'D' = diamonds = 2,
 *<br>          'H' = hearts = 3
 *<br>
 *<br>          'J' = joker = -1
 *<br>          'W' = wildcard = 4
 *<br>          '.' = EMPTY = -2
 *<br>
 *<br>     RANK 'A' = Ace = 0,
 *<br>          '2','3','4','5','6','7','8','9',
 *<br>          'T' = 9,
 *<br>          'J' = jack = 10,
 *<br>          'Q' = queen = 11,
 *<br>          'K' = king = 12
 *<br>
 *<br>          '0' = joker = -1
 *<br>          'W' = wildcard = 13
 *<br>          '.' = EMPTY = -2
 *<br>
 *<br> </b> </code></pre>
 * @author K Becker
 * @version 1.0, Jan 2002
 */
public class Card {
    
    /* data members */
    // NOTE: joker & no-card gets treated as a special case
    // the rest are organized to make comparissons easier
    /** "CSDHW" */
    public static final String SUIT = "CSDHW";
    /** "A23456789TJQKW" */
    public static final String RANK = "A23456789TJQKW";
    public static final int    EMPTY = -2;
    public static final int    JOKER = -1;
    public static final int    WILDCARD = 52;
    public static final int    FIRST = 0;
    public static final int    LAST = 51;
    public static final int    HIGHRANK = 12;
    public static final int    LOWRANK = 0;
    
    private int cardval = EMPTY; // numeric -2..52
    private int rank = EMPTY;    // numeric -2..13
    private char crank = '.'; // char as in RANK
    private int suit = EMPTY;    // numeric -1..4
    private char csuit = '.'; // char as in SUIT
    private String pic = "--";
    
    private boolean acehigh = false; 
    /** true = ace beats king; false = king beats ace */
    
/*----------------------------------------------------------------*/
/* ----- constructors ----- */
/** Constructs a new Card with the value given
 */
public Card(int cval) {		
	/*----DEBUG----*/
	if (Debug.isSet())
	    System.out.print("Card(int c):: " + cval + "\n");
	/*----DEBUG----*/
	if (cval == JOKER) { // it's a joker
	    cardval = -1;
	    rank = -1;
	    crank = '0';
	    suit = -1;
	    csuit = 'J';
	    pic = ":)";
	}
	else if (cval == EMPTY) { // make a 'blank' card; already done
	    return;
	}
	else if (cval == WILDCARD) { // it's a wildcard
	    cardval = cval;
	    rank = 13;
	    crank = 'W';
	    suit = 4;
	    csuit = 'W';
	    pic = "..";
	}
	else if ((cval > JOKER)&&(cval < WILDCARD)) { // regular card
	    cardval = cval;
	    rank = cval%13;
	    crank = RANK.charAt(rank);
	    suit = cval/13;
	    csuit = SUIT.charAt(suit);
	    Character c1 = new Character(csuit);
	    Character c2 = new Character(crank);
	    pic = c1.toString() + c2.toString();
	}
	
}// end Card
    
/*----------------------------------------------------------------*/
/** Draw a random card. Jokers and Wildcards excluded.
  *
  *  @return the new card
  */
public static Card pick() {
/* return a random card
 */
	return new Card(MyRand.choose(FIRST,LAST));
	
}// end pick
    
/*----------------------------------------------------------------*/
/** Make an "EMPTY" card
  *
  *  @return representation of an empty card
  */
public static Card empty() {
	return new Card(EMPTY);
	
}// end empty
    
/*----------------------------------------------------------------*/
/* ----- access ----- */
    
/** Find out what suit this card is
  *  @return this card's suit as a char
  */
public char suitIs() {
	return csuit;
}
/** Find out what suit this card is
  *  @return this card's suit as an int
  */
public int suitNum() {
	return suit;
}
/** Find out what rank this card is
  *   @return this card's rank as a char
  */
public char rankIs() {
	return crank;
}
/** Find out what rank this card is
  *  @return this card's rank as an int
  */
public int rankNum() {
	return rank;
}
/** Show the card
  *  @return this card's picture
  */
public String show() {
	return pic;
}
    
/*----------------------------------------------------------------*/
/* ----- input ----- */
/* not right now */
    
/*----------------------------------------------------------------*/
/* ----- output ----- */
/** Print it out:
  */
public void display(){
	System.out.print(pic);	
}// display   
    
/*----------------------------------------------------------------*/
/* ----- make a copy ----- */
/** Copy the given parameter to the current object
  *
  * @param B the object we want to copy
  */
public void assign( Card B ) {
	cardval = B.cardval;
	rank = B.rank;
	crank = B.crank;
	suit = B.suit;
	csuit = B.csuit;
	pic = B.pic.toString();
	
}// end copyFrom
    
    
/*----------------------------------------------------------------*/
/* ----- operators ----- */
/** Return the next higher rank card
  *
  *  @return next card SAME suit, next rank with wrap
  */
public Card next() {
   // check for empty, joker, wildcard
   if (cardval == EMPTY) 
      return new Card(EMPTY);
   if (cardval == JOKER)
      return new Card(JOKER);
   if (cardval == WILDCARD)
      return new Card(WILDCARD);
      
	int val = rank + 1; // next val with wrap	
	if (val > HIGHRANK) val = LOWRANK;
	Card C = new Card(suit*(HIGHRANK+1) + val);		
	/*-----DEBUG-----*/
	if (Debug.isSet()) {
	   System.out.print("Card.next:: old rank: " + crank +
	                    " new rank= " + RANK.charAt(val) + "\n");
	   System.out.print("         :: old card is: " + pic + "\n");
	   System.out.print("         :: new card is: " + C.pic + "\n");
	}
	/*-----DEBUG-----*/
	return C;
}// end next

/*----------------------------------------------------------------*/
/** Return the next lower rank card
  *
  *  @return next card SAME suit, previous rank with wrap
  */
public Card prev() {
   // check for empty, joker, wildcard
   if (cardval == EMPTY) 
      return new Card(EMPTY);
   if (cardval == JOKER)
      return new Card(JOKER);
   if (cardval == WILDCARD)
      return new Card(WILDCARD);
      
	int val = rank - 1; // prev val with wrap
	if (val < LOWRANK) val = HIGHRANK;	
	Card C = new Card(suit*(HIGHRANK+1) + val);		
	/*-----DEBUG-----*/
	if (Debug.isSet()) {
	   System.out.print("Card.prev:: old rank: " + crank +
	                    " new rank= " + RANK.charAt(val) + "\n");
	   System.out.print("         :: old card is: " + pic + "\n");
	   System.out.print("         :: new card is: " + C.pic + "\n");
	}
	/*-----DEBUG-----*/
	return C;
}// end prev

/*----------------------------------------------------------------*/
/** See if the given param is the same as or smaller than we are
  *
  *  @param B the object to compare against
  *  @return true if we are greater than arg 'B'
  */
public boolean greaterThan( Card B ) {
/* return true if we are greater than arg 'B'
 */
	if (cardval > B.cardval) 
	    return true;
	else
	    return false;	
}// end greater

/*----------------------------------------------------------------*/    
/** See if the given param is the same as or lower RANK than we are
  *
  *  @param B the object to compare against
  *  @return true if we have higher RANK than arg 'B'
  */
public boolean greaterRank( Card B ) {
/* return true if we are greater than arg 'B'
 */
	if (rank > B.rank) 
	    return true;
	else
	    return false;	
}// end greaterRank
    
/*----------------------------------------------------------------*/
/** See if the given param is the same as we are
  *
  *  @param B the object to compare against
  *  @return true if we are the same as arg 'B'
  */
public boolean equalTo( Card B) {
/* return true if we are equal to arg 'B'
 */
	if (cardval == B.cardval) 
	    return true;
	else
	    return false;
}// end equalTo
    
/*----------------------------------------------------------------*/
/** See if the given param is the same RANK as we are
  *
  *  @param B the object to compare against
  *  @return true if we are the same RANK as arg 'B'
  */
public boolean equalRank( Card B) {
/* return true if we are equal to arg 'B'
 */
	if (rank == B.rank) 
	    return true;
	else
	    return false;
}// end equalRank
    
/*----------------------------------------------------------------*/
/** See if the given param is the same SUIT as we are
  *
  *  @param B the object to compare against
  *  @return true if we are the same SUIT as arg 'B'
  */
public boolean equalSuit( Card B) {
/* return true if we are equal to arg 'B'
 */
	if (suit == B.suit) 
	    return true;
	else
	    return false;
}// end equalSuit
    
/*----------------------------------------------------------------*/    
}// end Card
