// ExtractingFilePath.cpp

#include "StdAfx.h"

#include "../../../Common/Wildcard.h"

#include "../../../Windows/FileName.h"

#include "ExtractingFilePath.h"

static UString ReplaceIncorrectChars(const UString &s, bool repaceColon)
{
  #ifdef _WIN32
  UString res;
  bool beforeColon = true;
  {
    for (unsigned i = 0; i < s.Len(); i++)
    {
      wchar_t c = s[i];
      if (beforeColon)
        if (c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"')
          c = '_';
      if (c == ':')
      {
        if (repaceColon)
          c = '_';
        else
          beforeColon = false;
      }
      res += c;
    }
  }
  if (beforeColon)
  {
    for (int i = res.Len() - 1; i >= 0; i--)
    {
      wchar_t c = res[i];
      if (c != '.' && c != ' ')
        break;
      res.ReplaceOneCharAtPos(i, '_');
    }
  }
  return res;
  #else
  return s;
  #endif
}

#ifdef _WIN32

static const wchar_t *g_ReservedNames[] =
{
  L"CON", L"PRN", L"AUX", L"NUL"
};

static bool CheckTail(const UString &name, unsigned len)
{
  int dotPos = name.Find(L'.');
  if (dotPos < 0)
    dotPos = name.Len();
  UString s = name.Left(dotPos);
  s.TrimRight();
  return s.Len() != len;
}

static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
{
  unsigned len = MyStringLen(reservedName);
  if (name.Len() <= len)
    return true;
  if (MyStringCompareNoCase_N(name, reservedName, len) != 0)
    return true;
  wchar_t c = name[len];
  if (c < L'0' || c > L'9')
    return true;
  return CheckTail(name, len + 1);
}

static bool IsSupportedName(const UString &name)
{
  for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++)
  {
    const wchar_t *reservedName = g_ReservedNames[i];
    unsigned len = MyStringLen(reservedName);
    if (name.Len() < len)
      continue;
    if (MyStringCompareNoCase_N(name, reservedName, len) != 0)
      continue;
    if (!CheckTail(name, len))
      return false;
  }
  if (!CheckNameNum(name, L"COM"))
    return false;
  return CheckNameNum(name, L"LPT");
}

#endif

static UString GetCorrectFileName(const UString &path, bool repaceColon)
{
  if (path == L".." || path == L".")
    return UString();
  return ReplaceIncorrectChars(path, repaceColon);
}

void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon)
{
  for (unsigned i = 0; i < pathParts.Size();)
  {
    UString &s = pathParts[i];
    #ifdef _WIN32
    bool needReplaceColon = (replaceAltStreamColon || i != pathParts.Size() - 1);
    if (i == 0 && isPathFromRoot && NWindows::NFile::NName::IsDrivePath(s))
    {
      UString s2 = s[0];
      s2 += L'_';
      s2 += GetCorrectFileName(s.Ptr(2), needReplaceColon);
      s = s2;
    }
    else
      s = GetCorrectFileName(s, needReplaceColon);
    #endif

    if (s.IsEmpty())
      pathParts.Delete(i);
    else
    {
      #ifdef _WIN32
      if (!IsSupportedName(s))
        s = (UString)L"_" + s;
      #endif
      i++;
    }
  }
}

UString MakePathNameFromParts(const UStringVector &parts)
{
  UString result;
  FOR_VECTOR (i, parts)
  {
    if (i != 0)
      result += WCHAR_PATH_SEPARATOR;
    result += parts[i];
  }
  return result;
}

static const wchar_t *k_EmptyReplaceName = L"[]";

void Correct_IfEmptyLastPart(UStringVector &parts)
{
  if (parts.IsEmpty())
    parts.Add(k_EmptyReplaceName);
  else
  {
    UString &s = parts.Back();
    if (s.IsEmpty())
      s = k_EmptyReplaceName;
  }
}

UString GetCorrectFsPath(const UString &path)
{
  UString res = GetCorrectFileName(path, true);
  #ifdef _WIN32
  if (!IsSupportedName(res))
    res = (UString)L"_" + res;
  #endif
  if (res.IsEmpty())
    res = k_EmptyReplaceName;
  return res;
}

UString GetCorrectFullFsPath(const UString &path)
{
  UStringVector parts;
  SplitPathToParts(path, parts);
  FOR_VECTOR (i, parts)
  {
    UString &s = parts[i];
    #ifdef _WIN32
    while (!s.IsEmpty() && (s.Back() == '.' || s.Back() == ' '))
      s.DeleteBack();
    if (!IsSupportedName(s))
      s.InsertAtFront(L'_');
    #endif
  }
  return MakePathNameFromParts(parts);
}
