/////////////////////////////////////////////////////////////////////////////// 
// Copyright (C) 2003-2012, Open Design Alliance (the "Alliance"). 
// All rights reserved. 
// 
// This software and its documentation and related materials are owned by 
// the Alliance. The software may only be incorporated into application 
// programs owned by members of the Alliance, subject to a signed 
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable  
// trade secrets of the Alliance and its suppliers. The software is also 
// protected by copyright law and international treaty provisions. Application  
// programs incorporating this software must include the following statement 
// with their copyright notices:
//   
//   This application incorporates Teigha(R) software pursuant to a license 
//   agreement with Open Design Alliance.
//   Teigha(R) Copyright (C) 2003-2012 by Open Design Alliance. 
//   All rights reserved.
//
// By use of this software, its documentation or related materials, you 
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4018) // signed/unsigned mismatch
#pragma warning(disable : 4146) // unary minus operator applied to unsigned type, result still unsigned

#if !defined(_WIN32_WCE) && !defined(ODA_MAC_OSX) && !defined(__MWERKS__)
// Use standard ftime() function available for all systems except WinCE
#include <sys/timeb.h>
#define ODA_USE_FTIME

#include <sys/types.h>
#endif

#ifdef WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#endif

#ifndef _WIN32_WCE
#include <io.h>
#endif

#pragma warning(pop)
#endif

#ifndef _WIN32_WCE
#include <sys/stat.h>
#endif



#include "OdaCommon.h"
#include "ExSystemServices.h"
#include "OdFileBuf.h"
#include "RxObjectImpl.h"
#include "RxDefs.h"
#include "RxDictionary.h"
#include "RxModule.h"
#include "OdToolKit.h"
#include "ExGiRasterImage.h"
#include "FlatMemStream.h"
#include "ColorMapping.h"
#include "Gs/GsBMPDevice.h"
#include "Gs/Gs.h"

#define STL_USING_ALGORITHM
#include "OdaSTL.h"
bool IsCompound(OdStreamBuf *pBuf);

ExSystemServices::ExSystemServices()
  : m_CodePageId(CP_UNDEFINED)
{
#ifdef _WIN32
  switch(::GetACP())
  {
  case 874:
    m_CodePageId = CP_ANSI_874;
    break;
  case 932:
    m_CodePageId = CP_ANSI_932;
    break;
  case 936:
    m_CodePageId = CP_ANSI_936;
    break;
  case 949:
    m_CodePageId = CP_ANSI_949;
    break;
  case 950:
    m_CodePageId = CP_ANSI_950;
    break;
  case 1200:
    m_CodePageId = CP_ANSI_1200;
    break;
  case 1250:
    m_CodePageId = CP_ANSI_1250;
    break;
  case 1251:
    m_CodePageId = CP_ANSI_1251;
    break;
  case 1252:
    m_CodePageId = CP_ANSI_1252;
    break;
  case 1253:
    m_CodePageId = CP_ANSI_1253;
    break;
  case 1254:
    m_CodePageId = CP_ANSI_1254;
    break;
  case 1255:
    m_CodePageId = CP_ANSI_1255;
    break;
  case 1256:
    m_CodePageId = CP_ANSI_1256;
    break;
  case 1257:
    m_CodePageId = CP_ANSI_1257;
    break;
  }
#endif
}

OdStreamBufPtr ExSystemServices::createFile(
    const OdString& pcFilename,                   // file name
    Oda::FileAccessMode nDesiredAccess,
    Oda::FileShareMode nShareMode,
    Oda::FileCreationDisposition nCreationDisposition)

{
	OdSmartPtr<OdBaseFileBuf> pFile;

  // MKU 19.02.2004   It was corrected after debugging with BORLANDC. It hangs on open() statement 
  //                  in case of using conditional operator: ? :.
  //
  // typedef OdSmartPtr<OdBaseFileBuf> OdBaseFileBufPtr;
	// OdBaseFileBufPtr pFile;
  // pFile = (nDesiredAccess == Oda::kFileRead ?
  //   OdBaseFileBufPtr(OdRdFileBuf::createObject()) :
  //   OdBaseFileBufPtr(OdWrFileBuf::createObject()));

  if(!pcFilename.isEmpty() && pcFilename[0])
  {
    if ((nDesiredAccess & Oda::kFileWrite) != 0)
    {
      pFile = OdWrFileBuf::createObject();
    }
    else
    {
      pFile = OdRdFileBuf::createObject();
    }

    pFile->open(pcFilename, nShareMode, nDesiredAccess, nCreationDisposition);
  }
  else
  {
    throw OdError(eNoFileName);
  }
  return OdStreamBufPtr(pFile);
}


