/////////////////////////////////////////////////////////////////////////////// 
// 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"
#include "OdaCommon.h"
#include "ExPageController.h"
#include "DbSystemServices.h"
#include "DbDatabase.h"
#include "OdString.h"
#include "FlatMemStream.h"

//----------------------------------------------------------
//
// ExUnloadController
//
//----------------------------------------------------------
ExUnloadController::ExUnloadController()
  : m_pDb(0)
{
}

OdStreamBufPtr ExUnloadController::read(Key)
{
  ODA_FAIL(); return (OdStreamBuf*)0;
}

bool ExUnloadController::write(Key&, OdStreamBuf*)
{
  ODA_FAIL(); return false;
}

void ExUnloadController::setDatabase(OdDbDatabase* pDb) 
{
  m_pDb = pDb;
}

OdDbDatabase* ExUnloadController::database() 
{
  return m_pDb; 
}

int ExUnloadController::pagingType() const
{
  return OdDb::kUnload;
}



class MyPageStream : public OdStreamBuf
{
  OdFlatMemStreamPtr m_pMemStream;
  OdBinaryData          m_buff;

public:
  bool init(FILE* fp)
  {
    OdUInt32 len;
    if (fread(&len, 1, sizeof(OdUInt32), fp) != sizeof(OdUInt32))
      return false;

    m_buff.resize(len);
    if (fread(m_buff.asArrayPtr(), 1, len, fp) != len)
      return false;

    m_pMemStream = OdFlatMemStream::createNew(m_buff.asArrayPtr(), len);
    return true;
  }

  OdUInt8 getByte()
  {
    return m_pMemStream->getByte();
  }

  void getBytes(void* buffer, OdUInt32 nLen)
  {
    m_pMemStream->getBytes(buffer, nLen);
  }

  OdUInt64 seek(OdInt64 offset, OdDb::FilerSeekType whence)
  {
    return m_pMemStream->seek(offset, whence);
  } 

  OdUInt64 tell()
  {
    return m_pMemStream->tell();
  }


};

typedef OdSmartPtr<MyPageStream> MyPageStreamPtr;


//----------------------------------------------------------
//
// ExPageController
//
//----------------------------------------------------------
ExPageController::ExPageController()
  : m_fp(0)
{
}

ExPageController::~ExPageController()
{
  if (m_fp)
  {
    fclose(m_fp);
#if !defined(_WIN32_WCE)
     remove(m_fname.c_str());
#else
    OdString tmp(m_fname);
    if (!DeleteFile(tmp.c_str()))
    {
      throw OdError("DeleteFile : File not found");
    }
#endif
  }
}

OdStreamBufPtr ExPageController::read(Key key)
{
  //OdUInt32 nCountRes = 0;
  if (!m_fp)
    return (OdStreamBuf*)0;

  if (fseek(m_fp, key, SEEK_SET) != 0)
    return (OdStreamBuf*)0;

  MyPageStreamPtr pRet = OdRxObjectImpl<MyPageStream>::createObject();
  if (!pRet->init(m_fp))
    return (OdStreamBuf*)0;

  return pRet;
}

bool ExPageController::write(Key& key, OdStreamBuf* pStreamSrc)
{
  if (!m_fp)
    return false;

  if (fseek(m_fp, 0, SEEK_END) != 0)
    return false;

  key = ftell(m_fp);

  OdUInt32 len = (OdUInt32)pStreamSrc->length();
  if (fwrite(&len, 1, sizeof(OdUInt32), m_fp) != sizeof(OdUInt32))
    return false;

  m_buffTmp.resize(len);
  pStreamSrc->getBytes(m_buffTmp.asArrayPtr(), len);
  if (fwrite(m_buffTmp.asArrayPtr(), 1, len, m_fp) != len)
    return false;

  return true;
}

void ExPageController::setDatabase(OdDbDatabase* pDb)
{
  ExUnloadController::setDatabase(pDb);

  m_fname.format("page%lu.tmp", (OdUInt64)database());
  m_fp = fopen(m_fname.c_str(), "w+b");
  if ( !m_fp )
    throw OdError(eFileAccessErr);
}

int ExPageController::pagingType() const
{
  return OdDb::kPage | OdDb::kUnload;
}

