/*
 * Copyright 1999 AT&T Labs -- Research
 * By receiving and using the code that follows, the user acknowledges
 * and agrees to keep the code confidential and use the code solely for
 * non-commercial research. The user further acknowledges and agrees that
 * the  code is not an official product of AT&T Corp., and is provided
 * on an "as is"  basis with no warranty, either express or implied, including
 * but not limited to implied warranties of merchantability and fitness
 * for a particular purpose, and any warranties of noninfringement.
 * The user shall use reasonable efforts to provide AT&T Laboratories
 * with reports of any errors, defects or suggestions for change and
 * improvements to the code.
 */

#include "stdafx.h"

#ifdef SET_OUTPUT_STATIC
	int XMLStringOutput::curcol;
	int XMLStringOutput::coldelta;
	struct XMLStringOutput::ABC XMLStringOutput::x;
#endif

XMLStringOutput::XMLStringOutput(Settings *settings)
{
	theoutput = new Output(settings);
   Init(XMLINDENT_NONE);
}

XMLStringOutput::~XMLStringOutput()
{
	trydel (theoutput);
}

void XMLStringOutput::SetOutput(Output *outp)
{
	if (theoutput && outp != theoutput) {
		trydel (theoutput);
	}
	theoutput = outp;
}

Output* XMLStringOutput::GetOutput()
{
	return theoutput;
}

char OUTPUT_STATIC XMLStringOutput::myCreateFile(char *fname)
{
	return theoutput->myCreateFile(fname);
}

void OUTPUT_STATIC XMLStringOutput::CloseFile()
{
	theoutput->CloseFile();
}

void OUTPUT_STATIC XMLStringOutput::Init(unsigned char myindentation,unsigned char myvaluespacing,unsigned char mycoldelta)
{
   curcol=0;
   coldelta=mycoldelta;
   x.indentation=myindentation;

   x.status=XMLOUTPUT_INIT;
   x.isinattrib=0;

   x.valuespacing=myvaluespacing;
}

OUTPUT_STATIC void XMLStringOutput::GotoNextLine(char moveright)
{
   switch(x.indentation)
   {
   case XMLINDENT_SPACES:
   case XMLINDENT_TABS:
   {
      theoutput->StoreNewline();

      if(moveright==0)
         curcol-=coldelta;

      if(x.indentation==XMLINDENT_SPACES)
         mymemset(theoutput->GetDataPtr(curcol),' ',curcol);
      else
         mymemset(theoutput->GetDataPtr(curcol),'\t',curcol);

      if(moveright)
         curcol+=coldelta;
      break;
   }
/*
   case XMLINDENT_WRAP:
      if(GetColPos()>=coldelta)
         StoreNewline();
*/
   }
}

void OUTPUT_STATIC XMLStringOutput::startElement(char *str,int len)
{
   switch(x.status)
   {
   case XMLOUTPUT_OPENLABEL:
      theoutput->StoreChar('>');
      GotoNextLine(1);
      break;

   case XMLOUTPUT_OPENATTRIB:
      throw new XMillException(XMILL_ERR_PARSE, "Cannot start element within attribute!");

   case XMLOUTPUT_AFTERENDLABEL:
   case XMLOUTPUT_AFTERDATA:
      GotoNextLine(1);
      break;

   case XMLOUTPUT_INIT:
      curcol+=coldelta;
      break;
   }
   theoutput->StoreChar('<');

   x.status=XMLOUTPUT_OPENLABEL;
   theoutput->StoreData(str,len);

   x.attribwhitespace=0;
}

void OUTPUT_STATIC XMLStringOutput::endElement(char *str,int len)
{
   char *ptr;
   switch(x.status)
   {
   case XMLOUTPUT_OPENLABEL:
      ptr=theoutput->GetDataPtr(len+4);
      *(ptr++)='>';
      *(ptr++)='<';
      *(ptr++)='/';
      mymemcpy(ptr,str,len);
      ptr+=len;
      *(ptr++)='>';
      curcol-=coldelta;
      x.status=XMLOUTPUT_AFTERENDLABEL;
      return;

   case XMLOUTPUT_AFTERENDLABEL:
      GotoNextLine(0);
      break;

   case XMLOUTPUT_AFTERDATA:
      curcol-=coldelta;
      break;

   default:
      throw new XMillException (XMILL_ERR_PARSE, "Invalid end tag");
   }

   ptr=theoutput->GetDataPtr(len+3);

   *(ptr++)='<';
   *(ptr++)='/';
   mymemcpy(ptr,str,len);
   ptr+=len;
   *(ptr++)='>';
   
   x.status=XMLOUTPUT_AFTERENDLABEL;
}

void OUTPUT_STATIC XMLStringOutput::endEmptyElement()
{
   char *ptr;
   if(x.status!=XMLOUTPUT_OPENLABEL)
      // Something is wrong !!
      return;

   ptr=theoutput->GetDataPtr(2);
   *(ptr++)='/';
   *(ptr++)='>';

   x.status=XMLOUTPUT_AFTERENDLABEL;
   curcol-=coldelta;
}

void OUTPUT_STATIC XMLStringOutput::startAttribute(char *str,int len)
{
   register char *ptr;

   if(x.status==XMLOUTPUT_OPENATTRIB)
   {
      ptr=theoutput->GetDataPtr(len+(x.attribwhitespace ? 3 : 4));
      *(ptr++)='"';
   }
   else
   {
      if(x.status!=XMLOUTPUT_OPENLABEL) {
         throw new XMillException(XMILL_ERR_CORRUPT, "Cannot print attribute outside of start element!");
      }
      ptr=theoutput->GetDataPtr(len+(x.attribwhitespace ? 2 : 3));
   }
   if(x.attribwhitespace==0)
   {
      *(ptr++)=' ';
      x.attribwhitespace=0;
   }

   mymemcpy(ptr,str,len);
   ptr+=len;
   *(ptr++)='=';
   *(ptr++)='"';

   x.status=XMLOUTPUT_OPENATTRIB;
}

void OUTPUT_STATIC XMLStringOutput::endAttribute(char *str, int len)
{
   if(x.status!=XMLOUTPUT_OPENATTRIB)
   {
      throw new XMillException(XMILL_ERR_PARSE, "Could not finish attribute outside of start element!");
   }
   theoutput->StoreChar('"');
   x.status=XMLOUTPUT_OPENLABEL;
}

void OUTPUT_STATIC XMLStringOutput::characters(char *str,int len)
{
   switch(x.status)
   {
   case XMLOUTPUT_OPENATTRIB:
      theoutput->StoreData(str,len);
      return;

   case XMLOUTPUT_OPENLABEL:
      theoutput->StoreChar('>');

   case XMLOUTPUT_AFTERDATA:
   case XMLOUTPUT_AFTERENDLABEL:
   case XMLOUTPUT_INIT:
      theoutput->StoreData(str,len);
   }
   x.status=XMLOUTPUT_AFTERDATA;
}

void OUTPUT_STATIC XMLStringOutput::whitespaces(char *str,int len)
{
   characters(str,len);
}

void OUTPUT_STATIC XMLStringOutput::attribWhitespaces(char *str,int len)
{
   char *ptr=theoutput->GetDataPtr(len);
   mymemcpy(ptr,str,len);
   x.attribwhitespace=1;
}
