/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the Collabora Office project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <vcl/UserResourceScanner.hxx>

#include <sal/config.h>
#include <sal/log.hxx>

#include <salhelper/linkhelper.hxx>
#include <unotools/pathoptions.hxx>
#include <o3tl/string_view.hxx>

#include <deque>

namespace vcl
{
namespace
{
OUString convertToAbsolutePath(const OUString& path)
{
    salhelper::LinkResolver resolver(0);
    osl::FileBase::RC rc = resolver.fetchFileStatus(path);
    if (rc != osl::FileBase::E_None)
    {
        SAL_INFO("vcl.app", "Could not resolve path '" << path << "' to search for icon themes.");
        if (rc == osl::FileBase::E_MULTIHOP)
        {
            throw std::runtime_error("Provided a recursive symlink to an icon theme directory that "
                                     "could not be resolved.");
        }
    }
    return resolver.m_aStatus.getFileURL();
}
}

namespace file
{
// read the status of a file. Returns false if the status could not be determined.
bool readFileStatus(osl::FileStatus& status, const OUString& file)
{
    osl::DirectoryItem dirItem;
    osl::FileBase::RC retvalGet = osl::DirectoryItem::get(file, dirItem);
    if (retvalGet != osl::FileBase::E_None)
    {
        if (retvalGet == osl::FileBase::E_NOENT)
            SAL_INFO("vcl.app", "Directory doesn't exist '" << file << "'.");
        else
            SAL_INFO("vcl.app", "Could not determine status for file '"
                                    << file << "' Return code: '" << retvalGet << "'.");
        return false;
    }
    osl::FileBase::RC retvalStatus = dirItem.getFileStatus(status);
    if (retvalStatus != osl::FileBase::E_None)
    {
        SAL_INFO("vcl.app", "Could not determine status for file '" << file << "'.");
        return false;
    }
    return true;
}

void splitPathString(std::u16string_view aPathString, std::deque<OUString>& rPaths)
{
    sal_Int32 nIndex = 0;
    do
    {
        rPaths.push_front(OUString(o3tl::getToken(aPathString, 0, ';', nIndex)));
    } while (nIndex >= 0);
}
}

UserResourceScanner::UserResourceScanner() = default;

void UserResourceScanner::addPaths(std::u16string_view aPathString)
{
    std::deque<OUString> aPaths;
    vcl::file::splitPathString(aPathString, aPaths);

    for (const auto& path : aPaths)
    {
        osl::FileStatus aFileStatus(osl_FileStatus_Mask_Type);

        if (!vcl::file::readFileStatus(aFileStatus, path))
            continue;

        if (!aFileStatus.isDirectory())
        {
            SAL_INFO("vcl.app", "Can not search for resource files in '"
                                    << path << "'. It is not a directory.");
            continue;
        }

        std::vector<OUString> aResourcePaths = readFilesFromPath(path);

        if (aResourcePaths.empty())
        {
            SAL_INFO("vcl.app",
                     "Could not find any file in the provided directory ('" << path << "'.");
            continue;
        }

        for (auto const& iconThemePath : aResourcePaths)
            addResource(iconThemePath);
    }
}

std::vector<OUString> UserResourceScanner::readFilesFromPath(const OUString& dir)
{
    std::vector<OUString> found;
    SAL_INFO("vcl", "Scanning directory '" << dir << " for potential resource files.");

    osl::Directory dirToScan(dir);
    osl::FileBase::RC retvalOpen = dirToScan.open();
    if (retvalOpen != osl::FileBase::E_None)
        return found;

    osl::DirectoryItem directoryItem;
    while (dirToScan.getNextItem(directoryItem) == osl::FileBase::E_None)
    {
        osl::FileStatus status(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL
                               | osl_FileStatus_Mask_FileName);
        osl::FileBase::RC retvalStatus = directoryItem.getFileStatus(status);
        if (retvalStatus != osl::FileBase::E_None)
            continue;

        OUString filename = convertToAbsolutePath(status.getFileURL());
        if (isValidResource(filename))
            found.push_back(filename);
    }

    return found;
}

} // end namespace vcl

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
