// ParseProperties.cpp

#include "StdAfx.h"

#include "ParseProperties.h"

#include "Common/StringToInt.h"
#include "Common/MyCom.h"

HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
{
  if (prop.vt == VT_UI4)
  {
    if (!name.IsEmpty())
      return E_INVALIDARG;
    resValue = prop.ulVal;
  }
  else if (prop.vt == VT_EMPTY)
  {
    if(!name.IsEmpty())
    {
      const wchar_t *start = name;
      const wchar_t *end;
      UInt64 v = ConvertStringToUInt64(start, &end);
      if (end - start != name.Length())
        return E_INVALIDARG;
      resValue = (UInt32)v;
    }
  }
  else
    return E_INVALIDARG;
  return S_OK;
}

static const int kLogarithmicSizeLimit = 32;
static const wchar_t kByteSymbol = L'B';
static const wchar_t kKiloByteSymbol = L'K';
static const wchar_t kMegaByteSymbol = L'M';

HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize)
{
  UString srcString = srcStringSpec;
  srcString.MakeUpper();

  const wchar_t *start = srcString;
  const wchar_t *end;
  UInt64 number = ConvertStringToUInt64(start, &end);
  int numDigits = (int)(end - start);
  if (numDigits == 0 || srcString.Length() > numDigits + 1)
    return E_INVALIDARG;
  if (srcString.Length() == numDigits)
  {
    if (number >= kLogarithmicSizeLimit)
      return E_INVALIDARG;
    dicSize = (UInt32)1 << (int)number;
    return S_OK;
  }
  switch (srcString[numDigits])
  {
    case kByteSymbol:
      if (number >= ((UInt64)1 << kLogarithmicSizeLimit))
        return E_INVALIDARG;
      dicSize = (UInt32)number;
      break;
    case kKiloByteSymbol:
      if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 10)))
        return E_INVALIDARG;
      dicSize = (UInt32)(number << 10);
      break;
    case kMegaByteSymbol:
      if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 20)))
        return E_INVALIDARG;
      dicSize = (UInt32)(number << 20);
      break;
    default:
      return E_INVALIDARG;
  }
  return S_OK;
}

HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
{
  if (name.IsEmpty())
  {
    if (prop.vt == VT_UI4)
    {
      UInt32 logDicSize = prop.ulVal;
      if (logDicSize >= 32)
        return E_INVALIDARG;
      resValue = (UInt32)1 << logDicSize;
      return S_OK;
    }
    if (prop.vt == VT_BSTR)
      return ParsePropDictionaryValue(prop.bstrVal, resValue);
    return E_INVALIDARG;
  }
  return ParsePropDictionaryValue(name, resValue);
}

bool StringToBool(const UString &s, bool &res)
{
  if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0)
  {
    res = true;
    return true;
  }
  if (s.CompareNoCase(L"OFF") == 0)
  {
    res = false;
    return true;
  }
  return false;
}

HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value)
{
  switch(value.vt)
  {
    case VT_EMPTY:
      dest = true;
      return S_OK;
    /*
    case VT_UI4:
      dest = (value.ulVal != 0);
      break;
    */
    case VT_BSTR:
      return StringToBool(value.bstrVal, dest) ?  S_OK : E_INVALIDARG;
  }
  return E_INVALIDARG;
}

int ParseStringToUInt32(const UString &srcString, UInt32 &number)
{
  const wchar_t *start = srcString;
  const wchar_t *end;
  UInt64 number64 = ConvertStringToUInt64(start, &end);
  if (number64 > 0xFFFFFFFF) 
  {
    number = 0;
    return 0;
  }
  number = (UInt32)number64;
  return (int)(end - start);
}

HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
{
  if (name.IsEmpty())
  {
    switch(prop.vt)
    {
      case VT_UI4:
        numThreads = prop.ulVal;
        break;
      default:
      {
        bool val; 
        RINOK(SetBoolProperty(val, prop));
        numThreads = (val ? defaultNumThreads : 1);
        break;
      }
    }
  }
  else
  {
    UInt32 number;
    int index = ParseStringToUInt32(name, number);
    if (index != name.Length())
      return E_INVALIDARG;
    numThreads = number;
  }
  return S_OK;
}
