/* *** specialwin.c *** */

static struct TextFont	*font = NULL;
static struct TextAttr	txtAttr;

#define FONTNAME	"topaz.font"
#define FONTYSIZE	8
#define FONTSTYLE	FS_NORMAL
#define FONTFLAGS	FPF_ROMFONT


#include "specialhost.h"
#include "specialwin.h"




#define WIN_X_KOO		30
#define WIN_Y_KOO		40
#define WIN_WIDTH		440
#define WIN_HEIGHT		130
#define WIN_TITLE		"Special-Host-Program V" VERSION
#define WIN_IDCMP_FLAGS		CLOSEWINDOW | MOUSEBUTTONS | GADGETUP | REFRESHWINDOW | RAWKEY
#define WIN_X_MIN_WIDTH		390
#define WIN_X_MIN_HEIGHT	70
#define WIN_X_MAX_WIDTH		640
#define WIN_X_MAX_HEIGHT	300

#define NR_TEXT_LINES		50		/* Lines */
#define LINE_LENGTH		80		/* Chars */
#define START_PRINTING		55		/* Pixel */
#define HEIGHT_CHAR		10		/* Pixel */
#define WIDTH_CHAR		 8		/* Pixel */




/**------------------*** Icon ***------------------**/

#define ICON_HEIGHT	35
#define ICON_WIDTH	64
#define ICON_LEFT_EDGE	20
#define ICON_TOP_EDGE	20

static USHORT  __chip imageData1[] = {
 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x0000, 0x0001,
 0x8000, 0x0000, 0x07FE, 0x0001,
 0x8100, 0x0000, 0x0402, 0x0001,
 0x8380, 0x0000, 0x07FE, 0x0001,
 0x8540, 0x0000, 0x0402, 0x0001,
 0x8100, 0x0000, 0x01DC, 0x0001,
 0x8000, 0x0000, 0x0402, 0x0001,
 0x8100, 0x0000, 0x07DA, 0x0001,
 0x8100, 0x0000, 0x0400, 0x0001,
 0x8100, 0x0000, 0x07DA, 0x0001,
 0x8100, 0x00F7, 0x4402, 0x0001,
 0x8100, 0x00C0, 0x41DA, 0x0001,
 0x8100, 0x0092, 0x4402, 0x0001,
 0x8100, 0x00A4, 0xC7FE, 0x0001,
 0x811F, 0xF8C9, 0x4402, 0x0001,
 0x8115, 0x5892, 0x47FE, 0x00C1,
 0x811A, 0xA8A4, 0xC402, 0x0061,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFFF1,
 0x8100, 0x0000, 0x0000, 0x0061,
 0x8100, 0x0000, 0x0000, 0x00C1,
 0x8000, 0x0000, 0x0000, 0x0001,
 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
/**/
 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
 0x8000, 0x0000, 0x0000, 0x0000,
 0x8000, 0x0000, 0x0000, 0x0000,
 0x8000, 0x0000, 0x0000, 0x0000,
 0x8FFC, 0x0E1C, 0x0000, 0x0000,
 0x88C4, 0x0B34, 0x0000, 0x0000,
 0x80C0, 0x01E0, 0x0000, 0x0000,
 0x80CF, 0xC0C0, 0x7800, 0x0000,
 0x80CC, 0x41E0, 0x0000, 0x0000,
 0x80CC, 0x0B34, 0x0000, 0x0000,
 0x80CF, 0x8E1C, 0x0000, 0x0000,
 0x800C, 0x0000, 0x0000, 0x0000,
 0x800C, 0x4000, 0x0000, 0x0000,
 0x800F, 0xC000, 0x0000, 0x0000,
 0x8000, 0x0000, 0x07FE, 0x0000,
 0x8100, 0x0000, 0x0402, 0x0000,
 0x8380, 0x0000, 0x07FE, 0x0000,
 0x8540, 0x0000, 0x0402, 0x0000,
 0x8301, 0xC38F, 0x0FFF, 0x8800,
 0x8102, 0x2448, 0x9526, 0x4800,
 0x8182, 0x0448, 0x17FE, 0x4800,
 0x8141, 0xC78F, 0x1427, 0xC800,
 0x8120, 0x2408, 0x17FE, 0x4800,
 0x8112, 0x24FF, 0xD526, 0x4900,
 0x8109, 0xC4CF, 0x4FFE, 0x4F00,
 0x8100, 0x0092, 0x4402, 0x0000,
 0x8100, 0x00A4, 0xC7FE, 0x0000,
 0x811F, 0xF8C9, 0x4402, 0x0000,
 0x8115, 0x5892, 0x47FE, 0x00C0,
 0x811A, 0xA8A4, 0xC402, 0x0060,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFFF0,
 0x8100, 0x0000, 0x0000, 0x0060,
 0x8100, 0x0000, 0x0000, 0x00C0,
 0x8000, 0x0000, 0x0000, 0x0000,
 0x0000, 0x0000, 0x0000, 0x0000,
/**/
 };

