/* Time-stamp: <97/01/24 15:32:02 john> */
/* table.c --
# Purpose: Output grid as table; also contains the routines for outputting a single entry (as done within each table cell).
 */

#include <stdio.h>
#include "attr.h"
#include "grid.h"
#include "style.h"
#include "anchor.h"
#include "graphics.h"
#include "edit.h"
#include "table.h"

/* Print an attribute of an entry, labelled with what it is */

void print_attr_if_present(struct entry *entry,
			   char *title,
			   char *key,
			   char *format)
{
  char *val = get_attr(entry, key);

  if ((val != NULL) && (val[0] != '\0'))
    {
      printf(format, title, val);
    }
}

/*  Return a query_encoded version of the given string, allocated with malloc
 */

char *to_query_encoded(char *in)
{
  char *out = (char*)malloc(strlen(in)+1);
  int i;
  if (out == NULL) return NULL;

  for (i = 0;
       in[i] != '\0';
       i++)
    {
      char c = in[i];
      if (c == ' ') c = '+';

      out[i]=c;
    }

  out[i] = in[i];

  return out;
}

char *to_label(char *in)
{
  char *temp = as_label(in);
  char *result = (char*)malloc(strlen(temp)+1);

  if (result == NULL) return NULL;
  strcpy(result, temp);
  return result;
}

/* Output the link for zooming to this entry. The visible markup passed
   in, to go inside the anchor, may be a graphic or text (or both).
 */

static void output_zoom(struct entry *entry,
			char *visible,
			char *page_type,
			char *page_name,			
			struct style *style)
{
  if ((strcmp(entry->type, "road") != 0) &&
      (strcmp(entry->type, "junction") != 0))
    {
      char *qe = to_query_encoded(entry->name);
      if (qe != NULL)
	{
	  link_in_style("getplan.cgi",
			page_type,
			page_name,
			style,
			visible,
			NULL,
			"zoom", qe);
	  Free(qe);
	}
    }
}

/* Select the graphic, if any, for this entry, as specified in
   graphics.attr, and output it, making it an anchor for zooming to
   the entry if appropriate. See ../doc/tech/graphics.html for details.
 */

static void output_graphic(struct entry *entry,
			   char *page_type,
			   char *page_name,
			   struct style *style)
{
  char graphics_buf[1024];
  char *graphic;
 if (!style->graphics) return;

  graphic = get_graphic(entry, "graphic", style);

  if (graphic == NULL)
    {
      return;
    } 
    
  if (strlen(graphic) > 200)
    {
      if (style->debug)
	{
	  printf("<code>Ridiculously long graphic name!</code>\n");
	}
      return;
    }

  sprintf(graphics_buf,
	  "<img%s border=\"0\" src=\"../graphics/%s.gif\">",
	  ((entry->column == 0) ?
	   "" : ((entry->column < 0) ?
		 " align=\"right\"" :
		 " align=\"left\"")),
	  graphic);

  if (!style->detail)
    {
      output_zoom(entry, graphics_buf, page_type, page_name, style);
    } else {
      fputs(graphics_buf, stdout);
    }
  putchar('\n');
}

static int pictures_found = 0;

/* Output one entry; this will normally be inside a table cell.
   Lots of the style parameters are handled here.
 */

