/* Time-stamp: <96/12/23 14:57:27 john> */

/* 
# Purpose: Takes the raw grid from <a href="#make-grid.c">make-grid.c</a> and widens and deepens any cells that cover more than one grid square.
 */

/* 
   Things to do:
   use height attribute to limit how far down an entry can be spread
 */

#include <stdio.h>
#include "attr.h"
#include "grid.h"
#include "spread.h"

/* #define debug 1 */

static struct row *make_empty_row(int left, int right)
{
  int n = 1 + right - left;
  struct row *row = (struct row*)malloc(sizeof(struct row));
  struct cell **array;
  int i;
  if (row == NULL) return NULL;
  array = (struct cell**)malloc(n * sizeof(struct cell*));
  if (array == NULL) { Free(row); return NULL; }
  row->next = NULL;
  row->row_number = 0;
  row->cell_list = NULL;
  row->cells = array;
  row->min_rank = left;
  row->max_rank = right;
  row->phys_y = 0;
  for (i = 0; i < n; i++) array[i] = NULL;
  return row;
}

int extend_end_roads(struct grid *grid)
{
  int left = grid->min_rank;
  int right = grid->max_rank;
  struct cell *top_cell = cell_yx(grid, 0, 0);
  struct cell *bottom_cell = cell_yx(grid, grid->n_rows - 1, 0);
  int extend_top_by = 0;
  int extend_bottom_by = 0;
  struct row **new_rows_array;
  struct row **old_rows_array = grid->rows;
  int count;
  int index = 0;

  if (top_cell == NULL)
    {
#ifdef debug
      printf("no top entry\n");
#endif
    } else {
#ifdef debug
      printf("Top entry is %s\n", top_cell->entry->name);
#endif
      if (strcmp(get_attr(top_cell->entry, "type"), "road") == 0)
	extend_top_by = top_cell->title_width;
    }

  if (bottom_cell == NULL)
    {
#ifdef debug
      printf("no bottom entry\n");
#endif
    } else {
#ifdef debug
      printf("Bottom entry is %s\n", bottom_cell->entry->name);
#endif
      if (strcmp(get_attr(bottom_cell->entry, "type"), "road") == 0)
	extend_bottom_by = bottom_cell->title_width;
    }

  new_rows_array = (struct row**)malloc((extend_top_by + extend_bottom_by + grid->n_rows) * sizeof(struct row*));
  if (new_rows_array == NULL) return NULL;

  for (count = 0; count < extend_top_by; count++)
    new_rows_array[index++] = make_empty_row(left, right);

  for (count = 0; count < grid->n_rows; count++)
    new_rows_array[index++] = old_rows_array[count];

  for (count = 0; count < extend_bottom_by; count++)
    new_rows_array[index++] = make_empty_row(left, right);
  
  for (count = 0; count < extend_top_by + grid->n_rows + extend_bottom_by; count++)
    {
      if (new_rows_array[count] == NULL)
	{
	  printf("NULL row at %d\n", index);
	}
      new_rows_array[count]->row_number = count;
    }
  
  grid->rows = new_rows_array;
  grid->n_rows += extend_top_by;
  grid->n_rows += extend_bottom_by;

  if (extend_top_by != 0)
    {
      cell_yx_raw(grid, 0, 0) = cell_yx_raw(grid, extend_top_by, 0);
      cell_yx_raw(grid, 0, 0)->entry->height=extend_top_by;
      cell_yx_raw(grid, extend_top_by, 0) = NULL;
    }

  if (extend_bottom_by != 0)
    {
      bottom_cell->entry->height = extend_bottom_by;
    }

  return 1;
}

int spread_across(struct grid *grid)
{
  struct row *row = grid->row_list;

  while (row != NULL)
    {
      int i;

      for (i = row->min_rank;
	   i <= row->max_rank;
	   i++)
	{
	  struct cell *cell = cell_n(row, i);

	  if ((cell != NULL) &&
	      (cell->entry->width > 1) &&
	      (cell->x_into == 0))
	    {
	      int n = cell->entry->width - 1;
	      int j;
#ifdef debug
	      printf("Spreading %s across from %d to %d\n",
		     cell->entry->name, i, i+n);
#endif
	      for (j = 1;
		   j <= n;
		   j++)
		{
		
		  struct cell *new_cell = (struct cell*)malloc(sizeof(struct cell));

		  if (new_cell == NULL)
		    return 0;
		  cell_n(row, i+j) = new_cell;

		  new_cell->next = row->cell_list;
		  row->cell_list = new_cell;
		  new_cell->entry = cell->entry;
		  new_cell->x_into = j;
		  new_cell->y_into = 0;
		  new_cell->cell_text = NULL;
		  new_cell->title_width = 0;
		  new_cell->phys_width = 1;
		  new_cell->phys_height = 1;
		}
	
	    }
	}

      row = row->next;
    }

  return 1;
}