struct Image image1 = {
  0,			/* LeftEdge */
  0,			/* TopEdge */
  ICON_WIDTH,		/* Width */
  ICON_HEIGHT,		/* Height */
  2,			/* Depth */
  NULL,			/* ImageData */
  0x3,			/* PlanePick */
  0x0,			/* PlaneOnOff */
  0,			/* [NextImage] */
 };




struct scroll_win  {
	struct	scroll_text	*top;		/* first viewed line */
	struct	scroll_text	*first_free;
		long		number;		/* number of used lines in buffer */
		long		displayed;	/* number of displayed lines */
  };

struct scroll_text {
		char		*line;
	struct  scroll_text	*next_line;
	struct  scroll_text	*prev_line;
		short		is_first;	/* is first line in buffer */
		short		is_last;	/* is last line in buffer */
  };

#ifdef LATTICE
extern	long	_stack;
extern	char *	_procname;
extern	long	_priority;
extern	long	_BackGroundIO;
extern	BPTR	_Backstdout;
#endif

struct Library		*IFFBase	= NULL;
struct GfxBase		*GfxBase	= NULL;
struct IntuitionBase	*IntuitionBase	= NULL;

extern struct MsgPort 		*special_port;
extern IFFFILE			ifffile;
extern struct BitMap		*bmap;

static struct Window		*win;
static struct Window		*icon;
static struct scroll_win	swin;
static 	      int		display_len;
static 	      int		lines_to_show;
static	      int		height_char;
static	      int		width_char;
static	      int		icon_x_pos;
static	      int		icon_y_pos;
static	      int		win_x_pos;
static	      int		win_y_pos;
static	      int		win_width;
static	      int		win_height;
static	      int		win_title_height;


static void	OpenI			(void);
static void	OpenG			(void);
static void	OpenLib			(void);
static void	CloseLib		(void);
static void	CloseWin		(void);
static int	get_wb_screen_data	(int *BarHeight);
static void	CloseTopaz		(void);
static void	OpenTopaz		(void);
static void	CloseIcon		(void);
static UBYTE	OpenIcon		(void);
static UBYTE	OpenWin			(void);
static void	refresh_draw_modus	(int draw_modus, int base_dpi);
static void	set_picture_draw_modus	(long nr, int *draw_modus, int *base_dpi);
static void	DrawWin			(void);
static long	keys			(struct IntuiMessage *msg);
static long	WindowMessage		(int *draw_modus, int *base_dpi);
static void	init_text		(void);
static void	DisplayText		(void);
static void	ScrollUp		(void);
static void	ScrollDown		(void);



void close_all(void)
{
  close_port_bitm();
  CloseWin();
  CloseIcon();
  CloseTopaz();
  CloseLib();
  if (_Backstdout) {
    Close(_Backstdout);
    _Backstdout = NULL;
  }
}

void Fatal(int nr)
{
  long ret;
  char *message;
  char str[64];
  
  switch (nr) {
    case NO_INTUI:
    	message = "can't open Intuition-Library!";
    	ret = 20;
    	break;
    case NO_GFX:
    	message = "can't open Graphics-Library!";
    	ret = 20;
    	break;
    case LINE_TO_LONG:
    	message = "line to long!!";
    	ret = 20;
    	break;
    case NO_WIN:
    	message = "can't open window!";
    	ret = 15;
    	break;
    case NO_ICON:
    	message = "can't open icon-window!";
    	ret = 15;
    	break;
    case NO_MEMORY:
    	message = "not enough memory!";
    	ret = 15;
    	break;
    case NOT_FIRST:
	message = "this is not the first special-programm!?";
	ret = 5;
	break;
    case NO_PORT:
    	message = "can't open message-port!";
    	ret = 10;
    	break;
    case NO_MESSAGE:
    	message = "signal without message??";
    	ret = 15;
    	break;
    case NO_MEM:
    	message = "no memory!";
    	ret = 10;
    	break;
    case EXP_SEND_SP:
    	message = "expect AC_SEND_SPECIAL!";
    	ret = 10;
    	break;
    case NO_OK_BIT:
    	message = "expect AC_OK_BITMAP!";
    	ret = 10;
    	break;
    default:
    	message = "unknown error!?";
    	ret = 20;
    	break;
  }
  sprintf(str, "Fatal: %s\n", message);
  if (_Backstdout) {
    Write(_Backstdout, str, strlen(str));
  }

  close_all();
  exit(ret);
}

