//*********************** Copy right information *************************
//                                FAQ's
// Q.   Is this program copy right protected?
// Ans. No. Even if it was you will copy it anyway so what is the point
//************************************************************************
// Program: Solitaire card game
// Programmer: H K Gupta     Date: 25 Oct1997
//                      added lazy bone option and useless help Aug 16 1998
//************************************************************************

import java.awt.*;
import java.awt.image.*;
import java.applet.Applet;
import java.lang.Math;

public class Solitaire extends Applet implements Runnable{

        Panel   pTop;
                Button  bNewGame;
                Button  bBuyExtra;
                Button  bLazyBones;
                Button  bSingleCard;
                Button  bHelp;
        Panel   pLeft;
                Label[] lSolitaire;
        Panel   pRight;
                Label[] lHridayesh;

        SolitairePlayArea playArea;
        Label           results;

        HridayeshCardDeck       deck;           // card deck for playing the game
        boolean         flagMoveSingleCard = false;
        boolean         isLazyBones = false;

        Thread          runThread = null;
        boolean         firstTime = true;
        boolean         pauseInEffect = false;

        public void init() {
        }

        public void start() {
                if (firstTime) {
                        deck = new HridayeshCardDeck(); // get a new card deck
                        setUpDisplay() ;
                        results.setText("*S*O*L*I*T*A*I*R*E*");
                        firstTime = false;
                }
                if (runThread == null) {
                        if(!pauseInEffect) {
                                runThread = new Thread(this, "Solitaire");
                                runThread.start();
                        }
                }
        }

        public void run() {
                while (Thread.currentThread() == runThread) {
                        if(playArea.moveInProgress)  {
                                playArea.move();
                        }
                        else {
                                if(playArea.autoInProgress) {
                                        playArea.moveAuto();
                                }
                        }
                        if(!gameOnDisplay) playArea.doGameOver();
                        try {
                                Thread.sleep(40);
                        } catch (InterruptedException e){
                        }
                }
        }

        public void stop() {
                runThread = null;
        }

        void setUpDisplay() {
                setLayout(new BorderLayout());
                pTop = new Panel();
                pTop.setLayout(new GridLayout(1,0));
                add("North", pTop);
                        bNewGame = new Button("New Game");
                        pTop.add(bNewGame);
                        bBuyExtra = new Button("Buy turnOver for 25 pnts");
                        pTop.add(bBuyExtra);
                        bLazyBones = new Button("Select Lazy Bones");
                        pTop.add(bLazyBones);
                        bSingleCard = new Button("Move Multiple Cards");
                        pTop.add(bSingleCard);
                        bHelp = new Button("HELP ME??");
                        pTop.add(bHelp);
                pLeft = new Panel();
                pLeft.setLayout(new GridLayout(0, 1));
                add("West", pLeft);
                        lSolitaire = new Label[9];
                        for(int i = 0; i < 9; i++) {
                                lSolitaire[i] = new Label("SOLITAIRE".substring(i, i+ 1), Label.CENTER);
                                lSolitaire[i].setFont(new Font("TimesRoman",Font.BOLD,24));
                                lSolitaire[i].setForeground(Color.red);
                                pLeft.add(lSolitaire[i]);
                        }
                pRight = new Panel();
                pRight.setLayout(new GridLayout(0, 1));
                add("East", pRight);
                        lHridayesh = new Label[9];
                        for(int i = 0; i < 9; i++) {
                                lHridayesh[i] = new Label("HRIDAYESH".substring(i, i+ 1), Label.CENTER);
                                lHridayesh[i].setFont(new Font("TimesRoman",Font.BOLD,24));
                                lHridayesh[i].setForeground(Color.red);
                                pRight.add(lHridayesh[i]);
                        }

                playArea = new SolitairePlayArea(this);
                add("Center", playArea);
                results = new Label("Loading Card Images", Label.CENTER);
                add("South", results);
                validate();
        }

        private boolean newGame() {
                if(playArea.autoInProgress || playArea.moveInProgress) return true;
                playArea.flagMoveStored = false;
                gameOnDisplay = true;
                playArea.dealHand();
                updateScore(1, -52);
                return true;
        }