int complete_rectangle(struct grid *grid)
{
  int left = grid->min_rank;
  int right = grid->max_rank;
  int width = (right - left)+1;
  struct row *this_row = grid->row_list;

  while (this_row != NULL)
    {
      int this_left = this_row->min_rank;
      int this_right = this_row->max_rank;

      if ((this_left > left) || (this_right < right))
	{
	  struct cell **old_cells = this_row->cells;
	  struct cell **new_cells = (struct cell **)malloc(width * sizeof(struct cell*));
	  int i;
	  int delta = this_left - left;
	  if (new_cells == NULL)
	    {
	      return 0;
	    }

	  for (i = 0; i < width; i++) new_cells[i] = (struct cell*)NULL;

	  for (i = this_left;
	       i <= this_right;
	       i++)
	    {
	      struct cell *cell = cell_n(this_row, i);
	      new_cells[delta+(i-this_left)] = cell;
	    }
	  this_row->cells = new_cells;
	  Free(old_cells);
	  this_row->min_rank = left;
	  this_row->max_rank = right;
	}
      this_row = this_row->next;
    }
  return 1;
}

int spread_down(struct grid *grid)
{
  struct row *prev_row = grid->rows[0];
  int this_row_index;

  for (this_row_index = 1;
       this_row_index < grid->n_rows;
       this_row_index++)
    {
      struct row *this_row=grid->rows[this_row_index];
      int column;
#ifdef debug
      printf("Spreading down into row %d from above\n", this_row_index);
#endif
      for (column = this_row->min_rank;
	   column < this_row->max_rank;
	   column++)
	{
	  struct cell *cell = cell_n(this_row, column);
	  if (cell == NULL)
	    {
	      struct cell *above = cell_n(prev_row, column);
#ifdef debug
	      printf("  [%d,%d] is empty\n", this_row_index, column);
#endif
	      if (above != NULL)
		{
#ifdef debug
		  printf("  There is one above it, called %s\n", above->entry->name);
#endif
		  if (((strcmp(above->entry->type, "road") != 0) ||
		       (above->entry->height > 1) ||
		       (above->entry == grid->central_entry)) &&
		      (above->entry->height < above->entry->max_height))
		    {
		      struct cell *new_cell = (struct cell*)malloc(sizeof(struct cell));
		      if (new_cell == NULL)
			return 0;
#ifdef debug
		      printf("  Want to spread %s to [%d,%d]\n",
			     above->entry->name,
			     this_row_index, column);
#endif
		      cell_n(this_row, column) = new_cell;
		      new_cell->next = this_row->cell_list;
		      this_row->cell_list = new_cell;
		      new_cell->entry = above->entry;
		      above->entry->height++;
		      new_cell->x_into = above->x_into;
		      new_cell->y_into = above->y_into + 1;
		      new_cell->title_width = 0;
		      new_cell->cell_text = NULL;
		      new_cell->phys_width = 1;
		      new_cell->phys_height = 1;
		    }
		}
	    } else {
#ifdef debug
	      printf("  [%d,%d] already occupied by %s\n", this_row_index, column, cell->entry->name);
#endif
	    }
	}
      prev_row = this_row;
    }

  return 1;
}