static void OpenI(void)
{
  IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  if (IntuitionBase==NULL) {
    Fatal(NO_INTUI);
  }
}

static void OpenG(void)
{
  GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
  if (GfxBase==NULL) {
    Fatal(NO_GFX);
  }
}

static void OpenLib(void)
{
#ifndef LATTICE
  int bytes;
#endif

  OpenI();
  OpenG();

#ifdef LATTICE
  image1.ImageData = (USHORT *)&imageData1;
#else
  bytes = ICON_HEIGHT * ICON_WIDTH * 2 / 8;
  image1.ImageData = AllocMem(bytes, MEMF_CHIP | MEMF_PUBLIC);
  if (image1.ImageData == NULL) {
    Fatal(NO_MEMORY);
  }
  memcpy((char *)image1.ImageData, (char *)imageData1, bytes);
#endif
}

static void CloseLib(void)
{
#ifndef LATTICE
  if (image1.ImageData) != NULL) {
    FreeMem(image1.ImageData, ICON_HEIGHT * ICON_WIDTH * 2 / 8);
  }
#endif

  if (IFFBase != NULL) CloseLibrary(IFFBase);
  if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase);
  if (GfxBase != NULL) CloseLibrary((struct Library *)GfxBase);
}

static void CloseWin(void)
{
  if (win != NULL) {
    win_x_pos  = win->LeftEdge;
    win_y_pos  = win->TopEdge;
    win_width  = win->Width;
    win_height = win->Height;
    CloseWindow(win);
    win = NULL;
  }
}


static void CloseTopaz(void)
{
  if (font != NULL) {
    CloseFont(font);
    font = NULL;
  }
}

static void OpenTopaz(void)
{
  txtAttr.ta_Name  = (STRPTR)FONTNAME;
  txtAttr.ta_YSize = FONTYSIZE;
  txtAttr.ta_Style = FONTSTYLE;
  txtAttr.ta_Flags = FONTFLAGS;
  font = OpenFont(&txtAttr);
}


static int get_wb_screen_data(int *BarHeight)
{
  struct Screen hscr;
  int res = 0;

  res = GetScreenData((char *)&hscr, (long)sizeof(hscr), (long)WBENCHSCREEN, IntuitionBase->ActiveScreen);
  if (res) {
    *BarHeight = hscr.BarHeight;
  }
  return (res);
}



/*--------------------------------------------*/
static struct Gadget dragit =
   { 0,0, 0, 0, 0,GADGIMAGE|GADGHIMAGE|GRELWIDTH|GRELHEIGHT,GADGIMMEDIATE,
   WDRAGGING, (APTR)&image1, (APTR)&image1,0,0,0,0,0 };

static struct NewWindow NewWI = {
   0, 0, 0, 0, 2,0, GADGETDOWN,
   SMART_REFRESH | BORDERLESS | NOCAREREFRESH,
   NULL, NULL, NULL, NULL, NULL, 0,0,0,0, WBENCHSCREEN
};

static void CloseIcon(void)
{
  if (icon != NULL) {
    RemoveGadget(icon,&dragit);
    icon_x_pos = icon->LeftEdge;
    icon_y_pos = icon->TopEdge;
    CloseWindow(icon);
    icon = NULL;
  }
}

static UBYTE OpenIcon(void)
{
  dragit.Height  = ICON_HEIGHT;
  NewWI.Height   = ICON_HEIGHT;
  NewWI.Width    = ICON_WIDTH;
  NewWI.LeftEdge = icon_x_pos;
  NewWI.TopEdge  = icon_y_pos;

  if ((icon = OpenWindow(&NewWI)) == NULL) {
    Fatal(NO_ICON);
  }

  if (font != NULL) {
    SetFont(win->RPort, font);		/* set all to my font */
  }

  AddGList(icon,&dragit,0,1,0);
  RefreshGadgets(&dragit,icon,0);
  
  return icon->UserPort->mp_SigBit;
}
/*--------------------------------------------*/




