/* float.c -- float environment functions.
   $Id: float.c,v 1.12 2007/07/01 21:20:32 karl Exp $

   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

   Originally written by Alper Ersoy <dirt@gtk.org>.  */

#include "system.h"
#include "makeinfo.h"
#include "cmds.h"
#include "files.h"
#include "float.h"
#include "html.h"
#include "sectioning.h"
#include "xml.h"

static FLOAT_ELT *float_stack = NULL;

void
add_new_float (char *id, char *title, char *shorttitle,
    char *type, char *position)
{
  FLOAT_ELT *new = xmalloc (sizeof (FLOAT_ELT));
  unsigned long num_len;

  new->id = id;
  new->type = type;
  new->title = title;
  new->shorttitle = shorttitle;
  new->position = position;
  new->title_used = 0;
  new->defining_line = line_number - 1;

  new->number = current_chapter_number ();
  /* Append dot if not @unnumbered.  */
  num_len = strlen (new->number);
  if (num_len > 0)
    {
      new->number = xrealloc (new->number, num_len + 1 + 1);
      new->number[num_len] = '.';
      new->number[num_len+1] = '\0';
    }

  { /* Append the current float number.  */
    unsigned len = strlen (new->number) + 21;  /* that's 64 bits */
    char *s = xmalloc (len + 1);

    sprintf (s, "%s%d", new->number,
                count_floats_of_type_in_chapter (text_expansion (type),
                                                 new->number) + 1); 
    free (new->number);
    new->number = xstrdup (s);
  }

  /* Plain text output needs sectioning number and its title,
     when listing floats.  */
  if (!html && !xml && no_headers)
    {
      new->section = current_sectioning_number ();
      if (strlen (new->section) == 0)
        new->section_name = current_sectioning_name ();
      else
        new->section_name = "";
    }

  new->next = float_stack;
  float_stack = new;
}

int
count_floats_of_type_in_chapter (char *type, char *chapter)
{
  int i = 0;
  int l = strlen (chapter);
  FLOAT_ELT *temp = float_stack;

  while (temp && strncmp (temp->number, chapter, l) == 0)
    {
      if (strlen (temp->id) > 0 && STREQ (text_expansion (temp->type), type))
        i++;
      temp = temp->next;
    }

  return i;
}

char *
current_float_title (void)
{
  return float_stack->title;
}

char *
current_float_shorttitle (void)
{
  return float_stack->shorttitle;
}

char *
current_float_type (void)
{
  return float_stack->type;
}

char *
current_float_position (void)
{
  return float_stack->position;
}

char *
current_float_number (void)
{
  return float_stack->number;
}

char *
current_float_id (void)
{
  return float_stack->id;
}

char *
get_float_ref (char *id)
{
  FLOAT_ELT *temp = float_stack;

  while (temp)
    {
      if (STREQ (id, temp->id))
        {
          char *s = xmalloc (strlen (temp->type) + strlen (temp->number) + 2);
          sprintf (s, "%s %s", temp->type, temp->number);
          return s;
        }
      temp = temp->next;
    }

  return NULL;
}

static int
float_type_exists (char *check_type)
{
  /* Check if the requested float_type exists in the floats stack.  */
  FLOAT_ELT *temp;

  for (temp = float_stack; temp; temp = temp->next)
    if (STREQ (temp->type, check_type) && temp->id && *temp->id)
      return 1;

  return 0;
}