        boolean gameOnDisplay = false;
        public boolean action(Event e, Object arg) {
                Object target = e.target;

                if(playArea.autoInProgress || playArea.moveInProgress) return true;
                if(target == bNewGame) return newGame();

                if(target == bBuyExtra) {
                        if(gameOnDisplay) {
                                playArea.buyExtraTurnOver();
                                return true;
                        }
                }

                if(target == bSingleCard) {
                        if(flagMoveSingleCard) {
                                bSingleCard.setLabel("Move Three cards");
                                bBuyExtra.setLabel("Buy turnOver for 25 points");
                        }
                        else {
                                bBuyExtra.setLabel("Buy turnOver for 75 points");
                                bSingleCard.setLabel("Move single card");
                        }
                        flagMoveSingleCard = !flagMoveSingleCard;
                        return newGame();
                }

                if(target == bHelp) { processHelp(); return true;}

                if(target == bLazyBones) {
                        if (isLazyBones) {
                                isLazyBones = false;
                                bLazyBones.setLabel("Select Lazy Bones");
                        }
                        else {
                                isLazyBones = true;
                                bLazyBones.setLabel("I Am Lazy");
                        }
                }

                return false;
        }

        public boolean keyDown(Event e, int key) {
                if(playArea.autoInProgress || playArea.moveInProgress) return true;
                return false;
        }

        int     gamesPlayed = 0; // statistics variables
        int     score = 0;

        void    updateScore(int games, int points) {
                gamesPlayed += games;
                score += points;
                dispScore();
        }

        void    dispScore() {
                results.setText("Games: " + gamesPlayed + " Score: " + score);
        }

        private void processHelp() {
                HridayeshHelp window = null;
                try {
                    window = new HridayeshHelp();
                } catch (Exception e) {
                    bHelp.setLabel("Error");
                    bHelp.disable();
                    return;
                }
                window.setTitle("SolitaireHelp");
                window.setText(
"\n                 Solitaire Help \n\n" +
"\nWe will not help you with the rules of the game. You better know them." +
"\nHowever we will let you know about the features we have tried to push" +
"\non unsuspecting public.\n"+
"\n1. Buy Turnover : After losing this game 273 straight times one of our" +
"\nfan threatened to stop playing this game. Now we can not have that. So" +
"\nto help out people who do not mind little bit of cheating, we allow you" +
"\nto continue the game (after you have lost to it) by paying a small penalty." +
"\nThe penalty is 25 points in three card at a time and 75 points in single" +
"\ncard at a time version. (PLEASE do not ask us to explain this single/three" +
"\ncard at a time business).\n\n" +
"\n2. Lazy Bones: Human beings have two kind of bones. One kind is made from " +
"\nCalcium and other unpronouncable materials. The other kind is made from" +
"\nsheer laziness and its assorted compounds. To help these people we will " +
"\nautomatically open any close card and save these souls from executing" +
"\npainful mouse clicks just for opening a card.\n\n\n" +
"\n                     GOOD LUCK");
                window.pack();
                window.show();
        }
}

class SolitairePlayArea extends Canvas {
        private Solitaire controller;
        private HridayeshLoadCards deckImages;
        private int nPlayStacks = 7;
        int     flagPaint = -1;
        SolitaireStack[]        stack;

        final   int     typeClose = 0;
        final   int     typeDone = 1;
        final   int     typePlay = 2;
        final   int     typeOpen = 3;
        SolitaireStack  closeStack;
        SolitaireStack  openStack;
        SolitaireStack  dragStack;

        HridayeshCardShow drawOver;

        public  SolitairePlayArea(Solitaire controller) {
                super();
                this.controller = controller;
                deckImages = new HridayeshLoadCards((Applet)controller);
                stack = new SolitaireStack[13];
                for(int i = 0; i < 13; i++) stack[i] = new SolitaireStack(this, i, deckImages.getCardW(), deckImages.getCardH());
                closeStack = stack[11];
                openStack = stack[12];
                dragStack = new SolitaireStack(this, 0, 0, 0); // we need a non drawing stack only
                moveArray = new SolitaireStack[100][2];
                moveCount = new int[100];
                drawOver = new HridayeshCardShow(deckImages);
                displayReset();
        }

        private void displayReset() {
                for(int i = 0; i < 13; i++) stack[i].reset();
                ssSelected = null;
                resetProgressFlags();
                flagPaint = -1;
        }

        public  void resetProgressFlags() {
                moveInProgress = false;
                autoInProgress = false;
                dragInProgress = false;
        }

