// Copyright 1997 by Jon Dart. All Rights Reserved.
#include "calctime.h"
#include "globals.h"
#include "util.h"

DWORD calc_time_limit(int moves, int minutes, int incr, 
   int32 time_left, int32 opp_time)
{
        int time_target = 0;
        int moves_in_game = game_moves->num_moves()/2; // full moves, not half-moves
        int est_time = incr/4 + minutes;
        if (incr >0)
        {
            // Fischer-type time control

            int extra_time = (time_left - 6000*minutes);
            if (extra_time < 0) extra_time = 0;
            
            int pct80 = 4*6000*minutes/5;
            
            if (time_left < 3000) // less than 30 seconds
                time_target = 90*incr;
            else if (time_left > pct80) // more than 80% of time is left
            {
                time_target = 100*incr + (time_left-3000)/20 + extra_time/12;
            }
            else
            {
                time_target = 100*(est_time > 3 ? est_time + 1 :
                   est_time);
                if (minutes > 0)
                  time_target = 100*incr + time_target*(time_left-3000)/(6000*minutes);
            }
            // add some sanity checks
            if (minutes > 0)
            {
              if (incr < 2*minutes)
              {
                 // don't use more than 1/40 the total time + the increment
                 if (time_target > (extra_time + 6000*minutes)/40 +
                     100*incr)
                   time_target = 100*incr + (extra_time + 6000*minutes)/40;
              }
              else
              {
                 // don't use more than 1/30 the total time + the increment
                 if (time_target > (extra_time + 6000*minutes)/30 +
                     100*incr)
                   time_target = 100*incr + (extra_time + 6000*minutes)/30;
              }
            }
            // try not to fall behind the opponent
            if (minutes == 0 ||
                time_left < minutes*6000/2) // less than 1/2 initial value
            {
                if (time_left > 3000)
                {
                   int threshold = Util::Min(9000,500*est_time);
                   int max_boost = time_target/4;
                   if (opp_time > time_left + threshold)
                   {
                       time_target -= Util::Min(max_boost,(opp_time-time_left)/10);
                       if (time_target < incr*100)
                            time_target = 90*incr;
                   }
                   else if (time_left > opp_time + threshold)
                   {
                       time_target += Util::Min(max_boost,(time_left-opp_time)/10);
                   }
                }
            }
        }
        else // zero-increment or "Tournament" game
        {
//            cout << "time left " << time_left << endl;
            if (time_left > 500)
                time_left-= 500;
            if (moves == 0) // "Game" time limit
            {
               if (time_left < 3000) // 30 seconds
                  time_target = (time_left+1000)/80;
               else if (time_left < 1500*minutes) // < 1/4 time left
                  time_target = (100*(time_left+1000))/3000;
               else if (time_left < 3000*minutes) // < 1/2 time left
                  time_target = (100*(time_left+4000))/3000;
               else
                  time_target = 100*(minutes > 3 ? minutes + 1 : minutes);
               // try not to fall behind the opponent
               int threshold = Util::Min(9000,500*est_time);
               int max_boost = time_target/4;
               if (opp_time > time_left + threshold && time_left > 3000)
               {
                   time_target -= Util::Min(max_boost,(opp_time-time_left)/10);
               }
               else if (time_left > opp_time + threshold)
               {
                   time_target += Util::Min(max_boost,(time_left-opp_time)/10);
               }
            }
            else
            {
               int moves_to_time_control = moves-(moves_in_game % moves);
               time_target = time_left/moves_to_time_control;
               int slack = Util::Max(500,time_target/10);
               if (time_left > slack+100)
                  time_target = (time_left-slack)/moves_to_time_control; 
               else
                  time_target = 0;
            }
        }
        // set a minimum (0.3 sec).
        if (time_target < 30) time_target = 30;
        if (time_target > time_left) 
        {
           cout << "warning : time_target > time_left" << endl;
           if (incr)
              time_target = 90*incr;
           else
             time_target = time_left/4;
        }
        //cout << "whisper time target = " <<
        //         time_target << endl;
        return time_target;
}

