/*-----------------------------------------------------------------------------

Copyright (C) 2012

A. Ronald Gallant
Post Office Box 659
Chapel Hill NC 27514
USA

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

-----------------------------------------------------------------------------*/

#include "libscl.h"
#include "craps.h"

using namespace scl;
using namespace std;

namespace craps {

  payoff_t pass_line_bet::house_action
    (roll_t roll, marker_t marker, bool& remove_bet)
  {
    INTEGER sum = roll.first + roll.second; 

    if (marker.on) {
      switch (sum) {
        case  2 :
        case  3 :
        case 11 :
        case 12 : 
          {
            remove_bet = false; 
            return payoff_t(0, 0);
          }
          break;
        case 7 :
          {
            remove_bet = true;
            return payoff_t(bet + odds, 0);
          }
          break;
        case  4 :
        case 10 :
          {
            if (marker.point == sum) {
              remove_bet = true;
              INTEGER pay = bet + 2*odds;
              return payoff_t(-pay, bet + odds + pay);
            }
            else {
              remove_bet = false;
              return payoff_t(0, 0);
            }
          }
          break;    
        case 5 :
        case 9 :
          {
            if (marker.point == sum) {
              remove_bet = true;
              INTEGER pay = bet + odds%2 + 3*(odds/2);
              return payoff_t(-pay, bet + odds + pay);
            }
            else {
              remove_bet = false;
              return payoff_t(0, 0);
            }
          }
          break;    
        case 6 :
        case 8 :
          {
            if (marker.point == sum) {
              remove_bet = true;
              INTEGER pay = bet + odds%5 + 6*(odds/5);
              return payoff_t(-pay, bet + odds + pay);
            }
            else {
              remove_bet = false;
              return payoff_t(0, 0);
            }
          }
          break;    
      }
    }
    else {
      switch (sum) {
        case  4 :
        case  5 :
        case  6 :
        case  8 :
        case  9 :
        case 10 :
          { 
            remove_bet = false;
            return payoff_t(0, 0);
          }
          break;
        case  7 :
        case 11 :
          {
            remove_bet = true;
            INTEGER pay = bet;
            return payoff_t(-bet, bet + pay);
          }
          break;
        case  2 :
        case  3 :
        case 12 : 
          {
            remove_bet = true;
            return payoff_t(bet, 0);
          }
          break;
       }
    }
    error("Error, pass_line_bet, this should never happen");
    return payoff_t();
  }
  
  payoff_t pass_line_bet::player_action 
    (roll_t roll, marker_t marker, INTEGER change_odds)
  {
    if (!marker.on) return payoff_t(0,0);
  
    if (change_odds < 0) {
      INTEGER deduct = -change_odds <= odds ? -change_odds : odds;
      odds -= deduct;
      return payoff_t(0, deduct);
    }
    else { // change_odds > 0
      switch (marker.point) {
        case  4 :
        case 10 :
          {
            odds += change_odds;
            if (odds <= 3*bet) {
              return payoff_t(0, -change_odds);
            }
            else {
              odds = 3*bet;
              INTEGER refund = odds - 3*bet;
              return payoff_t(0, refund - change_odds);
            }
          }
          break;    
        case 5 :
        case 9 :
          {
            odds += change_odds;
            if (odds <= 4*bet) {
              return payoff_t(0, -change_odds);
            }
            else {
              INTEGER refund = odds - 4*bet;
              odds = 4*bet;
              return payoff_t(0, refund - change_odds);
            }
          }
          break;    
        case 6 :
        case 8 :
          {
            odds += change_odds;
            if (odds <= 5*bet) {
              return payoff_t(0, -change_odds);
            }
            else {
              INTEGER refund = odds - 5*bet;
              odds = 5*bet;
              return payoff_t(0, refund - change_odds);
            }
          }
          break;    
        }
      }
  
    return payoff_t(0,0);
  }