        public  void dealHand() {
                displayReset();
                int     card;
                closeStackTurnOverCount = 0;
                controller.deck.reset();
                for(int k = 0; k < 7; k++) {
                        for(int i = 0; i <= k; i++) {
                                card = controller.deck.newCard();
                                if(k == i) {
                                        stack[k].addCard(card, true);
                                }
                                else {
                                        stack[k].addCard(card, false);
                                }
                        }
                }
                for(int i = 0; i < 24; i++) closeStack.addCard(controller.deck.newCard(), false);
                flagPaint = -1;
                repaint();
        }

        private int closeStackTurnOverCount = 0;
        private boolean turnOversPending() {
                int     max = 3;
                if(controller.flagMoveSingleCard) max = 1;
                if(closeStackTurnOverCount < max) return true;
                return false;
        }

        public  void buyExtraTurnOver() {
                closeStackTurnOverCount--;
                if(controller.flagMoveSingleCard) {
                        controller.updateScore(0, -75);
                }
                else {
                        controller.updateScore(0, -25);
                }
                if(flagPaint != -1) return;
                flagPaint = 12;
                repaint();
        }

        private boolean flagSetOffsets = true;

        Image           iBuffer; // double buffer the playArea
        Graphics        g;
        public  void update(Graphics gPlayArea) {
                if(flagSetOffsets) {
                        Dimension d = size();
                        iBuffer = createImage(d.width, d.height);
                        g = iBuffer.getGraphics();
                        for(int i = 0; i < 13; i++) stack[i].setOffsets(g);
                        flagSetOffsets = false;
                }
                if(flagPaint == 10) return; // some painting in progress
                int tmp = flagPaint;
                flagPaint = 10; // prevent others from issuing a repaint();
                switch(tmp) {
                        case -1:
                        case  0: paintEveryThing(g);            break;
                        case  2: selectForDrag(g);              break;
                        case  4: paintMove(g);                  break;
                        case  5: moveAutoCard(g);               break;
                        case  7: paintDragging(g);              break;
                        case  8: paintDragOver(g);              break;
                        case 11: drawOver.draw(g, this);        break;
                        case 12: closeStack.drawStack(g);       break;
                        default:
                }
                gPlayArea.drawImage(iBuffer, 0, 0, this);
                flagPaint = -1;
        }