static UBYTE OpenWin(void)
{
  struct NewWindow new_win; 

  new_win.LeftEdge = win_x_pos;
  new_win.TopEdge  = win_y_pos;
  new_win.Width = win_width;
  new_win.Height = win_height;
  new_win.DetailPen = 0;
  new_win.BlockPen = 1;
  new_win.Title = (STRPTR)WIN_TITLE;
  new_win.Flags = WINDOWCLOSE | ACTIVATE | WINDOWSIZING | WINDOWDEPTH | 
			WINDOWDRAG | SIMPLE_REFRESH | RMBTRAP /*| GIMMEZEROZERO*/;
  new_win.IDCMPFlags = WIN_IDCMP_FLAGS;
  new_win.Type = WBENCHSCREEN;
  new_win.FirstGadget = &toIcon_Gad;
  new_win.CheckMark = NULL;
  new_win.Screen = NULL;
  new_win.BitMap = NULL;
  new_win.MinWidth  = WIN_X_MIN_WIDTH;
  new_win.MinHeight = WIN_X_MIN_HEIGHT;
  new_win.MaxWidth  = WIN_X_MAX_WIDTH;
  new_win.MaxHeight = WIN_X_MAX_HEIGHT;
  win = (struct Window *)OpenWindow(&new_win);
  if (win == NULL) {
     Fatal(NO_WIN);
  }
  if (font != NULL) {
    SetFont(win->RPort, font);		/* set all to my font */
  }

  return win->UserPort->mp_SigBit;
}


static void DrawWin(void)
{
  struct RastPort *rp = win->RPort;
  long start = START_PRINTING + win_title_height - 10;

  if (win == NULL) return;

  rp = win->RPort;
  Move(rp,2,start);
  Draw(rp,win->Width-3,start);
  Move(rp,2,start-10);
  Draw(rp,win->Width-3,start-10);
}

static long keys(struct IntuiMessage *msg)
{
  ULONG Code, Qualifier;
  long ret = 0;

  Code = msg->Code;
  Qualifier = msg->Qualifier;

  if (!(Code & 128)) {
    switch (Code) {
      case CURSORUP:
	ScrollUp();
    	break;
      case CURSORDOWN:
        ScrollDown();
    	break;
      case 51:			/* c */
        if (Qualifier & IEQUALIFIER_CONTROL) {
          ret = 10;
        }
      default:
    	break;
    }
  }
  
  return ret;
}

static long WindowMessage(int *draw_modus, int *base_dpi)
{
  struct IntuiMessage *msg;
  long gnr;
  long ret = 0;

  while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)) != NULL) {
    switch (msg->Class) {
	case CLOSEWINDOW:
		ret = 10;
		break;
	case MOUSEBUTTONS:
		if (msg->Code == MENUDOWN) {
		  ;
		}
		else {
		  if (msg->Code == SELECTDOWN) {
		    ;
		  }
		}
		break;
	case GADGETUP:
		gnr = ((struct Gadget *)(msg->IAddress))->GadgetID;
		if (gnr == NR_TOICON_GAD) {
		  ret = 3;
		}
		else {
		  set_picture_draw_modus(gnr, draw_modus, base_dpi);
		}
		break;
	case REFRESHWINDOW:
		DisplayText();
		DrawWin();
		refresh_draw_modus(*draw_modus, *base_dpi);
		break;
	case RAWKEY:
		ret = keys(msg);
		break;
	default:
		pline("*** unknown message (%d)\n",msg->Class);
		ret = 10;
    }
    ReplyMsg(&(msg->ExecMessage));
  }
  return ret;
}


