/*   
		Tempi - A HTML Template system
    Copyright (C) 2002  Roger Faust <roger_faust@bluewin.ch>

    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 2 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, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
		
*/

#ifndef TEMPI_C
#define TEMPI_C 1
#endif

/*starting to whole stuff*/
char *
init (char *argv)
{
  int temp_i;

  /*YY_BUFFER_STATE temp_buffer; */
  /*int _yyi; */

  if (init_done)
    {
      s_strfree (&temp_string);
      s_strcat (&temp_string,
		"Init has already been running, use first tempi_reinit ()");
      return (temp_string.value);
    }

  free_memory_done = false;
  ablock = &fblock;
  temp_string.value = NULL;
  temp_string.size = 0;
  temp_string.memory = 0;
  parst.value = NULL;
  parst.size = 0;
  parst.memory = 0;

  if (!init_run)
    {
      flex_output.value = s_malloc (REALLOC_STRING_BIG);
      flex_output.size = 1;
      flex_output.memory = REALLOC_STRING_BIG;
      *flex_output.value = '\0';
      for (temp_i = 0; temp_i < MAX_BLOCK_DEP; temp_i++)
	{
	  (block_names[temp_i]).value = NULL;
	  (block_names[temp_i]).size = 0;
	  (block_names[temp_i]).memory = 0;
	}
      a_file.value = NULL;
      a_file.size = 0;
      a_file.memory = 0;
      block_counter = 0;
      line_counter = 0;
      block_counter_real = 0;
      track_file = NULL;
      for (temp_i = 0; temp_i < MAX_FILE_DEP; temp_i++)
	{
	  (files.files)[temp_i] = NULL;
	}
      files.open = 0;
      for (temp_i = 0; temp_i < MAX_FILE_DEP; temp_i++)
	{
	  (buffers.buffers)[temp_i] = NULL;
	}
      buffers.open = 0;
      add_block_name (MAIN_BLOCK_NAME);
      s_strcat (&(block_names[0]), MAIN_BLOCK_NAME);
      temp_i = errno;
      errno = 0;
      yyin = fopen (argv, "r");
      if (errno)
	{
	  s_strfree (&temp_string);
	  s_strcat (&temp_string, "Couldn't open file ");
	  s_strcat (&temp_string, argv);
	  return (temp_string.value);
	  /*s_error (NULL); */
	}
      errno = temp_i;
      s_strcat (&a_file, argv);
      block_counter_real++;
      temp_i = yylex ();
      if (temp_i == ERROR_DURING_PARSING)
	return (temp_string.value);
      for (temp_i = 0; temp_i < MAX_BLOCK_DEP; temp_i++)
	{
	  s_strfree (&block_names[temp_i]);
	}
      s_strfree (&a_file);
      s_strfree (&flex_output);
      init_run = true;
    }
  init_done = true;
  make_out_struct ();
  return (NULL);
}


/*
 * collecting the output of flex (overriding builtin ECHO macro with this
 * function)
 */
void
get_flex_output (void)
{
  flex_output.size += yyleng;
  /*a terrible debugging session has shown my, that we need this controll */
  /*this functions depens on getting a true string in flex_output, but */
  /*we can not count on that, so we have to prouve that flex_output.size */
  /*is at last 2 byte (one for the char we want, and one for the \0) */
  if (flex_output.size == 1)
    flex_output.size++;
  while (flex_output.memory < flex_output.size)
    {
      flex_output.memory += REALLOC_STRING_BIG;
      flex_output.value = s_realloc (flex_output.value, flex_output.memory);
    }
  /*it's very important, to avoid strcat, since it would 
     slow down the whole thing by about 100% (depending on 
     each block size, since c has always to calculait the 
     size of a string (in contrast to pascal :-), but we will 
     store it for us...) */
  if (yyleng == 1)
    {
      *(flex_output.value + flex_output.size - 2) = *yytext;
      *(flex_output.value + flex_output.size - 1) = '\0';
    }
  else
    strcat (flex_output.value, yytext);
}


/*
 * adding output to a block, creating a new one
 */
void
add_block_value (char *value)
{
  ablock->next = s_malloc (sizeof (block));
  if (value == NULL)
    ablock->value = NULL;
  else
    {
      ablock->value = s_malloc (1 + strlen (value));
      strcpy (ablock->value, value);
    }
  ablock = ablock->next;
  ablock->next = NULL;
  ablock->is_var = false;
  ablock->is_last = false;
}

