/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "file/async.hh"
#include "threads/threads.hh"
#include "time/time.hh"
#include "error/error.hh"

i4_async_reader::i4_async_reader(char *name) : sig(name)  
{ 
  emulation=i4_F; 
  stop=i4_F;
}

void i4_async_reader_thread_start(void *arg)
{
  ((i4_async_reader *)arg)->PRIVATE_thread();
}

void i4_async_reader::init()
{
  if (i4_threads_supported())
  {
    stop=i4_T;
    i4_add_thread(i4_async_reader_thread_start, STACK_SIZE, this);
  }
}

void i4_async_reader::uninit()
{
  if (i4_threads_supported())
  {
    while (stop==i4_T)       // wait to thread is read to be stopped
      i4_thread_yield();
  
    stop=i4_T;
    sig.signal();
    while (stop)
      i4_thread_yield();
  }
}

i4_bool i4_async_reader::start_read(int fd, void *buffer, w32 size, 
                                    i4_file_class::async_callback call,
                                    void *context)
{
  if (!i4_threads_supported())
    i4_error("threads not supported");

  que_lock.lock();

  read_request r(fd, buffer, size, call, context);
  if (!request_que.que(r))
  {
    que_lock.unlock();
    return i4_F;
  }
  que_lock.unlock();

  sig.signal();
  return i4_T;
}


void i4_async_reader::emulate_speeds(read_request &r)
{    
  if (emulation) 
  {
    i4_time_class now, start;
    while (start.milli_diff(now) < r.size*1000/(1000*1024) + 20*1000)
    {
      i4_thread_yield();
      now.get();
    }
  }
}


void i4_async_reader::PRIVATE_thread()
{
  read_request r;
  sw32 amount;

  do
  {
    while (request_que.empty())   // if no more request to satisfy, wait for main process signal
    {
      stop=i4_F;
      sig.wait_signal();
    }

    if (!stop)
    {
      que_lock.lock();

      if (request_que.deque(r))
      {
        que_lock.unlock();
        emulate_speeds(r);

        amount = read(r.fd, r.buffer, r.size);          

        r.callback(amount, r.context);
      }
      else que_lock.unlock();
    }

  } while (!stop);
  stop=i4_F;
}