static void set_picture_draw_modus(long nr, int *draw_modus, int *base_dpi)
{
  struct RastPort *rp = win->RPort;

  Move(rp, 20, START_PRINTING + win_title_height - 10 -2);
  switch(nr) {
	case NR_MEM_GAD:
		Text(rp,"Transfer picture in memory                   ",45);
		*draw_modus = DRAW_IN_MEM;
		break;
	case NR_FILE_GAD:
		Text(rp,"Transfer picture in a file                   ",45);
		*draw_modus = DRAW_FILE;
		break;
	case NR_MEM_B_GAD:
		Text(rp,"Transfer picture in memory (draw with border)",45);
		*draw_modus = DRAW_IN_MEM_B;
		break;
	case NR_FILE_B_GAD:
		Text(rp,"Transfer picture in a file (draw with border)",45);
		*draw_modus = DRAW_FILE_B;
		break;
	case NR_BORDER_GAD:
		Text(rp,"Draw only a border                           ",45);
		*draw_modus = DRAW_BORDER;
		break;
	case NR_RECT_GAD:
		Text(rp,"Draw only a filled rectangle                 ",45);
		*draw_modus = DRAW_RECT;
		break;
	case NR_INT_GAD:
		*base_dpi = ((struct StringInfo *)(Bdpi_Gad.SpecialInfo))->LongInt;
		pline("Set base dpi to %d",*base_dpi);
		break;
	default:
		pline("Unknown Gadget %d!\n",nr);
  }
}



static void refresh_draw_modus(int draw_modus, int base_dpi)
{
  struct RastPort *rp = win->RPort;
  struct StringInfo *si;
  char *iBuf, *iuBuf;

  if (win == NULL) return;

  rp = win->RPort;

  Move(rp, 20, START_PRINTING + win_title_height - 10 -2);
  switch(draw_modus) {
	case DRAW_IN_MEM:
		Text(rp,"Transfer picture in memory                   ",45);
		break;
	case DRAW_FILE:
		Text(rp,"Transfer picture in a file                   ",45);
		break;
	case DRAW_IN_MEM_B:
		Text(rp,"Transfer picture in memory (draw with border)",45);
		break;
	case DRAW_FILE_B:
		Text(rp,"Transfer picture in a file (draw with border)",45);
		break;
	case DRAW_BORDER:
		Text(rp,"Draw only a border                           ",45);
		break;
	case DRAW_RECT:
		Text(rp,"Draw only a filled rectangle                 ",45);
		break;
	default:
		pline("*** Unknown draw modus %d!\n",draw_modus);
		break;
  }

  si = (struct StringInfo *)Bdpi_Gad.SpecialInfo;
  iBuf = (char *)si->Buffer;
  iuBuf = (char *)si->UndoBuffer;
  sprintf(iBuf,"%d",base_dpi);
  sprintf(iuBuf,"%d",base_dpi);
  si->LongInt = (long)base_dpi;

  RefreshGadgets(&Bdpi_Gad, win, NULL);
}


static void init_text (void)
{
  struct scroll_text *entry, *entry2, *first_entry;
  char *block;
  int i;

  block = malloc(NR_TEXT_LINES * (LINE_LENGTH+1) * sizeof(char));
  if (block == NULL) {
    Fatal(NO_MEMORY);
  }

  memset(block,0,NR_TEXT_LINES * (LINE_LENGTH+1) * sizeof(char));
  
  first_entry = entry2 = NULL;

  for (i=0; i<NR_TEXT_LINES; i++) {
    if ((entry = malloc(sizeof(struct scroll_text))) == NULL) {
      Fatal(NO_MEMORY);
    }
    entry->is_first = FALSE;
    entry->is_last = FALSE;
    entry->next_line = entry2;
    if (entry2 != NULL) {
      entry2->prev_line = entry;
    }
    entry->line = block;
    block += LINE_LENGTH+1;
    entry2 = entry;
    if (i == 0) {
      first_entry = entry;
    }
  }
  first_entry->next_line = entry2;
  entry2->prev_line = first_entry;
  swin.top = swin.first_free = first_entry;
  swin.number = 0;
  swin.displayed = 0;
}


