/*
  Print
*/

#include "print.h"

#include "addr.h"
#include "console.h"
#include "head.h"
#include "jump.h"
#include "mem.h"
#include "message.h"
#include "object.h"
#include "os.h"
#include "page.h"
#include "pc.h"
#include "shared.h"
#include "wio.h"

static word buff[MAX_SLACK];
static int buff_held, buff_width;

void init_print(void)
{
  extern int linecount;
  extern bool enable_screen;
  extern bool disable_script;

  extern void (*PrintChar) (word);
  extern bool windowing_enabled;
  extern word current_window;
  extern bool use_buffered_io;

  linecount         = 0;
  enable_screen     = 1;
  disable_script    = 0;
  PrintChar         = print_char;
  buff_held         = 0;
  buff_width        = 0;
  windowing_enabled = 0;
  current_window    = 0;
  use_buffered_io   = 1;
}

static void measure(word ch)
{
  if(kind(ch) != 0)
    out_char(ch);
  else
    buff_width += char_width(ch);
}

static void print_buffer(int count)
{
  int i;
  start_update();
  for(i = 0; i < count; ++i)
    out_char(buff[i]);
  finish_update();
  os_mcpy(buff, buff + count, (buff_held -= count) * sizeof(*buff));
  for(i = buff_width = 0; i < buff_held; ++i)
    measure(buff[i]);
}

void flush_prt_buff(void)
{
  extern int linecount;
  print_buffer(buff_held);
  linecount = 0;
}

void print_num(word number)
{
  extern void (*PrintChar) (word);
  int num;

  if(number == 0)
    (*PrintChar) ((word) '0');
  else
  {
    num = (signed_word) number;
    if(num < 0)
    {
      num = -num;
      (*PrintChar) ((word) '-');
    }
    PrintNumber(num);
  }
}

void PrintNumber(int num)
{
  extern void (*PrintChar) (word);

  if(num > 9) PrintNumber(num / 10);
  (*PrintChar) ('0' + num % 10);
}

void print2(word packed)
{
  long_word addr = ad_text_addr(packed);
  word page      = pg_page(addr);
  word offset    = pg_offset(addr);
  print_coded(&page, &offset);
}

void print1(word address)
{
  word page   = pg_page(address);
  word offset = pg_offset(address);
  print_coded(&page, &offset);
}

void wrt(void)
{
  word page   = pc_page();
  word offset = pc_offset();
  print_coded(&page, &offset);
  set_pc(page, offset);
}

void writeln(void)
{
  wrt();
  new_line();
  ret_true();
}

void new_line(void)
{
  print_buffer(buff_held);
  out_char('\n');
}

void print_char(word ch)
{
  extern bool use_buffered_io;
  extern bool use_internal_buffer;
  extern long_word internal_io_buffer;
  extern word int_io_buff_length;
  extern word current_window;

  if(use_internal_buffer)
  {
    wr_byte_addr(internal_io_buffer + 2 + int_io_buff_length++, ch);
  }
  else if(!use_buffered_io || current_window != 0)
  {
    out_char(ch);
  }
  else
  {
    buff[buff_held++] = ch;
    measure(ch);
    if(buff_width >= display_width()
    || buff_held >= MAX_SLACK)
    {
      int i = buff_held - 1;
      while(i >= 0 && buff[i] != ' ')
        --i;
      out_char('\f');
      print_buffer(i >= 0 ? i+1 : buff_held);
      out_char('\n');
    }
  }
}
