/* TN5250
 * Copyright (C) 1997 Michael Madore
 * 
 * This file is part of TN5250.
 *
 * TN5250 is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1, or (at your option)
 * any later version.
 * 
 * TN5250 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 * 
 */
#include "tn5250-config.h"

#ifndef NDEBUG

#define _TN5250_TERMINAL_PRIVATE_DEFINED

#if defined(WINE) || defined(WIN32)
#undef VERSION
#include <windows.h>
#include <winsock.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "utility.h"
#include "buffer.h"
#include "record.h"
#include "stream.h"
#include "dbuffer.h"
#include "menu.h"
#include "terminal.h"
#include "field.h"
#include "display.h"
#include "debug.h"

struct _Tn5250TerminalPrivate {
   Tn5250Stream *dbgstream;
   Tn5250Terminal *slaveterm;
   int keyq;
   int pauseflag;
};

typedef struct _Tn5250TerminalPrivate Tn5250TerminalPrivate;

static int debug_stream_connect(Tn5250Stream * This, const char *to);
static void debug_stream_disconnect(Tn5250Stream * This);
static int debug_stream_handle_receive(Tn5250Stream * This);
static void debug_stream_send_packet(Tn5250Stream * This, int length, 
				     StreamHeader header, unsigned char *data);static void debug_stream_destroy(Tn5250Stream *This);

static void debug_terminal_init(Tn5250Terminal *This);
static void debug_terminal_term(Tn5250Terminal *This);
static void debug_terminal_destroy(Tn5250Terminal /*@only@*/ *This);
static int debug_terminal_width(Tn5250Terminal *This);
static int debug_terminal_height(Tn5250Terminal *This);
static int debug_terminal_flags(Tn5250Terminal *This);
static void debug_terminal_update(Tn5250Terminal *This, Tn5250Display *display);
static void debug_terminal_update_indicators(Tn5250Terminal *This, Tn5250Display *display);
static int debug_terminal_waitevent(Tn5250Terminal *This);
static int debug_terminal_getkey(Tn5250Terminal *This);
static void debug_terminal_beep(Tn5250Terminal *This);

/****f* lib5250/tn5250_debug_stream_init
 * NAME
 *    tn5250_debug_stream_init
 * SYNOPSIS
 *    ret = tn5250_debug_stream_init (This);
 * INPUTS
 *    Tn5250Stream *       This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
int tn5250_debug_stream_init (Tn5250Stream *This)
{
   This->connect = debug_stream_connect;
   This->disconnect = debug_stream_disconnect;
   This->handle_receive = debug_stream_handle_receive;
   This->send_packet = debug_stream_send_packet;
   This->destroy = debug_stream_destroy;
   This->debugfile = NULL;
   return 0; /* Ok */
}