void output_entry(char *page_type,
		  char *page_name,
		  struct entry *entry,
		  struct style *style,
		  struct entry *page_entries,
		  char *linked_from,
		  char *zoomed_to)
{
  if ((style->graphics) && 
      (((style->browser_features&BROWSER_HAS_ALIGN)) ||
       (entry->column > 0)))
    {
      output_graphic(entry, page_type, page_name, style);
    }

  if ((!style->detail) && (entry->column < 0) && (zoomed_to==NULL))
    {
      /* might move this inside the printing of the graphic, so the */
      /* word "zoom" is not displayed if the picture is */
      output_zoom(entry, "[zoom]", page_type, page_name, style);
    }
  
  if ((!style->graphics) || (entry->column != 0))
    {
      output_with_link(entry->name,
		       style,
		       entry,
		       linked_from);
    }

#if 1
  if (style->debug)
    {
      struct attribute *attr;
      printf("<pre>");
#if 1
      printf("Entry \"%s\" of type \"%s\",\nin column %d,\n%d wide and %d high",
	     entry->name, entry->type, entry->column,
	     entry->width, entry->height);
      output_attributes(entry, 1);
#endif
      printf("\n</pre>\n");
    }
#endif

  print_attr_if_present(entry, "#", "number", "%s%s");

  {
    char *picture = get_attr(entry, "picture");
    if (style->pictures & (picture != NULL))
      {
	char *home_page = get_attr(entry, "home-page");
	printf("<br>");
	if (home_page != NULL)
	  {
	    printf("<a href=\"%s\">", home_page);
	  }
	printf("<img src=\"%s\">", picture);
	if (home_page != NULL)
	  {
	    printf("</a>");
	  }
	printf("<br>\n");
	pictures_found++;
      }
  }

  if (style->extra)
    {
      fetch_inclusions(entry, style);

      output_with_substitutions(style->extra,
				entry, page_entries,
				page_type, page_name,
				style, "{}");
    }

  if (style->detail)
    {
      char *description;
      char use_sub_tables = style->browser_features & BROWSER_RECURSIVE_TABLES;
      char *detail_format = use_sub_tables ?
	"  <tr><th align=\"right\">%s</th><td align=\"left\">%s</td></tr>" :
	  "%s: %s<br>\n";

      fetch_inclusions(entry, style);

      if (use_sub_tables)
	{
	  printf("<table>\n");
	} else {
	  printf("<br>");
	}
      print_attr_if_present(entry, "Type", "type", detail_format);
      print_attr_if_present(entry, "Kind: ", "kind", detail_format);
      print_attr_if_present(entry, "Opening times: ", "opening-times", detail_format);
      print_attr_if_present(entry, "Provides: ", "provides", detail_format);
      print_attr_if_present(entry, "Review", "review", "%s: <a href=\"%s\">review</a><br>");
      if (use_sub_tables)
	{
	  printf("</table>\n");
	}

      description = get_attr(entry, "description");

      if (description != NULL)
	{
	  char c;
	  printf("\n<h2>Description</h2>\n");
	  while ((c = *description++) != '\0')
	    {
	      putchar(c);
	    }
	  printf("\n<!-- end of description -->\n\n");
	}
      
      
    } else {
      if ((!style->detail) && (entry->column >= 0) && (zoomed_to==NULL))
	{
	  output_zoom(entry, "[zoom]", page_type, page_name, style);
	}
    }

  if ((strcmp(entry->type, "dummy") == 0) && !style->hide_edit)
    {
      char *qe = to_query_encoded(entry->name);
      if (qe == NULL) qe = "unknown";
      printf("<p><a href=\"#zippy\">Random</a> dummy -- please ");
      if (style->edit)
	{
	  printf("edit");
	} else {
	  char *entry_query = to_query_encoded(entry->name);
	  char *page_query = to_label(page_name);
	  if ((entry_query != NULL) && (page_query != NULL))
	    {
	      Link_In_Other_Style("getplan.cgi", page_type, page_query,
				  style,
				  int, edit, 1, "edit",
				  "zoom", entry_query);
	      free(entry_query);
	      free(page_query);
	    }
	}
      printf("!</p>\n");
    }

  if ((style->edit) && !style->hide_edit)
    {
      make_edit(entry, style, zoomed_to);
    } else {
      if ((style->all_edit_links) && (!style->hide_edit) && (zoomed_to == NULL))
	{
	  char *entry_query = to_query_encoded(entry->name);
	  char *page_query = to_label(page_name);
	  if ((entry_query != NULL) && (page_query != NULL))
	    {
	      Link_In_Other_Style("getplan.cgi", page_type, page_query,
				  style,
				  int, edit, 1, " [edit]",
				  "zoom", entry_query);
	      free(page_query);
	      free(entry_query);
	    }
	}
    }

  if ((style->graphics) && 
      ((!(style->browser_features&BROWSER_HAS_ALIGN))) &&
      (entry->column < 0))
    {
      output_graphic(entry, page_type, page_name, style);
    }
    
}

/* Takes a grid as produced by entries_to_grid or
   make_area_layout_grid, and output it as an HTML table.
 */

void output_grid_as_table(struct grid *grid,
			  struct style *style)
{
  struct row *row;
  int this_row_index;
  char *spine_name = grid->central_entry->name;
  char spine_name_buf[512];

  pictures_found = 0;