void pline(char *format,...)
{
  va_list argptr;
  char maxline[5*LINE_LENGTH+1];		/* about 500 bytes stack! */
  char *ptr;
  int i, j, len;
  
  va_start(argptr, format);
  vsprintf(maxline, format, argptr);
  va_end(argptr);

  len = strlen(maxline);
  if (len >5*LINE_LENGTH+1) {
    Fatal(LINE_TO_LONG);		/* trashing the stack !! */
  }

  if (len > display_len) {
    strncpy(swin.first_free->line,maxline,display_len);
    if (swin.first_free->is_first) {
      swin.first_free->is_first = FALSE;
      swin.first_free->next_line->is_first = TRUE;
    }
    if (swin.first_free->prev_line->is_last) {
      swin.first_free->prev_line->is_last = FALSE;
      swin.first_free->is_last = TRUE;
    }
    swin.first_free = swin.first_free->next_line;
    swin.displayed ++;
    if (swin.displayed > lines_to_show) {
      swin.top = swin.top->next_line;
      swin.displayed --;
    }
    swin.number++;
    DisplayText();
    len -= display_len;
    ptr = maxline + display_len;
    for (i=0; i < len / (display_len-1)+1; i++) {
      *swin.first_free->line = '+';
      strncpy(swin.first_free->line+1,ptr,display_len-1);
      for (j=strlen(swin.first_free->line); j<LINE_LENGTH; j++) {
        swin.first_free->line[j] = ' ';
      }
      swin.first_free->line[LINE_LENGTH] = '\0';
      ptr += display_len - 1;
      if (swin.first_free->is_first) {
        swin.first_free->is_first = FALSE;
        swin.first_free->next_line->is_first = TRUE;
      }
      if (swin.first_free->prev_line->is_last) {
        swin.first_free->prev_line->is_last = FALSE;
        swin.first_free->is_last = TRUE;
      }
      swin.first_free = swin.first_free->next_line;
      swin.displayed ++;
      if (swin.displayed > lines_to_show) {
        swin.top = swin.top->next_line;
        swin.displayed --;
      }
      swin.number++;
      DisplayText();
    }
  }
  else {
    for (i=len; i<LINE_LENGTH; i++) {
      maxline[i] = ' ';
    }
    maxline[LINE_LENGTH] = '\0';
    strcpy(swin.first_free->line,maxline);
    if (swin.first_free->is_first) {
      swin.first_free->is_first = FALSE;
      swin.first_free->next_line->is_first = TRUE;
    }
    if (swin.first_free->prev_line->is_last) {
      swin.first_free->prev_line->is_last = FALSE;
      swin.first_free->is_last = TRUE;
    }
    swin.first_free = swin.first_free->next_line;
    swin.displayed ++;
    if (swin.displayed >= lines_to_show) {
      swin.top = swin.top->next_line;
      swin.displayed --;
    }
    swin.number++;
    DisplayText();
  }
}


static void ScrollUp(void)
{
  if (swin.number > swin.displayed && !swin.top->is_first) {
    swin.top = swin.top->prev_line;
    DisplayText();
  }
}

static void ScrollDown(void)
{
  struct scroll_text *entry;
  int i;

  entry = swin.top;
  for (entry = swin.top, i=0; !entry->is_last && i<lines_to_show; i++, entry=entry->next_line);

  if (i == lines_to_show) {
    swin.top = swin.top->next_line;
    DisplayText();
  }
}



static void DisplayText(void)
{
  struct RastPort *rp;
  int i, len, more;
  long x, y;
  struct scroll_text *entry;
  long start = START_PRINTING + win_title_height - 10;

  if (win == NULL) return;

  rp = win->RPort;

  display_len = (win->Width-21) / width_char;
  lines_to_show = (win->Height-3-start) / height_char;

  more = lines_to_show - swin.displayed;
  if (more >= 0) {
    if (swin.displayed + more > swin.number) {
      more = swin.number - swin.displayed;
    }
    for (i=0; i<more && !swin.top->is_first; i++) {
      swin.top = swin.top->prev_line;
    }
    swin.displayed += more;
  }
  else {
    for (i=0; i>more && !swin.top->is_last; i--) {
      swin.top = swin.top->next_line;
    }
    swin.displayed += more;
  }

  x = 5;
  y = start+height_char;;

  entry = swin.top;
  for (i=0; i<lines_to_show; i++) {
    if (entry == swin.first_free) {
      break;
    }
    len = strlen(entry->line);
    if (len > 0) {
      if (len > display_len) {
        len = display_len;
      }
      Move(rp,x,y);
      Text(rp,entry->line,len);
    }
    y += height_char;
    entry = entry->next_line;
  }

  if (swin.number > NR_TEXT_LINES) {
    swin.number = NR_TEXT_LINES;
  }
}


