/*
        handpile.cpp (Käsipakan ohjelmamoduuli)

        V?.?? - ??????  Kimmo Teräväinen
        -----   ------  ----------------
        V0.01   121296  Added ShowHandEvaluation

        Look handpile.h
*/

#include "handpile.h"

#ifndef _Windows
#include "requester.h"
#endif

char *HandEvalText[] = {
  "Lousy Hand",
  "Pair",
  "Two Pairs",
  "Three of Kind",
  "Straight",
  "Flush",
  "Full House",
  "Four of Kind",
  "Five of Kind",
  "Straight Flush",
  "Royal Flush"
};


void ShowHandEvaluation(TWindow *wnd,int eval)
{
#ifdef _Windows
  wnd->MessageBox(HandEvalText[eval],"Your Hand:");
#else
  cRequester(wnd,"Your Hand:",HandEvalText[eval]).Execute();
#endif
}

cIMGCard *cHandPile::Deal()
{
  cIMGCard *card;
  for(int i=0; i<5 ; i++)
    if(cards[i])
      if(cards[i]->Turned()) {
        card=cards[i];
        cards[i]=NULL;
        return card;
      }
  return NULL;
}

cIMGCard *cHandPile::Remove(int i)
{
  cIMGCard *card;
  if(i<0 || i>4) return NULL;
  if(cards[i])
    if(cards[i]->Turned()) {
      card=cards[i];
      cards[i]=NULL;
      return card;
    }
  return NULL;
}

void cHandPile::Insert(cIMGCard *card)
{
  if(!card) return;
  for(int i=0; i<5 ; i++)
    if(!cards[i]) {
      cPoint p(CARD_SLOT_WIDTH*i,0);
      p+=pos;
      cards[i]=card;
      card->CanTurn();
      card->Turn_CoverUp();
      card->MoveTo(p);
      card->Show();
      return;
    }
}


int cHandPile::Can_Insert() const
{
  for(int i=0; i<5 ; i++)
    if(!cards[i]) return TRUE;
  return FALSE;
}

void cHandPile::TurnAll()
{
  for(int i=0; i<5 ; i++)
    if(cards[i]) cards[i]->Turn_CoverDown();
}

void cHandPile::FreezeAll()
{
  for(int i=0; i<5 ; i++)
    if(cards[i]) cards[i]->CanTurn(FALSE);
}


int cHandPile::Evaluate() const
{
  cCard arvio[5];
  int i,j,c,d,n=0;

  // Let's start by copying cards from hand (except jokers) to
  // arvio[] array
  //
  for(i=0; i < 5 ; i++ )
    if (cards[i]->Suit() != JOKER) arvio[n++]=*cards[i];


  // Special case 5 jokers
  if (n == 0) {
    if(GetPrefs_5jokers()) return ROYAL_FLUSH;
    return LOUSY_HAND;
  }


  // Sorting array... smallest 1st, ACE is smallest
  for( i=0 ; i<n ; i++)
    for( j=i ; j<n ; j++)
      if (arvio[i].Num() > arvio[j].Num()) {
        cCard temp=arvio[i];
        arvio[i]=arvio[j];
        arvio[j]=temp;
      }


  // Now special case 4 jokers
  if (n == 1) {
    if( arvio[0].Num_HI() >= T) return ROYAL_FLUSH;
    if(GetPrefs_5ofkind()) return FIVE_OF_KIND;
    return STRAIGHT_FLUSH;
  }

  // Search 2 biggest card sets, where cards are same.
  // return amount of item in these sets in c & d.
  //
  // mathematically this is:
  //  c=#{ X1,..Xc: X1=..=Xc=a } ja d=#{ Y1,..Yd: X1=..=Xd=b } , a!=b
  //  where Xj and Yj are numerical values of cards.
  //
  c=1; d=1;
  for(i=1 ; i<n ; i++ ) {
    if(arvio[i-1].Num() != arvio[i].Num()) {
      if(c>1) {
        if(d>1) break;
        d=c;
      }
      c=1;
    } else c++;
  }


  // If all cards are different we will examine possibility of
  // flush and/or straight. Also 4 of a kind may occur with
  // 3 jokers.
  //
  if(d<2 && c<2) {
    int value=FLUSH;

    // Is it Flush
    for(i=1; i<n ; i++)
      if(arvio[i-1].Suit() != arvio[i].Suit()) { value=LOUSY_HAND; break; }

    // Is it Straight
    if((arvio[n-1].Num()-arvio[0].Num()) < 5) value+=STRAIGHT;
    if((arvio[0].Num()==A) && (arvio[1].Num() >= T)) value+=STRAIGHT;

    if((value<STRAIGHT+FLUSH) && (n==2)) return FOUR_OF_KIND;

    if(value==STRAIGHT+FLUSH) {
      value=STRAIGHT_FLUSH;
      if((arvio[0].Num() == A) && (arvio[1].Num() >= T)) return ROYAL_FLUSH;
      if(arvio[0].Num() >= T) return ROYAL_FLUSH;
    }
    if(value!=LOUSY_HAND) return value;
  }


  if(d>=c) { j=d; } else { j=c; c=d; }  // j=max(d,c); c=min(c,d)

  j=j+5-n;    // let's add jokers to bigger card set, when we get best
              // possible hand.

  switch(j){
    case 2: if(c==2)  return TWO_PAIRS;
                      return PAIR;
    case 3: if(c==2)  return FULL_HOUSE;
                      return THREE_OF_KIND;
    case 4:           return FOUR_OF_KIND;
    case 5:           return FIVE_OF_KIND;
  }

  return LOUSY_HAND;
}