/****f* lib5250/tn5250_debug_terminal_new
 * NAME
 *    tn5250_debug_terminal_new
 * SYNOPSIS
 *    ret = tn5250_debug_terminal_new (slave, dbgstream);
 * INPUTS
 *    Tn5250Terminal *     slave      - 
 *    Tn5250Stream *       dbgstream  - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
Tn5250Terminal *tn5250_debug_terminal_new (Tn5250Terminal *slave, Tn5250Stream *dbgstream)
{
   Tn5250Terminal *This = tn5250_new(Tn5250Terminal, 1);
   if (This != NULL) {
      This->conn_fd = -1;
      This->init = debug_terminal_init;
      This->term = debug_terminal_term;
      This->destroy = debug_terminal_destroy;
      This->width = debug_terminal_width;
      This->height = debug_terminal_height;
      This->flags = debug_terminal_flags;
      This->update = debug_terminal_update;
      This->update_indicators = debug_terminal_update_indicators;
      This->waitevent = debug_terminal_waitevent;
      This->getkey = debug_terminal_getkey;
      This->beep = debug_terminal_beep;
      This->config = NULL;

      This->data = tn5250_new(Tn5250TerminalPrivate, 1);
      if (This->data == NULL) {
	 free (This);
	 return NULL;
      }
      This->data->dbgstream = dbgstream;
      This->data->slaveterm = slave;
      This->data->keyq = -1;
      This->data->pauseflag = 1;
   }
   return This;
}

/****f* lib5250/tn5250_debug_terminal_set_pause
 * NAME
 *    tn5250_debug_terminal_set_pause
 * SYNOPSIS
 *    tn5250_debug_terminal_set_pause (This, f);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 *    int                  f          - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
void tn5250_debug_terminal_set_pause (Tn5250Terminal *This, int f)
{
   This->data->pauseflag = f;
}

/****i* lib5250/debug_stream_connect
 * NAME
 *    debug_stream_connect
 * SYNOPSIS
 *    ret = debug_stream_connect (This, to);
 * INPUTS
 *    Tn5250Stream *       This       - 
 *    const char *         to         - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static int debug_stream_connect(Tn5250Stream * This, const char *to)
{
   This->debugfile = fopen (to, "r");
   if (This->debugfile == NULL)
      return -1;
   return 0;
}

/****i* lib5250/debug_stream_disconnect
 * NAME
 *    debug_stream_disconnect
 * SYNOPSIS
 *    debug_stream_disconnect (This);
 * INPUTS
 *    Tn5250Stream *       This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_stream_disconnect(Tn5250Stream * This)
{
   if (This->debugfile != NULL)
      fclose (This->debugfile);
}

/****i* lib5250/debug_stream_handle_receive
 * NAME
 *    debug_stream_handle_receive
 * SYNOPSIS
 *    ret = debug_stream_handle_receive (This);
 * INPUTS
 *    Tn5250Stream *       This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static int debug_stream_handle_receive(Tn5250Stream * This)
{
   return 1;
}

static void debug_stream_send_packet(Tn5250Stream * This, int length, 
				     StreamHeader header, unsigned char *data)

{
   /* noop */
}

/****i* lib5250/debug_stream_destroy
 * NAME
 *    debug_stream_destroy
 * SYNOPSIS
 *    debug_stream_destroy (This);
 * INPUTS
 *    Tn5250Stream *       This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_stream_destroy(Tn5250Stream *This)
{
   /* noop */
}

/****i* lib5250/debug_terminal_init
 * NAME
 *    debug_terminal_init
 * SYNOPSIS
 *    debug_terminal_init (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_terminal_init(Tn5250Terminal *This)
{
   (* (This->data->slaveterm->init)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_term
 * NAME
 *    debug_terminal_term
 * SYNOPSIS
 *    debug_terminal_term (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_terminal_term(Tn5250Terminal *This)
{
   (* (This->data->slaveterm->term)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_destroy
 * NAME
 *    debug_terminal_destroy
 * SYNOPSIS
 *    debug_terminal_destroy (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_terminal_destroy(Tn5250Terminal /*@only@*/ *This)
{
   (* (This->data->slaveterm->destroy)) (This->data->slaveterm);
   free (This->data);
   free (This);
}

/****i* lib5250/debug_terminal_width
 * NAME
 *    debug_terminal_width
 * SYNOPSIS
 *    ret = debug_terminal_width (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static int debug_terminal_width(Tn5250Terminal *This)
{
   return (* (This->data->slaveterm->width)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_height
 * NAME
 *    debug_terminal_height
 * SYNOPSIS
 *    ret = debug_terminal_height (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static int debug_terminal_height(Tn5250Terminal *This)
{
   return (* (This->data->slaveterm->height)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_flags
 * NAME
 *    debug_terminal_flags
 * SYNOPSIS
 *    ret = debug_terminal_flags (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static int debug_terminal_flags(Tn5250Terminal *This)
{
   return (* (This->data->slaveterm->flags)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_update
 * NAME
 *    debug_terminal_update
 * SYNOPSIS
 *    debug_terminal_update (This, display);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 *    Tn5250Display *      display    - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_terminal_update(Tn5250Terminal *This, Tn5250Display *display)
{
   (* (This->data->slaveterm->update)) (This->data->slaveterm, display);
}

/****i* lib5250/debug_terminal_update_indicators
 * NAME
 *    debug_terminal_update_indicators
 * SYNOPSIS
 *    debug_terminal_update_indicators (This, display);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 *    Tn5250Display *      display    - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_terminal_update_indicators(Tn5250Terminal *This, Tn5250Display *display)
{
   (* (This->data->slaveterm->update_indicators)) (This->data->slaveterm, display);
}

/****i* lib5250/debug_terminal_beep
 * NAME
 *    debug_terminal_beep
 * SYNOPSIS
 *    debug_terminal_beep (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static void debug_terminal_beep(Tn5250Terminal *This)
{
   (* (This->data->slaveterm->beep)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_waitevent
 * NAME
 *    debug_terminal_waitevent
 * SYNOPSIS
 *    ret = debug_terminal_waitevent (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    This is a hook for the Tn5250Terminal->waitevent method.
 *****/
