/* This file is part of Lcrzo.
*/

#if defined LCRZODEF_SYSTEM_Unix
 /* do no need these functions */
#elif defined LCRZODEF_SYSTEM_Windows

/*-------------------------------------------------------------*/
int lcrzo_priv_winreg_uint32_get(HKEY hive,
                                 lcrzo_conststring key,
                                 lcrzo_conststring name,
                                 lcrzo_uint32 *pvalue)
{ HKEY hivekey;
  DWORD type;
  lcrzo_uint32 value, valuesize;
  int ret;

  /* get value from registery */
  ret=RegOpenKeyEx(hive, key, 0, KEY_READ, &hivekey);
  if ( ret != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGOPENKEYEX);
  valuesize=sizeof(lcrzo_uint32);
  ret=RegQueryValueEx(hivekey, name, NULL, &type, (LPBYTE)&value, &valuesize);
  if ( ret != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGQUERYVALUEEX);
  if ( type != REG_DWORD )
    return(LCRZO_ERR_SPREGBADTYPE);
  ret=RegCloseKey(hivekey);
  if ( ret != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGCLOSEKEY);
  
  /* set output value */
  if (pvalue!=NULL) *pvalue=value;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_winreg_data_get(HKEY hive,
                               lcrzo_conststring key,
                               lcrzo_conststring name,
                               lcrzo_data *pvalue,
                               lcrzo_int32 *pvaluesize)
{ HKEY hivekey;
  DWORD type;
  lcrzo_data value;
  lcrzo_uint32 valuesize;
  lcrzo_string errmsg;
  lcrzo_int16 language;
  int ret;

  /* get value from registery */
  ret=RegOpenKeyEx(hive, key, 0, KEY_READ, &hivekey);
  if ( ret != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGOPENKEYEX);
  /* get the size of the value of this key */
  ret=RegQueryValueEx(hivekey, name, NULL, &type, NULL, &valuesize);
  if ( ret != ERROR_SUCCESS )
  { RegCloseKey(hivekey);
    return(LCRZO_ERR_FUREGQUERYVALUEEX);
  }
  if ( type!=REG_BINARY && type!=REG_SZ )
  { lcrzo_er(lcrzo_global_get_language(&language));
    if (language==LCRZO_GLOBAL_LANG_FR)
      lcrzo_string_initm_text("Le type de la cle n'est pas REG_BINARY, REG_SZ : ", &errmsg);
    else
      lcrzo_string_initm_text("The key type is not REG_BINARY, REG_SZ : ", &errmsg);
    lcrzo_string_appendm_int(type, "%d", &errmsg);
    lcrzo_priv_global_set_errmsglcrzo(errmsg);
    lcrzo_string_free(errmsg);
    return(LCRZO_ERR_SPREGBADTYPE);
  }
  lcrzo_er(lcrzo_data_alloc(valuesize, &value));
  ret=RegQueryValueEx(hivekey, name, NULL, NULL, (LPBYTE)value, &valuesize);
  if ( ret != ERROR_SUCCESS )
  { lcrzo_data_free(value);
    return(LCRZO_ERR_FUREGQUERYVALUEEX);
  }
  ret=RegCloseKey(hivekey);
  if ( ret != ERROR_SUCCESS )
  { lcrzo_data_free(value);
    return(LCRZO_ERR_FUREGCLOSEKEY);
  }
  
  /* set output value */
  if (pvalue!=NULL)
  { *pvalue=value;
  }
  else
  { lcrzo_data_free(value);
  }
  if (pvaluesize!=NULL)
  { if ( type==REG_SZ && valuesize!=0 ) *pvaluesize=valuesize-1;
    else *pvaluesize=valuesize;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_winreg_datalist_get(HKEY hive,
                                   lcrzo_conststring key,
                                   lcrzo_conststring name,
                                   lcrzo_list *plist)
{ HKEY hivekey;
  DWORD type;
  lcrzo_data value;
  lcrzo_uint32 valuesize, itemsize, n;
  int ret;

  /* initialize list */
  lcrzo_er(lcrzo_datalist_init(plist));

  /* get value from registery */
  ret=RegOpenKeyEx(hive, key, 0, KEY_READ, &hivekey);
  if ( ret != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGOPENKEYEX);
  /* get the size of the value of this key */
  ret=RegQueryValueEx(hivekey, name, NULL, &type, NULL, &valuesize);
  if ( ret != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGQUERYVALUEEX);
  if ( type != REG_MULTI_SZ )
    return(LCRZO_ERR_SPREGBADTYPE);
  lcrzo_er(lcrzo_data_alloc(valuesize, &value));
  ret=RegQueryValueEx(hivekey, name, NULL, NULL, (LPBYTE)value, &valuesize);
  if ( ret != ERROR_SUCCESS )
  { lcrzo_data_free(value);
    return(LCRZO_ERR_FUREGQUERYVALUEEX);
  }
  ret=RegCloseKey(hivekey);
  if ( ret != ERROR_SUCCESS )
  { lcrzo_data_free(value);
    return(LCRZO_ERR_FUREGCLOSEKEY);
  }

  /* convert value in a list of items */  
  n=0;
  while (n<valuesize)
  { itemsize=strlen((lcrzo_string)value+n);
    if (itemsize==0) break;
    lcrzo_efr(lcrzo_datalist_add_pos(plist, -1, 0, value+n, itemsize), lcrzo_data_free(value));
    n+=itemsize+1;
  }

  lcrzo_data_free(value);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_winreg_subkeylist_get(HKEY hive,
                                     lcrzo_conststring key,
                                     lcrzo_list *plist)
{ HKEY hivekey;
  DWORD i, MaxSubKeyLen;
  lcrzo_string keyname;
  lcrzo_string longkeyname;
  int ret;
  BOOL err;

  /* get value from registery */
  err=RegOpenKeyEx(hive, key, 0, KEY_READ, &hivekey);
  if ( err != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGOPENKEYEX);

  /* get the longest subkey name */
  err=RegQueryInfoKey(hivekey, NULL, NULL, NULL, NULL, &MaxSubKeyLen,
	                  NULL,    NULL, NULL, NULL, NULL, NULL);
  if ( err != ERROR_SUCCESS )
    ret=LCRZO_ERR_FUREGQUERYINFOKEY;
  else
  { /* initialize list */
    ret=lcrzo_datalist_init(plist);
    if (ret==LCRZO_ERR_OK)
    { /* allocate data to store key names */
      ret=lcrzo_string_alloc(MaxSubKeyLen, &keyname);
      if (ret==LCRZO_ERR_OK)
	  { /* list the subkeys */
        i=0;
		while(LCRZO_TRUE)
		{ /* find it */
	      err=RegEnumKey(hivekey, i, keyname, MaxSubKeyLen+1);
          if ( err==ERROR_NO_MORE_ITEMS )
		  { ret=LCRZO_ERR_OK;
	        break;
		  }
          else if ( err!=ERROR_SUCCESS )
		  { ret=LCRZO_ERR_FUREGENUMKEY;
		    break;
		  }
          /* create the long name */
		  ret=lcrzo_string_initm_text(key, &longkeyname);
		  if (ret==LCRZO_ERR_OK)
		  { ret=lcrzo_string_appendm_text("\\", &longkeyname);
		    if (ret==LCRZO_ERR_OK)
			{ ret=lcrzo_string_appendm_text(keyname, &longkeyname);
		      if (ret==LCRZO_ERR_OK)
			  { /* add it */
                ret=lcrzo_datalist_add_pos(plist, -1, 0, (lcrzo_data)longkeyname, strlen(longkeyname)+1);
			  }
			}
			lcrzo_string_free(longkeyname);
		  }
		  if (ret!=LCRZO_ERR_OK) break;
		  i++;
		}
		/* free */
        lcrzo_string_free(keyname);
	  }
	  /* free list only on errors */
      if (ret!=LCRZO_ERR_OK)
	  { lcrzo_list_close(plist);
	  }
	}
  }

  /* close the registery */
  err=RegCloseKey(hivekey);
  if ( err != ERROR_SUCCESS )
  { return(LCRZO_ERR_FUREGCLOSEKEY);
  }

  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_winreg_subvallist_get(HKEY hive,
                                     lcrzo_conststring key,
                                     lcrzo_list *plist)
{ HKEY hivekey;
  DWORD i, MaxValueNameLen, valuenamesize;
  lcrzo_data valuename;
  int ret;
  BOOL err;

  /* get value from registery */
  err=RegOpenKeyEx(hive, key, 0, KEY_READ, &hivekey);
  if ( err != ERROR_SUCCESS )
    return(LCRZO_ERR_FUREGOPENKEYEX);

  /* get the longest value name */
  err=RegQueryInfoKey(hivekey, NULL, NULL, NULL, NULL, NULL,
	                  NULL,    NULL, &MaxValueNameLen, NULL, NULL, NULL);
  if ( err != ERROR_SUCCESS )
    ret=LCRZO_ERR_FUREGQUERYINFOKEY;
  else
  { /* initialize list */
    ret=lcrzo_datalist_init(plist);
    if (ret==LCRZO_ERR_OK)
    { /* allocate data to store value names */
	  /*printf("MaxValueNameLen=%d\n", MaxValueNameLen);*/
      ret=lcrzo_data_alloc(MaxValueNameLen, &valuename);
      if (ret==LCRZO_ERR_OK)
	  { /* list the subkeys */
        i=0;
		while(LCRZO_TRUE)
		{ /* find it */
          valuenamesize=MaxValueNameLen+1;
	      err=RegEnumValue(hivekey, i, (lcrzo_string)valuename, &valuenamesize, NULL, NULL, NULL, NULL);
          if ( err==ERROR_NO_MORE_ITEMS )
		  { ret=LCRZO_ERR_OK;
	        break;
		  }
          else if ( err!=ERROR_SUCCESS )
		  { ret=LCRZO_ERR_FUREGENUMVALUE;
		    break;
		  }
		  valuename[valuenamesize]='\0';
		  /* add it */
          ret=lcrzo_datalist_add_pos(plist, -1, 0, valuename, valuenamesize+1);
		  if (ret!=LCRZO_ERR_OK) break;
		  i++;
		}
		/* free */
        lcrzo_data_free(valuename);
	  }
	  /* free list only on errors */
      if (ret!=LCRZO_ERR_OK)
	  { lcrzo_list_close(plist);
	  }
	}
  }

  /* close the registery */
  err=RegCloseKey(hivekey);
  if ( err != ERROR_SUCCESS )
  { return(LCRZO_ERR_FUREGCLOSEKEY);
  }

  return(ret);
}

#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
