/*
This product contains certain software code or other information
("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
WILL MEET YOUR REQUIREMENTS.

Unless you accept a license to use the AT&T Software, you shall not
reverse compile, disassemble or otherwise reverse engineer this
product to ascertain the source code for any AT&T Software.

(c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.

***********************************************************************

History:

      24/11/99  - initial release by Hartmut Liefke, liefke@seas.upenn.edu
                                     Dan Suciu,      suciu@research.att.com
*/
//**************************************************************************
//**************************************************************************
// This module contains the output file management

#include "stdafx.h"

#ifdef SET_OUTPUT_STATIC
	FILE  *Output::output;
	char  *Output::buf;
	char  *Output::savefilename;
	int   Output::bufsize,
			Output::curpos;
	int   Output::overallsize;
#endif

// For now, we do not have a static implementation
//#define SET_OUTPUT_STATIC

#ifdef SET_OUTPUT_STATIC
	#define OUTPUT_STATIC static
#else
	#define OUTPUT_STATIC
#endif

/* some C functions */
char FileExists(char *filename)
{
#ifdef WIN32
   _finddata_t fileinfo;
   long        handle=_findfirst(filename,&fileinfo);
   if(handle==-1)
      return 0;
   _findclose(handle);
   return 1;
#else /* !WIN32 */
   FILE *file=fopen(filename,"r");
   if(file==NULL)
      return 0;
   fclose(file);
   return 1;
#endif /* WIN32 */
}

void RemoveFile(char *filename)
{
   unlink(filename);
}

/* class Output implementation */
Output::Output(Settings *se)
{
	settings = se;
	setMaxLength(0);
}

void Output::setMaxLength(int mlen)
{
	maxlen = mlen;
}

char OUTPUT_STATIC Output::myCreateFile(char *filename,int mybufsize)
   // Creates the output file. If 'filename==NULL', then the standard
   // output is used.
{
   if(filename==NULL)
   {
      savefilename=NULL;
      output=stdout;

      // We allocate the memory
      buf=(char *)mymalloc(mybufsize);
      if(buf==NULL)
         ExitNoMem();

#ifdef WIN32
      _setmode(_fileno(stdout),_O_BINARY);
#endif
   }
   else
   {
      // We allocate the output buffer memory and a little more for the filename
      buf=(char *)mymalloc(mybufsize+strlen(filename)+1);
      if(buf==NULL)
         ExitNoMem();

      savefilename=buf+mybufsize;
      strcpy(savefilename,filename);

      // We only open the output file, if strlen(filename)>0.
      // Otherwise, no output is performed at all.
      // (This is the test-case)
      if(strlen(filename)!=0)
      {
         output=fopen(filename,"wb");
         if(output==NULL)
            return 0;
      }
      else
         output=NULL;
   }
   bufsize=mybufsize;
   curpos=0;
   overallsize=0;
   return 1;
}

void OUTPUT_STATIC Output::CloseFile()
   // Writes the remaining output to the file and closes the file
{
   Flush();
   if(savefilename!=NULL)
   {
      if(output!=NULL)
         fclose(output);
   }
   tryfree(buf);
}

void OUTPUT_STATIC Output::CloseAndDeleteFile()
   // Writes the remaining data and closes the file and removes it
{
   Flush();
   if(savefilename!=NULL)
   {
      if(output!=NULL)
         fclose(output);
      unlink(savefilename);
   }
   tryfree(buf);
   return;
}

void OUTPUT_STATIC Output::Flush()
   // Flushes the output file
{
   overallsize+=curpos;

   if(output==NULL)
   {
      curpos=0;
      return;
   }

   char  *ptr=buf;
   int   byteswritten;

   // We write the output between '0' and 'curpos'
   // We only write at most 30000 bytes - to avoid some glitches
   // in the implementation of 'fwrite'.

   while(curpos>0)
   {
      byteswritten=fwrite(ptr,1,(curpos<XMILL_MAXFILEBUFSIZE) ? curpos : XMILL_MAXFILEBUFSIZE,output);
      if(byteswritten==0)
      {
         throw new XMillException(XMILL_ERR_WRITE, "Could not write output file!");
      }
      curpos-=byteswritten;
      ptr+=byteswritten;
   }
}

char OUTPUT_STATIC *Output::GetBufPtr(int *len)
   // Returns the current empty buffer space and its size
{
   *len=bufsize-curpos;
   return buf+curpos;
}

