/* Stack.C
 *
 * Adjusting the look and feel of the document in a recursive way is done
 * with a stack of Environments, where each environment holds variables such
 * as the current font and margin sizes. This describes the stack.
 *
 * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute,
 * edit and use as long as this copyright statement remains intact.
 *
 */

#include "Global.h"
#include "Document.h"
#include "Font.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Environment *Stack::environments[MAXNESTING];
int Stack::level;

Stack::Stack()
{
   level=0;
   for(int x=0; x < MAXNESTING; x++)
      environments[x] = NULL;
   environments[0] = new Environment();  // Initialize the root environment
}

void Stack::push(int, int, float, char *)
{
   if(level > MAXNESTING)
      Global::files->fatal_error("Too much nesting");
   
   environments[level+1] = new Environment(environments[level]);
   level++;
}

void Stack::pop(int, int subtype, float, char *)
{
   if(level == 0)
      Global::files->fatal_error("Too many \\end or } tokens");

   Stack::get(Environment::PDocument, subtype, "");

   environments[level-1]->revert(environments[level]);
   delete environments[level];
   level--;
}

/* This functions sets a parameter in the current environment. When the '}'
 * character or the \end command is encountered, the current environment
 * will popped off the stack and this parameter will be reset to its former
 * value (the value previous to the last '{' character or \begin command
 * or the default value)
 */
void Stack::set(int paramtype, int subtype, float value, char *replacestr)
{
   environments[level]->set(paramtype,subtype,value,replacestr);
}

/* This functions sets a parameter in the current environment, relative
 * to its current value.
 */
void Stack::relative_set(int paramtype, int subtype, float value,
			 char *replacestr)
{
   environments[level]->
      set(paramtype, subtype,
	   value + environments[level]->get(paramtype, subtype, replacestr),
	  replacestr);
}



/* This function gets a parameter value from the current environment, 
 * as indexed by the parameter type and subtype.
 */
float Stack::get(int paramtype, int subtype, char *comparestr)
{
   return environments[level]->get(paramtype, subtype, comparestr);
}

void Stack::shutdown()
{
   char commandname[MAXSTRING];
   if(level > 0)
	 Global::files->fatal_error("Missing \\end or }");
   Global::files->outfile << endl;
   Global::files->outfile << "ENDPAGE" << endl;

   Stack::get(Environment::PDocument, Document::ShutDown, "");
   Global::files->outfile.close();
   Global::labels->shutdown();
   char realname[MAXSTRING];

   char srcdir[MAXSTRING];     // Take a trailing / off the source
   strcpy(srcdir,SRCDIR);      // directory pathname, if needed.
   int last = strlen(srcdir) - 1;
   if(srcdir[last]=='/')
      srcdir[last]='\0';
   strcpy(realname, Global::files->outfilename);
   char *p = strchr(realname,'.');
   *p='\0';

   if(Global::files->plain_text_output) {
	sprintf(commandname, "perl %s/plaintext.pl < %s > %s.txt", srcdir,
		Global::files->outfilename, Global::files->outfileroot);
	system(commandname);
	sprintf(commandname, "Output has been placed in %s.txt",
		Global::files->outfileroot);
	cerr << commandname << endl;
        sprintf(commandname,"rm %s", Global::files->outfilename);
	system(commandname);
      return;
   }
   Stack::get(Environment::PFont, Font::ShutDown, "");

   /* A number of files have been created. It's time to merge them
      together into one big file */



   // Concatenate all these library and temporary files into
   // the final rootname.ps file.

   sprintf(commandname,
 "cat %s/latex.header lametex.PS %s/format.ps %s/breakpath.ps %s %s/latex.footer > %s.ps",
	   srcdir, srcdir, srcdir, Global::files->outfilename, srcdir,
	   realname);

   
   system(commandname);   // Execute the concatenate command
   cerr << "Created PostScript file " << realname
	<< ".ps" << endl;

   sprintf(commandname,"rm lametex.PS lametex.aux lametex.log %s", Global::files->outfilename);
   system(commandname);   // Execute the concatenate command
}

Length *Stack::get_length()
{
   return (Length *)environments[level]->get_param(Environment::PLength);
}