int multi_line_texts(struct grid *grid)
{
  int this_row_index;

  for (this_row_index = 1;
       this_row_index < grid->n_rows;
       this_row_index++)
    {
      struct row *this_row=grid->rows[this_row_index];

      int i;

      for (i = this_row->min_rank;
	   i <= this_row->max_rank;
	   i++)
	{
	  struct cell *cell = cell_n(this_row, i);
	  if (cell != NULL)
	    {
	      int height_available = cell->entry->height;
	      char *original_text = cell->cell_text;

	      if ((original_text != NULL) &&
		  (original_text == cell->entry->name) &&
		  (height_available > 1))
		{
		  int n_words = 1;
		  char *s = original_text;
		  char *new_text;
		  int words_per_line;
		  int row_to_use = this_row_index;		

		  while (*s != '\0')
		    {
		      if (*s++ == ' ') n_words++;
		    }
		
		  words_per_line = n_words / height_available;
		  if ((words_per_line * height_available) < n_words) words_per_line++;
#ifdef debug
		  printf("Want to split title %s (%d words) to %d lines starting at row %d -- %d words per line\n",
			 original_text, n_words, height_available,
			 row_to_use,
			 words_per_line);
#endif
		  s = original_text;

		  while (*s != '\0')
		    {
		      int this_words = 0;
		      char *t = s;
		      int k;
		      int this_length;
		      while (*t != '\0')
			{
			  if (*t++ == ' ')
			    {
			      if (++this_words >= words_per_line)
				break;
			    }
			}
		      this_length = t - s;
		      new_text = (char*)malloc(1 + this_length);
		      if (new_text == NULL) return 0;
		      for (k = 0; k < this_length; k++) new_text[k] = s[k];
		      new_text[k]='\0';
#ifdef debug
		      printf("New text \"%s\" leaving \"%s\"\n",
			     new_text, t);
#endif
		      cell->cell_text = new_text;
		      cell->title_width = this_length;
		      row_to_use++;
		      cell = cell_yx(grid, row_to_use, i);
#ifdef debug
		      printf("Next one will go in row %d\n");
#endif
		      if (cell == NULL)
			{
			  struct cell* new_cell = (struct cell*)malloc(sizeof(struct cell));
			  if (new_cell == NULL) return 0;
#ifdef debug
			  printf("Making new cell for \"%s\"\n", new_cell);
#endif
			  cell_yx_raw(grid, row_to_use, i) = new_cell;
			  new_cell->next = cell;
			  new_cell->entry = cell->entry;
			  new_cell->x_into = cell->x_into;
			  new_cell->y_into = cell->y_into + 1;
			  new_cell->cell_text = NULL;
			  new_cell->title_width = 0;
			  new_cell->phys_width = 1;
			  new_cell->phys_height = 1;
			  cell = new_cell;
			}
		      s = t;
		    }

		}
	    }
	}
      this_row = this_row->next;
    }
  return 1;
}

int verticalize_texts(struct grid *grid)
{
  int i;
  for (i = 0;
       i < grid->n_rows;
       i++)
    {
      struct cell *cell = cell_yx(grid, i, 0);
      if (cell == NULL)
	{
#ifdef debug
	  printf("Nothing at [%d,0]\n", i);
#endif
	} else {
#ifdef debug
	  printf("Considering verticalizing %s(%s here) w=%d into=%d\n",
		 cell->entry->name,
		 cell->cell_text,
		 cell->entry->width,
		 cell->y_into);
#endif
	}
      if ((cell != NULL) &&
	  (cell->entry->width == 1) &&
	  (cell->y_into == 0))
	{
	  int old_length = cell->title_width;
	  char* old_text = cell->cell_text;
	  char *text_remaining = old_text;
	  char *end_text = old_text+strlen(old_text);
	  int height_available = cell->entry->height;
	  int j;
#ifdef debug
	  printf("Verticalizing %s from %d wide to %d high\n", old_text, old_length, height_available);
#endif
	  if (height_available >= old_length)
	    {
#ifdef debug
	      printf("That's easy, one letter per row\n");
#endif
	      for (j = 0;
		   j < height_available;
		   j++)
		{
		  struct cell *cell_to_fix = cell_yx_raw(grid, i+j, 0);
		  char *new_str = (char*)malloc(2);
		  if (new_str == NULL)
		    return 0;
		  new_str[0]=*text_remaining;
		  new_str[1] = '\0';
		  cell_to_fix->cell_text = new_str;
		  cell_to_fix->title_width = 1;
		  text_remaining++;
		  if (text_remaining >= end_text) break;
		}
	    } else {
	      int per_row = (old_length / height_available) + 1;
#ifdef debug
	      printf("That'll be %d per row, plus a hyphen\n", per_row);
#endif
	      for (j = 0;
		   j < height_available;
		   j++)
		{
		  struct cell *cell_to_fix = cell_yx_raw(grid, i+j, 0);
		  char *new_str = (char*)malloc(per_row+2);
		  if (new_str == NULL)
		    return 0;
		  strncpy(new_str, text_remaining, per_row);
		  new_str[per_row]='-';
		  new_str[per_row+1] = '\0';
		  cell_to_fix->cell_text = new_str;
		  cell_to_fix->title_width = per_row+1;
		  text_remaining += per_row;
		  if (text_remaining >= end_text) break;
		}
	    }
	}
    }
  return 1;
}

int spread(struct grid *grid)
{
 return (complete_rectangle(grid) && spread_across(grid) && spread_down(grid));
}

/* end of spread.c */
