/*
 *  Copyright (c) 1992, 1993 John E. Davis  (davis@amy.tch.harvard.edu)
 *  All Rights Reserved.
 */
#include <stdio.h>
#ifdef msdos
#include <alloc.h>
#endif

#include "config.h"
#include "buffer.h"
#include "window.h"
#include "screen.h"
#include "misc.h"
#include "ledit.h"
#include "sysdep.h"

Window_Type *Window;
extern Window_Type *The_MiniWindow;

Window_Type *create_window(int top, int rows, int col, int width)
{
    Window_Type *w;

    if (NULL == (w = (Window_Type *) MALLOC(sizeof(Window_Type))))
      {
	  exit_error("create_window: malloc error.");
      }

    w->rows = rows;
    w->column = col;
    w->top = top;
    w->width = width;
    w->next = NULL;
    w->buffer = NULL;
    w->mark.line = NULL;
    w->mark.point = 0;
   w->mark.n = 0;
    w->mark.next = NULL;
    w->beg.line = NULL;
    w->beg.point = 0;
    w->beg.next = NULL;
    return(w);
}

void window_buffer(Buffer *b)
{
   if (Window == NULL)
     {
	Window = create_window(1, Screen_Height - 2, 1, Screen_Width);
	Window->next = Window;
     }

   touch_window();
   Window->mark.line = b->line;
   Window->mark.point = b->point;
   Window->mark.n = b->linenum + b->nup;
   Window->beg.line = b->line;
   Window->beg.point = b->point;
   Window->buffer = b;
   Window->trashed = 1;
}

int other_window()
{
   switch_to_buffer(Window->buffer);
   /* CBuf->line = CLine;
   CBuf->point = Point; */
   Window->mark.point = Point;
   Window->mark.line = CLine;
   Window->mark.n = LineNum + CBuf->nup;
   /* Window->buffer = CBuf; */

   Window = Window->next;
   switch_to_buffer(Window->buffer);
   /* CBuf = Window->buffer; */
   Point = Window->mark.point;
   CLine = Window->mark.line;
   LineNum = Window->mark.n - CBuf->nup;
   return(1);
}

int find_screen_line(void)
{
   int i;
   for (i = 0; i < Screen_Height - 2; i++)
     {
	if (Screen[i].line == CLine) return(i + 1);
     }
   return(0);
}

int split_window()
{
    int n, top, width, row;
    Window_Type *w, *neew;
   Line *l;

    if (Window->rows < 5)
      {
	  msg_error("Window too small.");
	  return(0);
      }

   switch_to_buffer(Window->buffer);
    n = Window->rows / 2;
    top = Window->top + n + 1;
    width = Window->width;
    n = Window->rows - n - 1;
    Window->rows = Window->rows / 2;

    Window->beg.line = find_top();
    w = Window->next;
    Window->next = neew = create_window(top, n, Window->column, width);

   neew->next = w;
   neew->buffer = CBuf;
   neew->mark.point = Point;
   neew->mark.line = CLine;
   neew->mark.n = LineNum + CBuf->nup;

    other_window();
    touch_window();
   l = Window->beg.line = find_top();
   n = 0;
   while (l != CLine) 
     {
	l = l->next;
	n++;
     }
   Window->beg.n = LineNum + CBuf->nup - n;
   
   /* Try to leave Point on same line of display if possible */
   if ((row = find_screen_line()) > 0)
     {
	w = Window;
	do
	  {
	     if ((Window->buffer == CBuf) && (Window->top <= row)
		 && (Window->top + Window->rows > row)) break;
	     other_window();
	  }
	while (w != Window);
     }

    return(1);
}

int one_window()
{
    Window_Type *w, *next, *mini;

    mini = NULL;
    if (Window->top == Screen_Height) return(0);  /* mini-buffer */
    w = Window->next;
    while(w != Window)
      {
	  next = w->next;
	  if (w != The_MiniWindow) FREE(w); else mini = w;
	  w = next;
      }
    if (mini == NULL) mini = Window;
    Window->next = mini;
    mini->next = Window;
    Window->top = 1;
    Window->rows = Screen_Height - 2;
    touch_window();
    return(1);
}

int enlarge_window()
{
   Window_Type *w, *w1;
   int min = 2;

   if (Window == The_MiniWindow) return(0);
   /* if (IS_MINIBUFFER) return(0); */
   if (Window == Window->next) return(0);
   w = Window->next;
   while(w->rows <= min) w = w->next;
   if (w == Window) return(0);

   if (w->top < Window->top)
     {
	w->rows -= 1;
	Window->rows += 1;
	do
	  {
	     w = w->next;
	     w->top -= 1;
	  }
	while (w != Window);
     }
   else
     {
	Window->rows += 1;
	w1 = Window;
	while(w1 != w)
	  {
	     w1 = w1->next;
	     w1->top += 1;
	  }
	w->rows -= 1;
     }
   w = Window;
   do
     {
	touch_window();
	Window = Window->next;
     }
   while (w != Window);
   return(1);
}

void adjust_windows(int height)
{
   Window_Type *w = Window;
   int rows;

   do
     {
	if (w->rows + w->top + 1 == Screen_Height)
	  {
	     rows = height - 1 - w->top;
	     if (rows > 1)
	       {
		  w->rows = rows;
		  return;
	       }
	     while(Window->top != 1) other_window();
	     one_window();
	     Window->rows = height - 2;
	     return;
	  }
	w = w->next;
     }
   while (w != Window);
   /* not reached! */
}

void change_screen_size(int width, int height)
{
   Window_Type *w;

   if (Window == NULL) return;

   if (height != Screen_Height)
     {
	adjust_windows(height);
     }
   reset_display();
   Screen_Width = width;
   Screen_Height = height;
   init_display(0);
   w = Window;
   do
     {
	Window->width = width;

	/* touch_window(); */
	Window = Window->next;
     }
   while(w != Window);
   if (The_MiniWindow != NULL)
     {
	The_MiniWindow->top = height;
	The_MiniWindow->width = width;
     }
   /* cls();
   update((Line*) NULL); */
   redraw();
}

Window_Type *buffer_visible(Buffer *b)
{
   Window_Type *w = Window;

   do
     {
	if (w->buffer == b) return(w);
	w = w->next;
     }
   while (w != Window);
   return(NULL);
}

int delete_window()
{
   Window_Type *tthis, *prev, *next;
   int nr1;
   
   tthis = Window;
   next = tthis->next;
   if ((MiniBuffer_Active && ((tthis == The_MiniWindow) || (tthis == next->next)))
       || (tthis == next)) return(0);
   
   
   
   nr1 = tthis->top + tthis->rows + 1;
   if (nr1 != Screen_Height)
     {
	while (Window->top != nr1) other_window();
	Window->top = tthis->top;
     }
   else
     {
	while(Window->top + Window->rows + 1 != tthis->top) other_window();
     }
   
   Window->rows += tthis->rows + 1;
   touch_window();
   
   prev = next;
   while(prev->next != tthis) prev = prev->next;
   prev->next = next;

   FREE(tthis);
   return(1);
}