  if ((spine_name != NULL) && (strlen(spine_name) < 500))
    {
      int i;
      char c;
      for (i = 0;
	   (c = spine_name[i]) != '\0';
	   i++)
	{
	  if (i > 100) break;
	  if (('a' <= c) && (c <= 'z'))
	    {
	      spine_name_buf[i] = c;
	    } else if (('A' <= c) && (c <= 'Z'))
	      {
		spine_name_buf[i] = c + ('a' - 'A');
	      } else {
		spine_name_buf[i] = '-';
	      }
	}
      spine_name_buf[i] = '\0';
      spine_name = spine_name_buf;
    }

  /* If we're using graphics, and we can colour cell backgrounds, we
     don't need to draw borders. Perhaps this condition should be or? */

  printf("<center>\n<table%s>\n",
	 (((style->graphics) &&
	   (style->browser_features & BROWSER_CELL_COLOURS)) ?
	  " cellpadding=\"0\" cellspacing=\"0\"" :
	  " border"));

  if (style->debug)
    {
      int i;
      printf("  <tr><td></td>");
      for (i = grid->min_rank;
	   i <= grid->max_rank;
	   i++)
	{
	  printf("\n    <td>%d</td>", i);
	}
      printf("</tr>\n");
    }

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

      int i;

      printf(" <tr>\n");

      if (style->debug)
	{
	  printf("    <td>%d</td>\n", this_row_index);
	}

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

	  if ((cell != NULL) &&
	      (cell->entry != NULL))
	    {
	      struct entry *entry = cell->entry;
	      char *property;

	      if ((cell->x_into == 0) && (cell->y_into == 0))
		{
		  printf("    <td align=\"%s\"",
			 (((i == 0) ||
			   (strcmp(entry->type, "road")==0)) ? "center" :
			  ((i < 0) ? "right" : "left")));

		  if (entry->width != 1)
		    {
		      printf(" colspan=\"%d\"", entry->width);
		    }

		  if (entry->height != 1)
		    {
		      printf(" rowspan=\"%d\" valign=\"center\"", entry->height);
		    }

		  /* Colour the cell background in, so roads are grey,
		     rivers blue, parks green and so if background
		     pictures are available, they are used instead. */

		  if (style->browser_features & BROWSER_CELL_COLOURS)
		    {
		      property = get_graphic(entry,
					     (entry->height > 1) ?
					     "tallbgpic" :
					     "widebgpic",
					     style);
		      if (property != NULL)
			{
			  printf(" background=\"../graphics/%s.gif\"",
				 property);
			} else {
			  property = get_colour(entry, "rgbhex", style);
			  if (property != NULL)
			    {
			      printf(" bgcolor=\"#%s\"", property);
			    }
			}

		      property = get_graphic(entry, "pixacross", style);
		      if (property != NULL)
			{
			  if (entry->height > 1)
			    {
			      printf(" width=\"%s\"", property);
			    } else {
			      printf(" height=\"%s\"", property);
			    }
			}
		    }

		  printf(">");
		  output_label(cell);

		  /* Output the name of the entry. If it's a road, it
		     may be vertical. */

		  if ((strcmp(entry->type, "road") == 0) &&
		      (((entry->width == 1)
#if 1
			&& ((entry->height > 1)
#if 1
			    || (i == 0)
#endif
			    )
#endif
			)
#if 0
		       || (i == 0)
#endif
		       ))
		    {
		      /* output the name vertically; we don't output
			 the rest of the entry, so it won't get a
			 graphic or anything like that; but it will
			 get the cell colour, as that has already been
			 handled by this stage */
		      char *t;
		      char c;
		      char buf[2];

		      buf[1] = '\0';

		      for (t = entry->name, c = *t;
			   c != '\0';
			   c = *++t)
			{
			  buf[0] = c;
			  output_with_link(buf,
					   style,
					   entry,
					   spine_name);
			  printf("<br>");
			}
		    } else {
		      /* output the name horizontally, as part of
			 outputting all the rest of the entry */
		      output_entry(grid->page_type,
				   grid->page_name,
				   entry,
				   style,
				   grid->central_entry,
				   ((strcmp(entry->type, "road") == 0) ?
				    spine_name : NULL),
				   NULL);
		    }

		  printf("  </td>\n");
		}
	    } else {
	      printf("    <td></td>\n");
	    }
	}
      printf(" </tr>\n");
    }

  printf("</table>\n</center>\n");

  if (style->verbose || style->debug)
    {
      printf("<p>%d picture%s on this page.</p>\n",
	     pictures_found, pictures_found==1 ? "" : "s");
    }

}

/* end of table.c */