void
cm_listoffloats (void)
{
  char *float_type;
  get_rest_of_line (1, &float_type);

  /* get_rest_of_line increments the line number by one,
     so to make warnings/errors point to the correct line,
     we decrement the line_number again.  */
  if (!handling_delayed_writes)
    line_number--;

  if (handling_delayed_writes && !float_type_exists (float_type))
    warning (_("Requested float type `%s' not previously used"), float_type);

  if (xml)
    {
      xml_insert_element_with_attribute (LISTOFFLOATS, START,
          "type=\"%s\"", text_expansion (float_type));
      xml_insert_element (LISTOFFLOATS, END);
    }
  else if (!handling_delayed_writes)
    {
      int command_len = sizeof ("@ ") + strlen (command) + strlen (float_type);
      char *list_command = xmalloc (command_len + 1);

      /* These are for the text following @listoffloats command.
         Handling them with delayed writes is too late.  */
      close_paragraph ();
      cm_noindent ();

      sprintf (list_command, "@%s %s", command, float_type);
      register_delayed_write (list_command);
      free (list_command);
    }
  else if (float_type_exists (float_type))
    {
      FLOAT_ELT *temp = (FLOAT_ELT *) reverse_list
        ((GENERIC_LIST *) float_stack);
      FLOAT_ELT *new_start = temp;

      if (html)
        insert_string ("<ul class=\"listoffloats\">\n");
      else
        {
          if (!no_headers)
            insert_string ("* Menu:\n\n");
        }

      while (temp)
        {
          if (strlen (temp->id) > 0 && STREQ (float_type, temp->type))
            {
              char *caption;
              if (strlen (temp->shorttitle) > 0)
                caption = expansion (temp->shorttitle, 0);
              else if (strlen (temp->title) > 0)
                caption = expansion (temp->title, 0);
              else
                caption = "";
                  
              if (html)
                {
                  /* A bit of space for HTML reabality.  */
                  insert_string ("  ");
                  add_html_block_elt ("<li>");

                  /* Simply relying on @ref command doesn't work here, because
                     commas in the caption may confuse the argument parsing.  */
                  add_word ("<a href=\"");
                  add_anchor_name (temp->id, 1);
                  add_word ("\">");

                  if (strlen (float_type) > 0)
                    execute_string ("%s", float_type);

                  if (strlen (temp->id) > 0)
                    {
                      if (strlen (float_type) > 0)
                        add_char (' ');

                      add_word (temp->number);
                    }

                  if (caption)
                    {
                      if (strlen (float_type) > 0 || strlen (temp->id) > 0)
                        insert_string (": ");
                      execute_string ("%s", caption);
                    }

                  add_word ("</a>");

                  add_html_block_elt ("</li>\n");
                }
              else
                {
                  char *entry;
                  char *raw_entry;

                  int len;
                  int aux_chars_len; /* these are asterisk, colon, etc.  */
                  int column_width; /* width of the first column in menus.  */
                  int number_len; /* length of Figure X.Y: etc.   */
                  int i = 0;

                  /* Chosen widths are to match what @printindex produces.  */
                  if (no_headers)
                    {
                      column_width = 43;
                      /* We have only one auxiliary character, NULL.  */
                      aux_chars_len = sizeof ("");
                    }
                  else
                    {
                      column_width = 37;
                      /* We'll be adding an asterisk, followed by a space
                         and then a colon after the title, to construct a
                         proper menu item.  */
                      aux_chars_len = sizeof ("* :");
                    }

                  /* Allocate enough space for possible expansion later.  */
                  raw_entry = (char *) xmalloc (strlen (float_type)
                      + strlen (temp->number) + strlen (caption)
                      + sizeof (":  "));

                  sprintf (raw_entry, "%s %s", float_type, temp->number);

                  if (strlen (caption) > 0)
                    strcat (raw_entry, ": ");

                  number_len = strlen (raw_entry);

                  len = strlen (caption) + strlen (raw_entry);

                  strcat (raw_entry, caption);
                  len = strlen (raw_entry);

                  if (len + aux_chars_len > column_width)
                    { /* Shorten long titles by looking for a space before
                         column_width - strlen (" ...").  */
                      /* -1 is for NULL, which is already in aux_chars_len.  */
                      aux_chars_len += sizeof ("...") - 1;
                      len = column_width - aux_chars_len;
                      while (raw_entry[len] != ' ' && len >= 0)
                        len--;

                      /* Advance to the whitespace.  */
                      len++;

                      /* If we are at the end of, say, Figure X.Y:, but
                         we have a title, then this means title does not
                         contain any whitespaces.  Or it may be that we
                         went as far as the beginning.  Just print as much
                         as possible of the title.  */
                      if (len == 0
                          || (len == number_len && strlen (caption) > 0))
                        len = column_width - sizeof ("...");

                      /* Break here.  */
                      raw_entry[len] = 0;

                      entry = xmalloc (len + aux_chars_len);

                      if (!no_headers)
                        strcpy (entry, "* ");
                      else
                        entry[0] = 0;

                      strcat (entry, raw_entry);
                      strcat (entry, "...");

                      if (!no_headers)
                        strcat (entry, ":");
                    }
                  else
                    {
                      entry = xmalloc (len + aux_chars_len);

                      if (!no_headers)
                        strcpy (entry, "* ");
                      else
                        entry[0] = 0;

                      strcat (entry, raw_entry);

                      if (!no_headers)
                        strcat (entry, ":");
                    }

                  insert_string (entry);

                  i = strlen (entry);
                  /* We insert space chars until ``column_width + four spaces''
                     is reached, to make the layout the same with what we produce
                     for @printindex.  This is of course not obligatory, though
                     easier on the eye.  -1 is for NULL.  */
                  while (i < column_width + sizeof ("    ") - 1)
                    {
                      insert (' ');
                      i++;
                    }

                  if (no_headers)
                    {
                      if (strlen (temp->section) > 0)
                        { /* We got your number.  */
                          insert_string ((char *) _("See "));
                          insert_string (temp->section);
                        }
                      else
                        { /* Sigh, @float in an @unnumbered. :-\  */
                          insert_string ("\n          ");
                          insert_string ((char *) _("See "));
                          insert_string ("``");
                          insert_string (expansion (temp->section_name, 0));
                          insert_string ("''");
                        }
                    }
                  else
                    insert_string (temp->id);

                  insert_string (".\n");

                  free (entry);
                }
              
              if (strlen (caption) > 0)
                free (caption);
            }
          temp = temp->next;
        }

      if (html)
        {
          inhibit_paragraph_indentation = 1;
          insert_string ("</ul>\n\n");
        }
      else
        insert ('\n');

      /* Retain the original order of float stack.  */
      temp = new_start;
      float_stack = (FLOAT_ELT *) reverse_list ((GENERIC_LIST *) temp);
    }

  free (float_type);
  /* Re-increment the line number, because get_rest_of_line
     left us looking at the next line after the command.  */
  line_number++;
}

int
current_float_used_title (void)
{
	return float_stack->title_used;
}

void current_float_set_title_used (void)
{
	float_stack->title_used = 1;
}