  payoff_t come_bet::house_action
    (roll_t roll, marker_t marker, bool& remove_bet)
  {
    INTEGER sum = roll.first + roll.second; 

    if (point != 0) {
      switch (sum) {
        case  2 :
        case  3 :
        case 11 :
        case 12 : 
          {
            remove_bet = false; 
            return payoff_t(0, 0);
          }
          break;
        case 7 :
          {
            remove_bet = true;
            if (marker.on) {
              return payoff_t(bet + odds, 0);
            } 
            else {
              return payoff_t(bet, odds);
            }
          }
          break;
        case  4 :
        case 10 :
          {
            if (point == sum) {
              remove_bet = true;
              INTEGER pay = marker.on ? bet + 2*odds : bet;
              return payoff_t(-pay, bet + odds + pay);
            }
            else {
              remove_bet = false;
              return payoff_t(0, 0);
            }
          }
          break;    
        case 5 :
        case 9 :
          {
            if (point == sum) {
              remove_bet = true;
              INTEGER pay = marker.on ? bet + odds%2 + 3*(odds/2) : bet;
              return payoff_t(-pay, bet + odds + pay);
            }
            else {
              remove_bet = false;
              return payoff_t(0, 0);
            }
          }
          break;    
        case 6 :
        case 8 :
          {
            if (point == sum) {
              remove_bet = true;
              INTEGER pay = marker.on ? bet + odds%5 + 6*(odds/5) : bet;
              return payoff_t(-pay, bet + odds + pay);
            }
            else {
              remove_bet = false;
              return payoff_t(0, 0);
            }
          }
          break;    
      }
    }
    else {  // point == 0
      switch (sum) {
        case  4 :
        case  5 :
        case  6 :
        case  8 :
        case  9 :
        case 10 :
          { 
            point = sum;
            remove_bet = false;
            return payoff_t(0, 0);
          }
          break;
        case  7 :
        case 11 :
          {
            remove_bet = true;
            INTEGER pay = bet;
            return payoff_t(-bet, bet + pay);
          }
          break;
        case  2 :
        case  3 :
        case 12 : 
          {
            remove_bet = true;
            return payoff_t(bet, 0);
          }
          break;
       }
    }
    error("Error, come_bet, this should never happen");
    return payoff_t();
  }
  
  payoff_t come_bet::player_action 
    (roll_t roll, marker_t marker, INTEGER change_odds)
  {
    if (point == 0) return payoff_t(0,0);
  
    if (change_odds < 0) {
      INTEGER deduct = -change_odds <= odds ? -change_odds : odds;
      odds -= deduct;
      return payoff_t(0, deduct);
    }
    else { // change_odds > 0
      switch (point) {
        case  4 :
        case 10 :
          {
            odds += change_odds;
            if (odds <= 3*bet) {
              return payoff_t(0, -change_odds);
            }
            else {
              odds = 3*bet;
              INTEGER refund = odds - 3*bet;
              return payoff_t(0, refund - change_odds);
            }
          }
          break;    
        case 5 :
        case 9 :
          {
            odds += change_odds;
            if (odds <= 4*bet) {
              return payoff_t(0,-change_odds);
            }
            else {
              odds = 4*bet;
              INTEGER refund = odds - 4*bet;
              return payoff_t(0, refund - change_odds);
            }
          }
          break;    
        case 6 :
        case 8 :
          {
            odds += change_odds;
            if (odds <= 5*bet) {
              return payoff_t(0,-change_odds);
            }
            else {
              INTEGER refund = odds - 5*bet;
              odds = 5*bet;
              return payoff_t(0, refund - change_odds);
            }
          }
          break;    
        }
      }
  
    return payoff_t(0,0);
  }

  payoff_t any_craps_bet::house_action
    (roll_t roll, marker_t marker, bool& remove_bet)
  {
    INTEGER sum = roll.first + roll.second; 

    switch (sum) {
      case  2 :
      case  3 :
      case 12 :
        {
          remove_bet = true;
          INTEGER pay = 7*bet;
          return payoff_t(-pay, bet + pay);
        }
        break;
      default :
        {
          remove_bet = true;
          return payoff_t(bet , 0);
        }
        break;
    }
  }

}