void OUTPUT_STATIC Output::SaveBytes(int bytecount)
   // After the user put some data into the empty buffer space,
   // it must be acknowledged with 'SaveBytes'
{
   curpos+=bytecount;
}

// Returns the current file size
int OUTPUT_STATIC Output::GetCurFileSize() 
{  
	return overallsize+curpos; 
}

void OUTPUT_STATIC Output::StoreData(char *ptr,int len)
   // Stores the data at position 'ptr' of length 'len'
{
   while(bufsize-curpos<len)
   {
      mymemcpy(buf+curpos,ptr,bufsize-curpos);
      len-=bufsize-curpos;
      ptr+=bufsize-curpos;
      curpos=bufsize;
      Flush();
   }
   mymemcpy(buf+curpos,ptr,len);
   curpos+=len;
}

void OUTPUT_STATIC Output::StoreInt32(int val)
   // Stores a simple uncompressed integer
{
   if(bufsize-curpos<4)
      Flush();

   *(int *)(buf+curpos)=val;
   curpos+=4;
}

void OUTPUT_STATIC Output::StoreChar(char c)
   // Stores a character
{
   if(bufsize-curpos<1)
      Flush();

   buf[curpos]=c;
   curpos++;
}

void OUTPUT_STATIC Output::StoreNewline()
   // Stores a new line
{
   if(settings->usedosnewline)
   {
      if(bufsize-curpos<2)
         Flush();

      buf[curpos++]='\r';
   }
   else
   {
      if(bufsize-curpos<1)
         Flush();
   }
   buf[curpos++]='\n';
}

char OUTPUT_STATIC *Output::GetDataPtr(int len)
   // Returns a buffer space big enough to contain 'len' bytes
   // The buffer pointer is automatically updated
{
   if(bufsize-curpos<len)
   {
      Flush();
      if(bufsize-curpos<len)
      {
         throw new XMillException (XMILL_ERR_FATAL, "memory fuckup");
      }
   }
   curpos+=len;
   return buf+curpos-len;
}

/* class MemOutput implementation */
char OUTPUT_STATIC MemOutput::myCreateFile(char **membuf,int *buflen,int mybufsize)
   // Creates the output file. If 'filename==NULL', then the standard
   // output is used.
{
   savefilename=NULL;
	memorybuffer = membuf;
	bufferlength = buflen;

   // We allocate the memory
	if (!(buf=(char *)mymalloc(mybufsize))) {
      ExitNoMem();
	}
	if (!(totalbuffer=(char *)mymalloc(mybufsize+1))) {
      ExitNoMem();
	}
   bufsize=mybufsize;
   totalbuflen=curpos=overallsize=0;
	return 1;
}

void OUTPUT_STATIC MemOutput::CloseFile()
   // Writes the remaining output to the file and closes the file
{
   Flush();
	if(memorybuffer) {
		*memorybuffer = totalbuffer;
	}
	if (bufferlength) {
		*bufferlength = totalbuflen;
	}
	tryfree(buf);
}

void OUTPUT_STATIC MemOutput::CloseAndDeleteFile()
   // Writes the remaining data and closes the file and removes it
{
   Flush();
	tryfree(totalbuffer);
	tryfree(buf);
}

void OUTPUT_STATIC MemOutput::Flush()
   // Flushes the output file
{
   overallsize+=curpos;
	
	if (maxlen > 0 && overallsize>maxlen && settings->noincrease) {
		char s[STRLEN+1];
		_snprintf(s, STRLEN, "XMI file has grown to %ld Bytes which is larger than input (%ld). "
			"The client is requested to copy the XML file to the intended XMI file. "
			"Disable the 'noincrease' XMill setting to ignore this error.",
			overallsize, maxlen);
		s[STRLEN] = '\0';
		throw new XMillException(XMILL_ERR_XMIFILELARGER, s);
	}

   if(memorybuffer==NULL)
   {
      curpos=0;
      return;
   }

   char  *ptr=buf;

   // We copy the output between '0' and 'curpos'
   if(curpos>0)
   {
		totalbuflen += curpos;
		totalbuffer = (char*)realloc(totalbuffer, totalbuflen+1);
		memcpy(&totalbuffer[totalbuflen - curpos], ptr, curpos);
      curpos=0;
   }
}
