#include "SM_SysPch.h"
#include <windows.h>
#include <assert.h>
#include "MWinreg.h"



#define REGISTRY_CLASS HKEY_LOCAL_MACHINE

namespace MWinreg
{

  static char basepath[256];
  
  
  static bool open_keys(
    bool _create,
    HKEY _base, char const* _path, 
    HKEY* keys_, int* _nkeys_ )
  {
    assert( _path );
    assert( keys_ );
    assert( _nkeys_ && *_nkeys_>=1 );

    HKEY parent = _base;
    bool found = false;
    int nkeys = 0;
    char const* p = _path;
    if (*p==0)
      found = true;
    else
    while (*p)
    {
      char buff[256];
      char* b = buff;
      char* be = buff + sizeof(buff)-1;
      char const* x = p;
      while ( b<be && *p && *p!='/' && *p!='\\' ) *b++ = *p++;
      if (*p=='\\' || *p=='/') ++p;
      if (b==be) break;
      *b = 0;

      HKEY hkey;
      DWORD res;
      if (_create)
        res = RegCreateKeyEx( 
          parent, buff, 0, "",
          REG_OPTION_NON_VOLATILE,
          KEY_ALL_ACCESS, 0, &hkey, 0);
      else
        res = RegOpenKeyEx( parent, buff, 0, KEY_ALL_ACCESS, &hkey );
      if (res != ERROR_SUCCESS) break;
      parent = hkey;
      keys_[nkeys] = hkey;
      ++nkeys;
      if (*p==0)
        found = true;
      if (nkeys==*_nkeys_) break;
    }

    *_nkeys_ = nkeys;
    return found;
  }

  static void close_keys( HKEY* _keys, int _numkeys )
  {
    for ( int i=_numkeys-1; i>=0; --i )
      RegCloseKey( _keys[i] );
  }


  ////////////////////////////////////////////////////////////////////////

  bool initd = false;

  bool Init( char const* _basepath )
  {
    assert( !initd );
    assert( _basepath );
    assert( _basepath[0] );
    CopyMemory( basepath, _basepath, lstrlen(_basepath)+1 );

    // falla si _basepath no existe ya
    HKEY keys[32];
    int nkeys = 32;
    bool res = open_keys( false, REGISTRY_CLASS, _basepath, keys, &nkeys );
    close_keys( keys, nkeys );

    initd = true;
    return res;
  }


  void Shutdown()
  {
    if (initd)
    {
      basepath[0] = 0;
      initd = false;
    }
  }


  bool ReadString( 
    char const* _keypath, char const* _valname, 
    char* buff_, int _buffsize )
  {
    assert( initd );
    assert( _keypath );
    assert( _valname && _valname[0] );

    HKEY keys[32];
    int nkeys1 = sizeof(keys)/sizeof(keys[0]);
    bool res = open_keys(false,REGISTRY_CLASS,basepath,keys,&nkeys1);
    if (res)
    {
      int nkeys2 = sizeof(keys)/sizeof(keys[0])-nkeys1;
      res = open_keys(false,keys[nkeys1-1],_keypath,keys+nkeys1,&nkeys2);
      nkeys1 += nkeys2;
      if (res)
      {
        DWORD bufsize = DWORD(_buffsize);
        DWORD type;
        res = (ERROR_SUCCESS==RegQueryValueEx( 
          keys[nkeys1-1], _valname, 0, &type, (unsigned char*)buff_, &bufsize ));
        res = res && (type==REG_SZ);
      }
    }
    close_keys( keys, nkeys1 );
    return res;
  }


  void WriteString( 
    char const* _keypath, char const* _valname, 
    char const* _buff )
  {
    assert( initd );
    assert( _keypath );
    assert( _valname && _valname[0] );

    HKEY keys[32];
    int nkeys1 = sizeof(keys)/sizeof(keys[0]);
    bool res = open_keys(true,REGISTRY_CLASS,basepath,keys,&nkeys1);
    if (res)
    {
      int nkeys2 = sizeof(keys)/sizeof(keys[0])-nkeys1;
      res = open_keys(true,keys[nkeys1-1],_keypath,keys+nkeys1,&nkeys2);
      nkeys1 += nkeys2;
      if (res)
      {
        res = (ERROR_SUCCESS==RegSetValueEx( 
          keys[nkeys1-1], _valname, 0, REG_SZ, (unsigned char*)_buff, lstrlen(_buff)+1 ));
      }
    }
    close_keys( keys, nkeys1 );
  }


