// SPDX-License-Identifier: GPL-3.0-only
/*
 *  Prism Launcher - Minecraft Launcher
 *  Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, version 3.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#pragma once

#include <QFileInfo>
#include <QSaveFile>
#include "Application.h"

#if defined(LAUNCHER_APPLICATION)

/* PSaveFile
 * A class that mimics QSaveFile for Windows.
 *
 * When reading resources, we need to avoid accessing temporary files
 * generated by QSaveFile. If we start reading such a file, we may
 * inadvertently keep it open while QSaveFile is trying to remove it,
 * or we might detect the file just before it is removed, leading to
 * race conditions and errors.
 *
 * Unfortunately, QSaveFile doesn't provide a way to retrieve the
 * temporary file name or to set a specific template for the temporary
 * file name it uses. By default, QSaveFile appends a `.XXXXXX` suffix
 * to the original file name, where the `XXXXXX` part is dynamically
 * generated to ensure uniqueness.
 *
 * This class acts like a lock by adding and removing the target file
 * name into/from a global string set, helping to manage access to
 * files during critical operations.
 *
 * Note: Please do not use the `setFileName` function directly, as it
 * is not virtual and cannot be overridden.
 */
class PSaveFile : public QSaveFile {
   public:
    PSaveFile(const QString& name) : QSaveFile(name) { addPath(name); }
    PSaveFile(const QString& name, QObject* parent) : QSaveFile(name, parent) { addPath(name); }
    virtual ~PSaveFile()
    {
        if (auto app = APPLICATION_DYN) {
            app->removeQSavePath(m_absoluteFilePath);
        }
    }

   private:
    void addPath(const QString& path)
    {
        m_absoluteFilePath = QFileInfo(path).absoluteFilePath() + ".";  // add dot for tmp files only
        if (auto app = APPLICATION_DYN) {
            app->addQSavePath(m_absoluteFilePath);
        }
    }
    QString m_absoluteFilePath;
};
#else
#define PSaveFile QSaveFile
#endif