#include <siaapi.h>
#include <regex>
#include <filepath.h>

using namespace Sia::Api;

CSiaApi::_CSiaFileTree::_CSiaFileTree(CSiaDriveConfig* siaDriveConfig) :
	CSiaBase(siaDriveConfig)
{
	
}

CSiaApi::_CSiaFileTree::~_CSiaFileTree()
{
	
}

void CSiaApi::_CSiaFileTree::BuildTree(const json& result)
{
  CSiaFileCollectionPtr fileList(new CSiaFileCollection());
	for (const auto& file : result["files"])
	{
		fileList->push_back(std::make_shared<CSiaFile>(&GetSiaDriveConfig(), file));
	}

  std::lock_guard<std::mutex> l(_updateMutex);
  _fileList = fileList;
}

bool CSiaApi::_CSiaFileTree::FileExists(const SString& siaPath)
{
  auto fileList = GetFileList();
	auto result = std::find_if(fileList->begin(), fileList->end(), [&](const CSiaFilePtr& item)->bool
	{
		return (item->GetSiaPath() == siaPath);
	});

	return (result != fileList->end());
}

CSiaFileCollectionPtr CSiaApi::_CSiaFileTree::GetFileList()
{
  std::lock_guard<std::mutex> l(_updateMutex);
  CSiaFileCollectionPtr ret(new CSiaFileCollection(*_fileList));
  return ret;
}

CSiaFilePtr CSiaApi::_CSiaFileTree::GetFile(const SString& siaPath)
{
  auto fileList = GetFileList();
	auto result = std::find_if(fileList->begin(), fileList->end(), [&](const CSiaFilePtr& item)->bool
	{
		return (item->GetSiaPath() == siaPath);
	});
	
	return ((result != fileList->end()) ? *result : nullptr);
}

CSiaFileCollection CSiaApi::_CSiaFileTree::Query(SString query)
{
  auto fileList = GetFileList();
	query = CSiaApi::FormatToSiaPath(query);
	query.Replace("*.*", "*").Replace(".", "\\.").Replace("*", "[^/]+").Replace("?", "[^/]?");
	std::wregex r(query.str());

	CSiaFileCollection ret;
	std::copy_if(fileList->begin(), fileList->end(), std::back_inserter(ret), [&](const CSiaFilePtr& v) -> bool
	{
		return std::regex_match(v->GetSiaPath().str(), r);
	});

	return std::move(ret);
}

std::vector<SString> CSiaApi::_CSiaFileTree::QueryDirectories(SString rootFolder)
{
  auto fileList = GetFileList();
	CSiaFileCollection col;
  rootFolder.Replace("/", "\\");
  if (!rootFolder.BeginsWith('\\'))
    rootFolder = '\\' + rootFolder;

	std::vector<SString> ret;
	std::for_each(fileList->begin(), fileList->end(), [&](const CSiaFilePtr& v)
	{
    SString path = ("\\" + FilePath(v->GetSiaPath()).RemoveFileName()).Replace("/", "\\");
    if (path.BeginsWith(rootFolder))
    {
      path = (rootFolder == "\\") ? path.SubString(1) : path.SubString(rootFolder.Length() + 1);
      if (path.Length())
      {
        auto splitPaths = path.Split('\\');
        if (splitPaths.size())
        {
          path = splitPaths[0];
          if (std::find(ret.begin(), ret.end(), path) == ret.end())
          {
            ret.push_back(path);
          }
        }
      }
    }
	});

	return std::move(ret);
}