  bool ReadInt( 
    char const* _keypath, char const* _valname, 
    int* val_ )
  {
    assert( initd );
    assert( _keypath );
    assert( _valname && _valname[0] );

    HKEY keys[32];
    int nkeys1 = sizeof(keys)/sizeof(keys[0]);
    bool res = open_keys(false,REGISTRY_CLASS,basepath,keys,&nkeys1);
    if (res)
    {
      int nkeys2 = sizeof(keys)/sizeof(keys[0])-nkeys1;
      res = open_keys(false,keys[nkeys1-1],_keypath,keys+nkeys1,&nkeys2);
      nkeys1 += nkeys2;
      if (res)
      {
        DWORD bufsize = sizeof(*val_);
        DWORD type;
        res = (ERROR_SUCCESS==RegQueryValueEx( 
          keys[nkeys1-1], _valname, 0, &type, (unsigned char*)val_, &bufsize ));
        res = res && (type==REG_DWORD);
      }
    }
    close_keys( keys, nkeys1 );
    return res;
  }


  void WriteInt( 
    char const* _keypath, char const* _valname, 
    int _val )
  {
    assert( initd );
    assert( _keypath );
    assert( _valname && _valname[0] );

    HKEY keys[32];
    int nkeys1 = sizeof(keys)/sizeof(keys[0]);
    bool res = open_keys(true,REGISTRY_CLASS,basepath,keys,&nkeys1);
    if (res)
    {
      int nkeys2 = sizeof(keys)/sizeof(keys[0])-nkeys1;
      res = open_keys(true,keys[nkeys1-1],_keypath,keys+nkeys1,&nkeys2);
      nkeys1 += nkeys2;
      if (res)
      {
        res = (ERROR_SUCCESS==RegSetValueEx( 
          keys[nkeys1-1], _valname, 0, REG_DWORD, (unsigned char*)&_val, sizeof(_val) ));
      }
    }
    close_keys( keys, nkeys1 );
  }


  bool ReadBin( 
    char const* _keypath, char const* _valname, 
    char* buff_, int* _buffsize_ )
  {
    assert( initd );
    assert( _keypath );
    assert( _valname && _valname[0] );

    HKEY keys[32];
    int nkeys1 = sizeof(keys)/sizeof(keys[0]);
    bool res = open_keys(false,REGISTRY_CLASS,basepath,keys,&nkeys1);
    if (res)
    {
      int nkeys2 = sizeof(keys)/sizeof(keys[0])-nkeys1;
      res = open_keys(false,keys[nkeys1-1],_keypath,keys+nkeys1,&nkeys2);
      nkeys1 += nkeys2;
      if (res)
      {
        DWORD bufsize = *_buffsize_;
        DWORD type;
        res = (ERROR_SUCCESS==RegQueryValueEx( 
          keys[nkeys1-1], _valname, 0, &type, (unsigned char*)buff_, &bufsize ));
        *_buffsize_ = bufsize;
        res = res && (type==REG_BINARY);
      }
    }
    close_keys( keys, nkeys1 );
    return res;
  }


  void WriteBin( 
    char const* _keypath, char const* _valname, 
    char const* _buff, int _buffsize )
  {
    assert( initd );
    assert( _keypath );
    assert( _valname && _valname[0] );

    HKEY keys[32];
    int nkeys1 = sizeof(keys)/sizeof(keys[0]);
    bool res = open_keys(true,REGISTRY_CLASS,basepath,keys,&nkeys1);
    if (res)
    {
      int nkeys2 = sizeof(keys)/sizeof(keys[0])-nkeys1;
      res = open_keys(true,keys[nkeys1-1],_keypath,keys+nkeys1,&nkeys2);
      nkeys1 += nkeys2;
      if (res)
      {
        res = (ERROR_SUCCESS==RegSetValueEx( 
          keys[nkeys1-1], _valname, 0, REG_BINARY, (unsigned char*)_buff, _buffsize ));
      }
    }
    close_keys( keys, nkeys1 );
 }


}