
/*
* NIST STEP Core Class Library
* cleditor/STEPfile.inline.cc
* April 1997
* Peter Carr
* K. C. Morris
* David Sauder

* Development of this software was funded by the United States Government,
* and is not subject to copyright.
*/

/* $Id: STEPfile_inline.cc,v 1.6 2000/02/14 13:44:04 gcosmo Exp $ */ 

#include <STEPfile.h>
#include <s_HEADER_SCHEMA.h>
#include <STEPaggregate.h>

//#ifdef __GNUG__
//#ifdef __SUNCPLUSPLUS__
//#ifdef __OBJECTCENTER__
//#ifdef __xlC__
extern "C" { 
double  ceil(double);
}


extern void HeaderSchemaInit (Registry & reg);

//To Be inline functions

//constructor & destructor

STEPfile::STEPfile(Registry& r, InstMgr& i, const char *filename)

#ifdef __O3DB__
: _reg(&r), _instances(&i),
#else
: _reg(r), _instances(i), 
#endif
#ifdef __OSTORE__
  db (0),
#endif
  _headerId(0), _maxErrorCount(5000), 
  _fileName (0), _entsNotCreated(0), _entsInvalid(0), 
  _entsIncomplete(0), _entsWarning(0), 
  _errorCount (0), _warningCount (0),
  _fileIdIncr (0)

{ 
    SetFileType(VERSION_CURRENT);
    SetFileIdIncrement(); 
    _currentDir = new DirObj("");
//    _headerRegistry = new Registry(&s_HeaderSchemaInit);
    _headerRegistry = new Registry(HeaderSchemaInit);
    _headerInstances = new InstMgr;
    if (filename) ReadExchangeFile(filename);
}

STEPfile::~STEPfile() 
{
    delete _currentDir;

//  remove everything from the Registry before deleting it
    _headerRegistry -> DeleteContents ();
    delete _headerRegistry;

//DAS    delete _headerRegistryOld;
    _headerInstances -> ClearInstances ();
    delete _headerInstances;
}

int
STEPfile::SetFileType(FileTypeCode ft) 
{
    FileType (ft);

    switch (_fileType) 
      {
	case (VERSION_OLD):
	  ENTITY_NAME_DELIM = '@';
	  FILE_DELIM = (char*)("STEP;");
	  END_FILE_DELIM = (char*)("ENDSTEP;");
/*DAS
	  if (!_headerRegistryOld) 
	      _headerRegistryOld = 
			new Registry(& s_Header_Section_Schema_N279Init);
*/

	  break;
	case (VERSION_UNKNOWN):
	case (VERSION_CURRENT):
	  ENTITY_NAME_DELIM = '#';
	  FILE_DELIM = (char*)("ISO-10303-21;");
	  END_FILE_DELIM = (char*)("END-ISO-10303-21;");
	  break;
	case (WORKING_SESSION):
	  ENTITY_NAME_DELIM = '#';
	  FILE_DELIM = (char*)("STEP_WORKING_SESSION;");
	  END_FILE_DELIM = (char*)("END-STEP_WORKING_SESSION;");
	  break;

	default:
	  // some kind of error
	  G4cerr << "Internal error:  " << __FILE__ <<  __LINE__ 
	       << "\n" << _POC_ "\n";
	  return 0;
      }
    return 1;
}

 
/******************************************************/
const char*
STEPfile::TruncFileName(const char* filename) const
{
    // Put a 'const' qualifier to the temporary string !! - GC
    const char* tmp = strrchr(filename,'/');
    if (tmp) return tmp++;
    else return filename;
    
}


/******************************************************/
Severity
STEPfile::ReadExchangeFile(const char* filename, int useTechCor)
{
    _error.ClearErrorMsg();
    _errorCount = 0;
    G4std::istream* in = OpenInputFile(filename);
    if (_error.severity() < SEVERITY_WARNING) 
      {	  
	CloseInputFile(in);
	return _error.severity();  
      }
    
    instances ().ClearInstances ();
    if (_headerInstances)
	_headerInstances->ClearInstances ();
    _headerId = 5;
    Severity rval = AppendFile (in, useTechCor);
    CloseInputFile(in);
    return rval;
}

Severity 
STEPfile::AppendExchangeFile (const char* filename, int useTechCor)
{
    _error.ClearErrorMsg();
    _errorCount = 0;
    G4std::istream* in = OpenInputFile(filename);
    if (_error.severity() < SEVERITY_WARNING) 
      {	      
	CloseInputFile(in);
	return _error.severity();  
      }
    Severity rval = AppendFile (in, useTechCor);
    CloseInputFile(in);
    return rval;
}

/******************************************************/
Severity
STEPfile::ReadWorkingFile(const char* filename, int useTechCor) 
{
    _error.ClearErrorMsg();
    _errorCount = 0;
    G4std::istream* in = OpenInputFile(filename);
    if (_error.severity() < SEVERITY_WARNING) 
      {	  
	CloseInputFile(in);
	return _error.severity();  
      }

    instances ().ClearInstances();
    _headerInstances->ClearInstances ();
    SetFileType(WORKING_SESSION);

    Severity rval = AppendFile (in, useTechCor);
    SetFileType();
    CloseInputFile(in);
    return rval;
}