bool ExSystemServices::accessFile(const OdString& pcFilename, int mode)
{
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
  // SetErrorMode() function is used to avoid the message box
  // if there is no floppy disk in the floppy drive (CR 2122).
  int oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  bool res = (_waccess(pcFilename,
    (GETBIT(mode, Oda::kFileRead)  ? 0x04 : 0x00) | 
    (GETBIT(mode, Oda::kFileWrite) ? 0x02 : 0x00)) == 0);
  SetErrorMode(oldErrorMode);
  if (res)
  {
    struct _stat st = {0};
    if (_wstat(pcFilename,&st)==-1)
      return false;
    if (st.st_mode & _S_IFDIR)
      return false;
  }
  return res;
#elif defined(sgi)
  // Use this version, since try/catch below results in memory leaks on sgi (OdError destructor doesn't get called).
  OdString  sMode = (mode == Oda::kFileRead) ? OD_T("rb") : OD_T("wb");
  FILE* fp = fopen((const char*)pcFilename, (const char*)sMode);
  if (fp)
  {
    fclose(fp);
    return true;
  }
  return false;
#else
  try
  {
    createFile(pcFilename, (Oda::FileAccessMode)mode);
    return true;
  }
  catch(...) 
	{
		return false; // Do NOT remove this, or else some compilers (e.g. cw7 mac) will optimize out the catch! 
	}
  return false;
#endif
}


#if (defined(_WIN32) || defined(_WIN64)) && !defined(_WIN32_WCE)
#include <sys/stat.h>

OdInt64 ExSystemServices::getFileCTime(const OdString& name)
{
  struct _stat st;
  if (_wstat(name, &st)) return -1;
  return st.st_ctime;
}

OdInt64 ExSystemServices::getFileMTime(const OdString& name)
{
  struct _stat st;
  if (_wstat(name, &st)) return -1;
  return st.st_mtime;
}

#else // _WIN32
OdInt64 ExSystemServices::getFileCTime(const OdString&)
{
  return (-1);
}

OdInt64 ExSystemServices::getFileMTime(const OdString&)
{
  return (-1);
}
#endif  // _WIN32

OdInt64 ExSystemServices::getFileSize(const OdString& name)
{
#if (defined(WIN32) || defined(_WIN64))  
  WIN32_FIND_DATA fd;
  if (HANDLE hf = ::FindFirstFile(OdString(name), &fd))
  {
    FindClose(hf);
    return (OdInt64(fd.nFileSizeLow) | (OdInt64(fd.nFileSizeHigh) << 32));
  }
  return OdInt64(-1);
#else
  struct stat st;
  OdString tmp(name);
  if (stat(static_cast<const char*>(tmp), &st)) return OdInt64(-1);
  return OdInt64(st.st_size);
#endif
}

bool IsCompound(OdStreamBuf *pBuf)
{
  static OdUInt8 docID[8]={ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };  
  OdUInt8  b8[8];
  int   i;

  pBuf->seek(128, OdDb::kSeekFromStart);
  pBuf->getBytes(b8, 8);
  pBuf->seek(0, OdDb::kSeekFromStart);
  for (i=0; i<8; i++)
  {
    if (b8[i] != docID[i]) 
    {
      return false;
    }
  }
  return true;
}


OdString ExSystemServices::formatMessage(unsigned int code, va_list* argList)
{
  static const OdChar* message[] =
  {
#define OD_ERROR_DEF(cod, desc)  desc,
#include "ErrorDefs.h"
#undef OD_ERROR_DEF

#define OD_MESSAGE_DEF(cod, desc) desc,
#include "MessageDefs.h"
#undef OD_MESSAGE_DEF
    OD_T("")// DummyLastMassage
  };

  OdString msg;
  if (code >= sidDummyLastMassage)
  {
    msg.format(OD_T("Unknown message (code: %d)"), code);
    return msg;
  }

  if (argList)
  {
    msg.formatV(message[code], *argList);
  }
  else msg = message[code];

  return msg;
}

OdCodePageId ExSystemServices::systemCodePage() const
{
  return m_CodePageId;
}

void ExSystemServices::setSystemCodePage(OdCodePageId id)
{
  m_CodePageId = id;
}

OdResult ExSystemServices::initModelerLibrary()
{
  return eNotImplemented;
}

OdResult ExSystemServices::uninitModelerLibrary()
{
  return eNotImplemented;
}