        void    moveAutoCard(Graphics g) {
                if(controller.isLazyBones) { // open any closed card
                        if(!closeStack.isEmpty()) {
                                if(openStack.isEmpty()) {
                                        putAndMoveCard(g, closeStack, null);
                                        return;
                                }
                        }
                        for(int i = 0; i < 7; i++) {
                                if(!stack[i].isEmpty()) {
                                        if(stack[i].isTopCardClosed()) {
                                                putAndMoveCard(g, stack[i], null);
                                                return;
                                        }
                                }
                        }
                }
                int     lowSuitNo = 13;
                for(int i = 7; i < 11; i++) {
                        if(suitNo(stack[i].topCard()) < lowSuitNo) lowSuitNo = suitNo(stack[i].topCard());
                }
                lowSuitNo++;
                for(int i = 0; i < 13; i++) {
                        int type = stack[i].getType();
                        if((type == typeOpen) ||(type == typePlay)) {
                                int     card = stack[i].topCard();
                                if((card != -1) && (!stack[i].isTopCardClosed())) {
                                        if(suitNo(card) == lowSuitNo) {
                                                for(int j = 7; j < 11; j++) {
                                                        if(stack[j].isEmpty()) {
                                                                putAndMoveCard(g, stack[i], stack[j]);
                                                                return;
                                                        }
                                                        if((int)(card / 13) == (int)(stack[j].topCard() / 13)) {
                                                                putAndMoveCard(g, stack[i], stack[j]);
                                                                return;
                                                        }
                                                }
                                        }
                                        else {
                                                if(suitNo(card) == (lowSuitNo + 1)) {
                                                        for(int j = 7; j < 11; j++) {
                                                                if(!stack[j].isEmpty()) {
                                                                        if((suitNo(card) == (suitNo(stack[j].topCard()) + 1)) &&
                                                                                        ((card / 13) == (stack[j].topCard() / 13))) {
                                                                                putAndMoveCard(g, stack[i], stack[j]);
                                                                                return;
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }
                }
                autoInProgress = false;
                moveIndex = totalMoves - 1;
                flagMoveStored = true;
                if(gameOver()) {
                        controller.updateScore(1, 0);
                        controller.gameOnDisplay = false;
                        flagMoveStored = false;
                }
        }

        void    putAndMoveCard(Graphics g, SolitaireStack ssSrc, SolitaireStack ssDst) { // single Card
                moveCardFromSrcToDst(g, ssSrc, ssDst, ssSrc.getNCards() - 1);
                moveArray[totalMoves][0] = ssSrc;
                moveArray[totalMoves][1] = ssDst;
                moveCount[totalMoves] = ssSrc.getNCards() - 1; // top card only
                totalMoves++;
        }

        private SolitaireStack[][]      moveArray;
        private int[]   moveCount;
        private int     moveIndex;
        private int     totalMoves;
        boolean flagMoveStored = false;

        void    paintMove(Graphics g) {
                if(!moveInProgress) return;
                moveCardFromSrcToDst(g, moveArray[moveIndex][0], moveArray[moveIndex][1], moveCount[moveIndex]);
                moveIndex++;
                if(moveIndex >= totalMoves) {
                        moveInProgress = false;
                        autoInProgress = true;
                }
        }

        void    moveCardFromSrcToDst(Graphics g, SolitaireStack ssSrc, SolitaireStack ssDst, int pos) {
                if(ssDst == null) { // open close card
                        if(ssSrc.getType() == typePlay) {
                                int card = ssSrc.removeCard(g);
                                ssSrc.putCard(g, card, true);
                        }
                        if(ssSrc.getType() == typeClose) {
                                if(ssSrc.isEmpty()) {
                                        if((!openStack.isEmpty()) && turnOversPending()) { // Move From Open stack all cards
                                                int n = openStack.getNCards();
                                                for(int i = 0; i < n; i++) ssSrc.putCard(g, openStack.removeCard(g), false);
                                                openStack.setOpenIndex(0);
                                        }
                                }
                                else {
                                        int n = getCardsToMove();
                                        openStack.eraseStack(g);
                                        openStack.setOpenIndex(0);
                                        for(int i = 0; i < n; i++) openStack.putCard(g, ssSrc.removeCard(g), true);
                                        if(closeStack.isEmpty()) {
                                                closeStackTurnOverCount++;
                                                closeStack.drawTopCard(g);
                                        }
                                }
                        }
                }
                else {
                        for(int i = pos; i < ssSrc.getNCards(); i++) ssDst.putCard(g, ssSrc.getIthCard(i), true);
                        for(int i = ssSrc.getNCards() - 1; i >= pos; i--) ssSrc.removeCard(g);
                        if(ssSrc.getType() == typeDone) controller.updateScore(0, -5);
                        if(ssDst.getType() == typeDone) controller.updateScore(0, 5);
                }
        }

        private int getCardsToMove() {
                int n = 1;
                if(!controller.flagMoveSingleCard) n = 3;
                if(n > closeStack.getNCards()) n = closeStack.getNCards();
                return n;
        }

        void    paintEveryThing(Graphics g) {
                Dimension d = size();
                g.setColor(Color.gray);
                g.fillRect(0, 0, d.width, d.height);
                for(int i = 0; i < 13; i++) stack[i].drawStack(g);
        }

        void    paintCard(Graphics g, boolean drawFlag, int x, int y, int cardNo, int type) {
                if(drawFlag && (cardNo >= 0)) {
                        g.drawImage(deckImages.getCardImage(cardNo), x, y, this);
                }
                else {
                        g.setColor(Color.gray);
                        g.fillRect(x, y, deckImages.getCardW() + 1, deckImages.getCardH() + 1);
                        if((type == typeClose) && (!turnOversPending())) {
                                g.setColor(Color.yellow);
                                g.fillRect(x, y, deckImages.getCardW() + 1, deckImages.getCardH() + 1);
                                g.setColor(Color.black);
                                g.drawString("XXXXXXX", x + 10, y + 50);
                        }
                        if(y == 2) {
                                g.setColor(Color.black);
                                g.drawRect(x, y, deckImages.getCardW() - 1, deckImages.getCardH() - 1);
                        }
                }
        }

        private SolitaireStack ssSelected = null;
        private SolitaireStack ssDestination = null;

        boolean autoInProgress = false;
        boolean moveInProgress = false;
        boolean dragInProgress = false;

        private int cardToDrag;

        public boolean mouseDown(Event event, int x, int y) {
                if(!controller.gameOnDisplay) return false;
                if(autoInProgress || moveInProgress) return false;
                if(flagPaint != -1) return false;
                for(int i = 0; i < 13; i++) {
                        int     selPos = stack[i].getPositionSelected(x, y);
                        switch(selPos) {
                                case -1: break; // not inside
                                case -2: if(stack[i] == closeStack) {
                                                return setMove(stack[i], null, 0);
                                         }
                                         break;
                                default: if(stack[i].isTopCardClosed()) {
                                                return setMove(stack[i], null, 0);
                                         }
                                        ssSelected = stack[i];
                                        dragInProgress = true;
                                        cardToDrag = selPos;
                                        flagPaint = 2; // selection
                                        dragOldX = stack[i].getXPos(selPos);
                                        dragOldY = stack[i].getYPos(selPos);
                                        dragXOff = x - dragOldX;
                                        dragYOff = y - dragOldY;
                                        repaint();
                                        return true;
                        }
                }
                return false;
        }

        void    selectForDrag(Graphics g) {
                if(ssSelected == null) return;
                ssSelected.paintSelection(g, cardToDrag);
        }

        Image   selImage;
        Graphics gSel;
        Image   savedImage;
        Graphics gSaved;

        void    drawSelectionImage(Graphics g, int x, int y, int w, int h) {
                selImage = createImage(w, h);
                gSel = selImage.getGraphics();
                gSel.drawImage(iBuffer, - x, - y, this);
                dragStack.reset();
                for(int i = cardToDrag; i < ssSelected.getNCards(); i++) dragStack.addCard(ssSelected.getIthCard(i), true);
                for(int i = ssSelected.getNCards() - 1; i >= cardToDrag; i--) ssSelected.removeCard(g);
                savedImage = createImage(w, h);
                gSaved = savedImage.getGraphics();
                gSaved.drawImage(iBuffer, - x, - y, this);
                g.drawImage(selImage, x, y, this);
        }

        private int dragOldX, dragOldY;
        private int dragX, dragY;
        private int dragXOff, dragYOff;

        private void paintDragging(Graphics g) {
                g.drawImage(savedImage, dragOldX, dragOldY, this);
                gSaved.drawImage(iBuffer, - dragX, - dragY, this);
                dragOldX = dragX;
                dragOldY = dragY;
                g.drawImage(selImage, dragX, dragY, this);
        }

        private void paintDragOver(Graphics g) {
                for(int i = 0; i < dragStack.getNCards(); i++) ssSelected.addCard(dragStack.getIthCard(i), true);
                g.drawImage(savedImage, dragOldX, dragOldY, this);
                if((ssDestination != null) && (ssDestination != ssSelected)) {
                        setMove(ssSelected, ssDestination, cardToDrag);
                }
                else {
                        ssSelected.drawStack(g);
                }
        }

        public boolean mouseDrag(Event event, int x, int y) {
                if((!dragInProgress) || (flagPaint != -1)) return false;
                dragX = x - dragXOff;
                dragY = y - dragYOff;
                flagPaint = 7;
                repaint();
                return false;
        }

        public boolean mouseUp(Event event, int x, int y) {
                if(!dragInProgress) return false;
                for(int i = 0; i < 13; i++) {
                        if(stack[i].isInside(x, y)) {
                                if(isMovePossible(dragStack, stack[i], 0)) {
                                        setDragOver(stack[i]);
                                        return false;
                                }
                        }
                }
                setDragOver(null);
                return false;
        }

        private void setDragOver(SolitaireStack ss) {
                ssDestination = ss;
                dragInProgress = false;
                flagPaint = 8;
                repaint();
        }

        boolean setMove(SolitaireStack ssSrc, SolitaireStack ssDst, int pos) {
                flagMoveStored = false;
                autoInProgress = false;
                moveInProgress = true;
                totalMoves = 0;
                moveIndex = 0;
                addMove(ssSrc, ssDst, pos);
                ssSelected = null;
                return true;
        }

        void    addMove(SolitaireStack ssSrc, SolitaireStack ssDst, int pos) {
                moveArray[totalMoves][0] = ssSrc;
                moveArray[totalMoves][1] = ssDst;
                moveCount[totalMoves] = pos;
                totalMoves++;
        }

        boolean isMovePossible(SolitaireStack ssSrc, SolitaireStack ssDst, int pos) {
                if(ssSrc == null) return false;
                if(ssSrc == ssDst) return false; // no move on self
                if(ssDst == openStack) return false; // no move to openStack
                if(ssSrc.isEmpty()) return false;
                if(ssSrc.isTopCardClosed()) return false;
                switch(ssDst.getType()) {
                        case typeDone:  if(pos != (ssSrc.getNCards() - 1)) return false;
                                        return isCardAceOrNext(ssSrc.topCard(), ssDst.topCard());
                        case typePlay:
                                        if(ssDst.isEmpty()) {
                                                if(suitNo(ssSrc.getIthCard(pos)) == 11) return true;
                                        }
                                        else {
                                                if(!ssDst.isTopCardClosed()) {
                                                        return isCardAllowed(ssDst.topCard(), ssSrc.getIthCard(pos));
                                                }
                                        }
                                        break;
                        default:
                }
                return false;
        }

        boolean isCardAceOrNext(int src, int dst) {
                if(dst == -1) {
                        if(suitNo(src) == -1) return true;
                }
                else {
                        if(((src / 13) == (dst / 13)) && (suitNo(src) == (suitNo(dst) + 1))) return true;
                }
                return false;
        }

        boolean isCardAllowed(int high, int low) {
                if(suitColor(high) == suitColor(low)) return false;
                if(suitNo(high) == (suitNo(low) + 1)) return true;
                return false;
        }

        int     suitNo(int card) {
                if(card < 0) return -2;
                int suitNum = card % 13;
                if(suitNum == 12) suitNum = -1;
                return suitNum;
        }

        int     suitColor(int card) {
                int clr = card / 13;
                if((clr == 0) || (clr == 3)) return 0;
                return 1;
        }

        void    move() {
                if(flagPaint != -1) return;
                flagPaint = 4;
                repaint();
        }

        void    moveAuto() {
                if(flagPaint != -1) return;
                flagPaint = 5;
                repaint();
        }

        boolean gameOver() {
                for(int i = 7; i < 11; i++) {
                        if(stack[i].getNCards() != 13) return false;
                }
                controller.gameOnDisplay = false;
                return true;
        }

        boolean gameLost() {
                return false;
        }

        public  void paint(Graphics g) {
                if(flagPaint != -1) return;
                update(g);
        }

        public  void doGameOver() {
                if(flagPaint != -1) return;
                flagPaint = 11;
                repaint();
        }
}

class   SolitaireStack {
        private int     crdW, crdH;
        private int     nCards; // No of cards on stack
        private int[]   stack;
        private int     closeCards;
        private int     type;
        private int     index;
        private int     indexOpen;
        private SolitairePlayArea parent;
        private final int stackSize = 25;
        final   int     typeClose = 0;
        final   int     typeDone = 1;
        final   int     typePlay = 2;
        final   int     typeOpen = 3;

        public  SolitaireStack(SolitairePlayArea parent, int index, int crdW, int crdH) {
                this.parent = parent;
                this.index = index;
                if(index < 7) {
                        type = typePlay;
                }
                else {
                        if(index < 11) {
                                type = typeDone;
                        }
                        else {
                                if(index == 11) {
                                        type = typeClose;
                                }
                                else {
                                        type = typeOpen;
                                }
                        }
                }
                this.crdW = crdW;
                this.crdH = crdH;
                stack = new int[stackSize];
                reset();
        }

        public  void reset() {
                for(int i = 0; i < stackSize; i++) stack[i] = -1;
                closeCards = 0;
                nCards = 0;
                indexOpen = 0;
        }

        public  void setOpenIndex(int n) { // index for open cards to be shift displayed sideways
                indexOpen = nCards - n;
        }

        public  int topCard() {
                if(nCards < 1) return -1;
                return stack[nCards - 1];
        }

        public  boolean isEmpty() {
                if(nCards == 0) return true;
                return false;
        }

        private int     xOff = 0;
        private int     yOff = 0;
        public  void setOffsets(Graphics g) {
                Dimension d = parent.size();
                switch(type) {
                        case typeClose: yOff = 2;
                                        xOff = 10;
                                        break;
                        case typeOpen:  yOff = 2;
                                        xOff = 10 + crdW + 20;
                                        break;
                        case typeDone:  yOff = 2;
                                        xOff = d.width - (4 - (index - 7)) * crdW;
                                        break;
                        case typePlay:  yOff = crdH + 9;
                                        int xGap = (d.width - 7 * crdW) / 8;
                                        xOff =  xGap + index * (xGap + crdW);
                                        break;
                        default:
                }
        }

        public boolean isInside(int x, int y) {
                if(type == typePlay) {
                        if((x < xOff) || (x > (xOff + crdW)) || (y < yOff)) return false;
                        return true;
                }
                if(type == typeDone) {
                        if((x < xOff) || (x > (xOff + crdW)) || (y < yOff) || (y > (yOff + crdH))) return false;
                        return true;
                }
                return false;
        }

        public  int getPositionSelected(int x, int y) {
                if(nCards < 1) {
                        if(type != typeClose) return -1;
                        if((x < xOff) || (x > (xOff + crdW)) || (y < yOff) || (y > (yOff + crdH))) return -1;
                        return -2;
                }
                if((nCards == closeCards) || (type != typePlay)) { // check top Card only
                        if(isCardSelected(nCards - 1, x, y)) return nCards - 1;
                }
                else {
                        for(int i = nCards - 1; i >= closeCards; i--) {
                                if(isCardSelected(i, x, y)) return i;
                        }
                }
                return -1;
        }

        private boolean isCardSelected(int i, int x, int y) {
                int xPos = getXPos(i);
                int yPos = getYPos(i);
                if((x < xPos) || (x > (xPos + crdW)) || (y < yPos) || (y > (yPos + crdH))) return false;
                return true;
        }

        public  int getXPos(int i) {
                int     xPos = xOff;
                switch(type) {
                        case typeClose: xPos = xOff + ((int)(i / 8)) * 2;
                                        break;
                        case typeOpen:  if(i > indexOpen) xPos = xOff + (i - indexOpen) * xShow;
                                        break;
                        default:
                }
                return xPos;
        }

        public  int getYPos(int i) {
                int     yPos = yOff;
                switch(type) {
                        case typeClose: yPos = yOff + ((int)(i / 8)) * 2;
                                        break;
                        case typeOpen:  if(i > indexOpen) yPos = yOff + (i - indexOpen) * 2;
                                        break;
                        case typePlay:  if(nCards < 1) return yOff;
                                        if(closeCards == 0) return yOff + yShow * i;
                                        if(i < closeCards) return yOff + i * 2;
                                        yPos = yOff + closeCards * 2 + (i - closeCards) * yShow;
                                        break;
                        default:
                }
                return yPos;
        }

        void    addCard(int card, boolean openFlag) {
                nCards++;
                stack[nCards - 1] = card;
                if(!openFlag) closeCards = nCards;
        }

        void    putCard(Graphics g, int card, boolean status) {
                addCard(card, status);
                drawTopCard(g);
        }

        int     removeCard(Graphics g) {
                if(nCards == 0) return -1;
                int     retCard = stack[nCards - 1];
                drawCard(g, false, nCards - 1);
                nCards--;
                stack[nCards] = -1;
                if(closeCards > nCards) closeCards = nCards;
                drawTopCard(g);
                return retCard;
        }

        int     getNCards() {
                return nCards;
        }

        int     getIthCard(int i) {
                return stack[i];
        }

        int     getType() {
                return type;
        }

        private int yShow = 17;
        private int xShow = 20;
        void    paintSelection(Graphics g, int i) {
                parent.drawSelectionImage(g, getXPos(i), getYPos(i), crdW, (nCards - i - 1) * yShow + crdH);
        }

        void    drawCard(Graphics g, boolean drawFlag, int j) {
                if((j >= closeCards) && drawFlag) {
                        parent.paintCard(g, drawFlag, getXPos(j), getYPos(j), stack[j], type);
                }
                else {
                        parent.paintCard(g, drawFlag, getXPos(j), getYPos(j), 52, type);
                }
        }

        void    drawTopCard(Graphics g) {
                if(isEmpty()) {
                        drawCard(g, false, 0);
                }
                else {
                        drawCard(g, true, nCards - 1);
                }
        }

        public  void drawStack(Graphics g) {
                if(isEmpty()) {
                        drawCard(g, false, 0);
                }
                else {
                        for(int j = 0; j < nCards; j++) drawCard(g, true, j);
                }
        }

        public  void eraseStack(Graphics g) {
                if(!isEmpty()) {
                        for(int i = nCards -1; i >= 0; i--) drawCard(g, false, i);
                }
        }

        boolean isTopCardClosed() {
                if(nCards <= closeCards) return true;
                return false;
        }
}


