//
// Copyright (C) 2000, 2001, 2002 Andrey Slepuhin <pooh@msu.ru>
//
// libp++ is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// libp++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libp++; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// $Source$
// $Revision$
// $Date$
// Author: Andrey Slepuhin <pooh@msu.ru>

#ifdef WINDOWS
#include <windows.h>    // for SYSTEM_INFO
#include <mbctype.h>    // for _setmbcp()
#else
#include <unistd.h>
#endif

#include "pxx_common.ih"
#include "pxx_exception.hh"
#include "pxx_sys_error.ih"

#include <stdarg.h>
#include <locale.h>
#include <typeinfo>

namespace pxx
{

unsigned debug_level = 0 ;

void (*terminate) (int _error_code) = null ;

void terminate_handler ()
{
  try {
    throw;
  } catch (SysError& e) {
    e.print();
    exit(e.get_code());
  } catch (Exception& e) {
    fprintf(stderr, "Caught exception:\n");
    e.print();
    exit(-1);
  } catch (...) {
    FATAL("Unknown exception thrown");
  }
}

void fatal (char const* _fmt, ...)
{
  va_list ap;
  va_start(ap, _fmt);
  vfprintf(stderr, _fmt, ap);
  fprintf(stderr, "\n");
  va_end(ap);
  if (terminate != null) (*terminate)(-1);
  else exit(-1);
}

void dprint (unsigned _level, char const* _fmt, ...) {
  if ((debug_level & _level) != 0) {
    va_list ap;
    va_start(ap, _fmt);
    vfprintf(stderr, _fmt, ap);
    va_end(ap);
  }
}

//
// Internal class used to initialize necessary data
class Init
{

public:

  size_t page_size ;
  size_t orders[256] ;
  size_t exps_of_two[sizeof(size_t) * 8] ;


  Init ()
  {
#ifdef WINDOWS
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    page_size = sysInfo.dwPageSize;
#else
    page_size = getpagesize();
#endif
    std::set_terminate(terminate_handler);
    unsigned i;
    orders[0] = 0;
    for (i = 1; i < 256; i++) {
      unsigned s = i;
      orders[i] = 0;
      while (s) {
        s >>= 1;
        orders[i]++;
      }
      orders[i]--;
    }
    for (i = 0; i < sizeof(exps_of_two) / sizeof(exps_of_two[0]); i++) {
      exps_of_two[i] = 1UL << i;
    }

    char* s = setlocale(LC_ALL, "");
#ifdef WINDOWS
//    s = setlocale(LC_ALL, "C");
    _setmbcp(_MB_CP_LOCALE);
#endif
    if (!s)
      fprintf(stderr, "Warning: can't switch to the desired locale!");
  }

};

Init init /* __attribute__ ((init_priority (101))) */ ;
//Init* __pinit = &init ;

size_t& page_size = init.page_size ;
size_t (&orders)[256] = init.orders ;
size_t (&exps_of_two)[sizeof(size_t) * 8] = init.exps_of_two ;

}