void main(int argc, char *argv[])
{
  UBYTE sig_win, sig_icon;
  ULONG sig_mask, sig_mask_win, sig_mask_icon, sig_ret, sig_port;
  long ret = 0;
  int draw_modus, base_dpi;
  int is_icon;
  long old_mics = 0, old_sec = 0;

  ifffile = NULL;
  bmap = NULL;
  is_icon = FALSE;

  icon = NULL;
  win  = NULL;

  win_x_pos  = WIN_X_KOO;
  win_y_pos  = WIN_Y_KOO;
  win_width  = WIN_WIDTH;
  win_height = WIN_HEIGHT;
  icon_x_pos = ICON_LEFT_EDGE;
  icon_y_pos = ICON_TOP_EDGE;

  OpenLib();
  OpenTopaz();

  if (!get_wb_screen_data(&win_title_height)) {
    win_title_height = 10;
  }
  if (win_title_height != 10) {
    short help = win_title_height - 10;

    Memory_Gad.TopEdge	+= help;
    File_Gad.TopEdge	+= help;
    Memory_B_Gad.TopEdge+= help;
    File_B_Gad.TopEdge	+= help;
    Border_Gad.TopEdge	+= help;
    Rect_Gad.TopEdge	+= help;
    Bdpi_Gad.TopEdge	+= help;
    toIcon_Gad.TopEdge	+= help;
  }

  sig_win = OpenWin();
  DrawWin();
  sig_mask_win = 1 << sig_win;
  
  install_special_port(&special_port);
  sig_port = 1 << special_port->mp_SigBit;

  init_text();

  display_len = 55;
  lines_to_show = 7;

  height_char = HEIGHT_CHAR;	/* depents on used font */
  width_char = WIDTH_CHAR;

  base_dpi = 100;		/* 100 pixel per inch is the default! */
  draw_modus = DRAW_BORDER;	/* draw only a border is the default! */

  refresh_draw_modus(draw_modus, base_dpi);

  pline("SpecialHost Version %s, last compiled: %s",VERSION,__DATE__);

  swin.top->is_first = TRUE;	/* importand! Initialisation after first pline	*/
  swin.top->is_last = TRUE;	/* ^^^^^^^^^^					*/

  pline("© Copyright 1990 Georg Heßmann. All Rights Reserved.");  
  pline("");

  pline("Choose first the draw mode and the base dpi ...");

  sig_mask = sig_mask_win | SIGBREAKF_CTRL_C | sig_port;

  /* now no IO!! (endcli closes the shell-window) */
  if (_Backstdout) {
    Close(_Backstdout);
    _Backstdout = NULL;
  }
  fclose(stderr);

  do {
    sig_ret = Wait(sig_mask);

    /* *** Intui Message *** */
    if (sig_ret & sig_mask_win) {
      ret = WindowMessage(&draw_modus, &base_dpi);
      if (ret == 3) {
        is_icon = TRUE;
        ret = 0;
        CloseWin();
        sig_icon = OpenIcon();
	sig_mask_icon = 1 << sig_icon;
	sig_win = 0;
	sig_mask_win = 0L;
	sig_mask = sig_mask_icon | SIGBREAKF_CTRL_C | sig_port;
      }
    }
    if (sig_ret & sig_mask_icon) {
      struct IntuiMessage *imess;

      while (is_icon && ((imess = (struct IntuiMessage *)GetMsg(icon->UserPort)) != NULL)) {
	if (DoubleClick(old_sec, old_mics, imess->Seconds, imess->Micros)) {
	  ReplyMsg(&(imess->ExecMessage));
	  while((imess = (struct IntuiMessage *)GetMsg(icon->UserPort)) != NULL) {
	    ReplyMsg(&(imess->ExecMessage));	/* clear message port */
	  }
	  is_icon = FALSE;
	  CloseIcon();
	  sig_win = OpenWin();
	  DrawWin();
	  sig_mask_win = 1 << sig_win;
	  sig_icon = 0;
	  sig_mask_icon = 0L;
	  sig_mask = sig_mask_win | SIGBREAKF_CTRL_C | sig_port;
	}
	else {
	  old_sec = imess->Seconds;
	  old_mics = imess->Micros;
	  ReplyMsg(&(imess->ExecMessage));
	}
      }
    }

    /* *** Message from DVI-driver *** */
    if (sig_ret & sig_port) {
      ret = work_with_special(draw_modus, base_dpi);
    }

  } while (ret == 0 && !(sig_ret & SIGBREAKF_CTRL_C));

  close_all();
}