Severity
STEPfile::AppendWorkingFile(const char* filename, int useTechCor)
{
    _error.ClearErrorMsg();
    _errorCount = 0;
    G4std::istream* in = OpenInputFile(filename);
    if (_error.severity() < SEVERITY_WARNING) 
      {	      
	CloseInputFile(in);
	return _error.severity();  
      }
    SetFileType(WORKING_SESSION);
    Severity rval = AppendFile (in, useTechCor);
    SetFileType();
    CloseInputFile(in);
    return rval;
}



/******************************************************/
G4std::istream*
STEPfile::OpenInputFile (const char* filename)
{
    //  if there's no filename to use, fail
    if (! (strcmp (filename, "") || strcmp (FileName (), "")) ) 
      {
	  _error.AppendToUserMsg("Unable to open file for input. No current file name.\n");
	  _error.GreaterSeverity(SEVERITY_INPUT_ERROR);
	  return (0);
      }		
    else  {
	if (!SetFileName (filename)) 
	  {
	      char msg[BUFSIZ];
	      sprintf(msg,"Unable to find file for input: \'%s\'. File not read.\n",filename);
	      _error.AppendToUserMsg(msg);
	      _error.GreaterSeverity(SEVERITY_INPUT_ERROR);
	      return (0);
	  }
    }
    //  G4std::istream* in = new G4std::istream(FileName(), io_readonly, a_useonly);
    // port 29-Mar-1994 kcm
    G4std::istream* in = new G4std::ifstream(FileName());
    // default for G4std::ostream is readonly and protections are set to 644 
//    if ( !in || !(in -> readable ()) )
    if ( !in || !(in -> good ()) )
      {
	      char msg[BUFSIZ];
	      sprintf(msg,"Unable to open file for input: \'%s\'. File not read.\n",filename);
	      _error.AppendToUserMsg(msg);
	      _error.GreaterSeverity(SEVERITY_INPUT_ERROR);
	      return (0);
      }
    return in;
}

/******************************************************/
void
STEPfile::CloseInputFile(G4std::istream* in)
{
    delete in;
}

    
/******************************************************/

/*
void
STEPfile::ReadWhiteSpace (G4std::istream& in)
{

  char c = ' ';
  while ((c == ' ') || (c == '\n') || (c == '\t'))  {
    in >> c; 
  }
  in.putback (c);
}
*/

/***************************
***************************/
G4std::ofstream*
STEPfile::OpenOutputFile(const char* filename)
{
    if (!filename) 
      {
	  if (!FileName())
	    { 
		_error.AppendToUserMsg("No current file name.\n");
		_error.GreaterSeverity(SEVERITY_INPUT_ERROR);
	    }
      }
    else 
      {
	  if (!SetFileName (filename)) 
	    {
		char msg[BUFSIZ];
		sprintf(msg,"can't find file: %s\nFile not written.\n",filename);
		_error.AppendToUserMsg(msg);
		_error.GreaterSeverity(SEVERITY_INPUT_ERROR);
	    }	      
      }

    if (_currentDir->FileExists(TruncFileName(FileName())))
	MakeBackupFile();
//    G4std::ostream* out  = new G4std::ostream(FileName(), io_writeonly, a_create);  
    // - port 29-Mar-1994 kcm
    G4std::ofstream* out  = new G4std::ofstream(FileName());  
    // default for G4std::ostream is writeonly and protections are set to 644 
    if (!out) 
      {
	  _error.AppendToUserMsg("unable to open file for output\n");
	  _error.GreaterSeverity(SEVERITY_INPUT_ERROR);
      }
    return out;
}

void
STEPfile::CloseOutputFile(G4std::ostream* out) 
{
    delete out;
}



/******************************************************/
int 
STEPfile::IncrementFileId (int fileid) 
{ 
    return (fileid + FileIdIncr()); 
}


void 
STEPfile::SetFileIdIncrement()
{
    // Added cast to float in argument for 'ceil' function call. This avoids
    // clashes with cmath function signatures on HP-aCC - GC
    if (instances ().MaxFileId() < 0) _fileIdIncr = 0;
    else _fileIdIncr = (int)((ceil(float((instances ().MaxFileId() + 99)/1000) + 1)) * 1000);
}

char *STEPfile::schemaName( char *schName )
    /*
     * Returns the schema name from the file schema header section (or the 1st
     * one if more than one exists).  Copies this value into schName.  If there
     * is no header section or no value for file schema, NULL is returned and
     * schName is unset.
     */
{
    p21DIS_File_schema *fs;
    SCLstring tmp;
    STEPnode *n;

    if ( _headerInstances == NULL ) return NULL;
    fs = (p21DIS_File_schema *)_headerInstances->GetApplication_instance("File_Schema");
    if ( fs == ENTITY_NULL ) return NULL;

    n = (STEPnode *)fs->schema_identifiers().GetHead();
    // (take the first one)
    if ( n == NULL ) return NULL;
    n->STEPwrite(tmp);
    if ( *tmp.chars() == '\0' || *tmp.chars() == '$' ) return NULL;
    // tmp.chars() returns the string we want plus a beginning and ending
    // quote mark (').  We remove these below.
    strncpy( schName, tmp.chars()+1, BUFSIZ-1 );
    // "+1" to remove beginning '.
    if ( *(schName + strlen( schName ) - 1) == '\'' ) {
	// Remove trailing '.  This condition checks that it wasn't removed
	// already.  That may have happend if strncpy had truncated schName
	// (it were >= BUFSIZ).
	*(schName + strlen( schName ) - 1) = '\0';
    }
    return schName;
}
