/* ====================================================================
 * Copyright (c) 2003-2006, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "File.h"
#include "Memory.h"
#include "apr.h"
#include "AprError.h"
#include "Error.h"

// apr
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_file_io.h>
#include <apr_file_info.h>
#include <apr_mmap.h>

// sys
#include <assert.h>



File::File( const char* file, apr_pool_t* pool )
: _open(false), _file(0), _mmaped(false), _mmap(0) 
{
  _pool = apr::createPool(pool);

  _filename = apr_pstrdup( _pool, file );
  assert(_filename);

  _finfo = (apr_finfo_t*)apr_pcalloc( _pool, sizeof(apr_finfo_t) );
  assert(_finfo);
}

File::~File()
{
  apr::destroyPool(_pool);
}


const sc::Error* File::open()
{
  apr_status_t status = apr_file_open( &_file, _filename, APR_READ, APR_OS_DEFAULT, _pool );
  APR_ERR(status);

  _open = true;
  return sc::Success;
}

const sc::Error* File::close()
{
  if( _open )
  {
    _open = false;
    apr_status_t status = apr_file_close(_file);
    APR_ERR(status);
  }
  return sc::Success;
}

const sc::Error* File::mmap()
{
  apr_status_t status;

  status = apr_file_info_get( _finfo, APR_FINFO_SIZE, _file );
  APR_ERR(status);

  _mmap = (apr_mmap_t*)apr_pcalloc( _pool, sizeof(apr_mmap_t) );
  assert(_mmap);

  status = apr_mmap_create( &_mmap, _file, 0, (apr_size_t)_finfo->size, APR_MMAP_READ, _pool );
  APR_ERR(status);

  _mmaped = true;
  return sc::Success;
}

const sc::Error* File::unmmap()
{
  _mmaped = false;

  apr_status_t status = apr_mmap_delete(_mmap);
  APR_ERR(status);

  return sc::Success;
}

bool File::ismmaped() const
{
  return _mmaped;
}

void* File::mmaped() const
{
  return _mmap->mm;
}

bool File::exists()
{
  if( ! _open )
  {
    const sc::Error* error = open();
    if( error )
    {
      delete error;
      return false;
    }
    close();
  }

  return true;

#if 0
 apr_status_t status = apr_file_info_get( _finfo, APR_FINFO_TYPE, _file );
 if( status != APR_SUCCESS )
 {
   return false;
 }

  return true;
#endif
}

sc_size_t File::getSize() const
{
  apr_status_t status;

  status = apr_file_info_get( _finfo, APR_FINFO_SIZE, _file );
 if( status != APR_SUCCESS )
 {
   // maybe throw AprException...!?
   return -1;
 }

 return _finfo->size;
}