/*
 * adds a name to a block
 */
void
add_block_name (char *name)
{
  if (name == NULL)
    ablock->name = NULL;
  else
    {
      ablock->name = s_malloc (1 + strlen (name));
      strcpy (ablock->name, name);
    }
}

/*
 * will create the output data structure
 */
void
make_out_struct (void)
{
  int temp_i;
  out = s_malloc ((1 + block_counter_real) * sizeof (string));
  for (temp_i = 0; temp_i <= block_counter_real; temp_i++)
    {
      out[temp_i].value = NULL;
      out[temp_i].size = 0;
      out[temp_i].memory = 0;
    }
}

/*
 * copy a block to the output string
 */
char *
parse_block (char *name)
{
  int temp_i = 0;
  bool c = true, found = false;
  string aname[MAX_BLOCK_DEP];
  if (!init_done)
    return (NO_INIT_RUN);
  for (temp_i = 0; temp_i <= MAX_BLOCK_DEP; temp_i++)
    aname[temp_i].value = NULL;
  temp_i = 0;
  ablock = &fblock;
  while (ablock->next != NULL)
    {
      if ((strcmp (ablock->name, name)) == 0)
	{
	  found = true;
	  s_strcat (&out[temp_i], ablock->value);
	  c = true;
	  if (ablock->is_last)
	    return (NULL);
	}
      else if (!(ablock->is_var))
	c = false;
      if (!(ablock->is_var))
	temp_i++;
      else if (c)
	s_strcat (&out[temp_i], ablock->value);
      ablock = ablock->next;
    }
  if (found)
    return (NULL);
  s_strfree (&temp_string);
  s_strcat (&temp_string, "Block ");
  s_strcat (&temp_string, name);
  s_strcat (&temp_string, " doesn't exist");
  return (temp_string.value);
}

/*
 * set a var with a value
 */
char *
set_var (char *name, char *value)
{
  bool found = false;
  if (!init_done)
    return (NO_INIT_RUN);
  ablock = &fblock;
  while (ablock->next != NULL)
    {
      if (ablock->is_var)
	{
	  if ((strcmp (ablock->name, name)) == 0)
	    {
	      found = true;
	      ablock->value = s_realloc (ablock->value, 1 + strlen (value));
	      strcpy (ablock->value, value);
	    }
	}
      ablock = ablock->next;
    }
  if (found)
    return (NULL);
  else
    {
      s_strfree (&temp_string);
      s_strcat (&temp_string, "Variable ");
      s_strcat (&temp_string, name);
      s_strcat (&temp_string, " doesn't exist");
      return (temp_string.value);
    }
}

/*
 * makes a string out of all parsed data
 */
char *
get_parsed ()
{
  int temp_i;
  if (!init_done)
    return (NULL);
  parst.value = NULL;
  for (temp_i = 0; temp_i <= block_counter_real; temp_i++)
    {
      s_strcat (&parst, out[temp_i].value);
    }
  return parst.value;
}

/*
 * will free no more used memory (at least i hope so...)
 */
char *
free_memory ()
{
  int temp_i;
  if (!init_done)
    return (NO_INIT_RUN);
  for (temp_i = 0; temp_i <= block_counter_real; temp_i++)
    {
      s_strfree (&out[temp_i]);
    }
  s_free (out);
  s_strfree (&parst);
  s_strfree (&temp_string);
  init_done = false;
  free_memory_done = true;
  return (NULL);
}

void
free_memory_rest ()
{
  block *temp;
  ablock = &fblock;
  /* this may seem very stupid, but it's necesary, since 
     fblock isn't dynamic memory, what would cause free  
     to fail terrible */
  if (ablock->value != NULL)
    s_free (ablock->value);
  if (ablock->name != NULL)
    s_free (ablock->name);
  ablock = ablock->next;
  while (ablock->next != NULL)
    {
      if (ablock->value != NULL)
	s_free (ablock->value);
      if (ablock->name != NULL)
	s_free (ablock->name);
      temp = ablock->next;
      s_free (ablock);
      ablock = temp;
    }
  s_free (ablock);
  free_memory ();
}

char *
reinit ()
{
  if ((!init_done) && (!free_memory_done))
    return (NO_INIT_RUN);
  if (!free_memory_done)
    return (NO_FREE_MEMORY_RUN);
  free_memory_rest ();
  init_run = false;
  init_done = false;
  free_memory_done = false;
  return (NULL);
}