static int debug_terminal_waitevent(Tn5250Terminal *This)
{
   char buf[256];
   int n;

   if (feof (This->data->dbgstream->debugfile))
      return (* (This->data->slaveterm->waitevent)) (This->data->slaveterm);

   while (fgets (buf, sizeof (buf)-2, This->data->dbgstream->debugfile)) {
      if (buf[0] != '@')
	 continue;

      if (!memcmp (buf, "@record ", 8)) {
	 if (This->data->dbgstream->current_record == NULL)
	    This->data->dbgstream->current_record = tn5250_record_new ();
	 for (n = 14; n < 49; n += 2) {
	    unsigned char b;

	    if (isspace (buf[n]))
	       n++;
	    if (isspace (buf[n]))
	       break;

	    b = (isdigit (buf[n]) ? (buf[n] - '0') : (tolower (buf[n]) - 'a' + 10)) << 4;
	    b |= (isdigit (buf[n+1]) ? (buf[n+1] - '0') : (tolower (buf[n+1]) - 'a' + 10));
	    tn5250_record_append_byte(This->data->dbgstream->current_record, b);
	 }
      } else if (!memcmp (buf, "@eor", 4)) {
	 if (This->data->dbgstream->current_record == NULL)
	    This->data->dbgstream->current_record = tn5250_record_new ();
	 if (This->data->dbgstream->records == NULL)
	    This->data->dbgstream->records
	       = This->data->dbgstream->current_record->prev
	       = This->data->dbgstream->current_record->next
	       = This->data->dbgstream->current_record;
	 else {
	    This->data->dbgstream->current_record->next = This->data->dbgstream->records;
	    This->data->dbgstream->current_record->prev = This->data->dbgstream->records->prev;
	    This->data->dbgstream->current_record->next->prev = This->data->dbgstream->current_record;
	    This->data->dbgstream->current_record->prev->next = This->data->dbgstream->current_record;
	 }
	 This->data->dbgstream->current_record = NULL;
	 This->data->dbgstream->record_count++;
	 return TN5250_TERMINAL_EVENT_DATA;
      } else if (!memcmp (buf, "@abort", 6)) {
	 /* It's useful to force a core dump sometimes... */
	 abort ();
      } else if (!memcmp (buf, "@key ", 5)) {
	 if (This->data->pauseflag)
	    (* (This->data->slaveterm->waitevent)) (This->data->slaveterm);
	 This->data->keyq = atoi (buf + 5);
	 return TN5250_TERMINAL_EVENT_KEY;
      }
   }
   
   /* EOF */
   return (* (This->data->slaveterm->waitevent)) (This->data->slaveterm);
}

/****i* lib5250/debug_terminal_getkey
 * NAME
 *    debug_terminal_getkey
 * SYNOPSIS
 *    ret = debug_terminal_getkey (This);
 * INPUTS
 *    Tn5250Terminal *     This       - 
 * DESCRIPTION
 *    DOCUMENT ME!!!
 *****/
static int debug_terminal_getkey(Tn5250Terminal *This)
{
   int ret = This->data->keyq;

   if (This->data->keyq == -1 && feof (This->data->dbgstream->debugfile))
      ret = (* (This->data->slaveterm->getkey)) (This->data->slaveterm);
   else
      (* (This->data->slaveterm->getkey)) (This->data->slaveterm);

   This->data->keyq = -1;
   return ret;
}

#endif /* NDEBUG */



syntax highlighted by Code2HTML, v. 0.9.1