/**
 * UGENE - Integrated Bioinformatics Tools.
 * Copyright (C) 2008-2023 UniPro <ugene@unipro.ru>
 * http://ugene.net
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#pragma once

#include <QSet>
#include <QStringList>
#include <QUrl>

#include <U2Core/GUrl.h>
#include <U2Core/global.h>

namespace U2 {

class TaskStateInfo;
class Logger;
class U2OpStatus;

/* Maximum file name length for Linux, Windows and MacOS X is 255 characters. */
#define MAX_OS_FILE_NAME_LENGTH 255

class U2CORE_EXPORT GUrlUtils : public QObject {
    Q_OBJECT
public:
    // gets the uncompressed extension for the URL. Filters 'gz' like suffixes
    static QString getUncompressedExtension(const GUrl& url);

    // gets the complete base file name without ignoring 'gz' suffix
    static QString getUncompressedCompleteBaseName(const GUrl& url);

    // ensures that url ends with one of the exts
    static GUrl ensureFileExt(const GUrl& url, const QStringList& typeExt);

    // Changes the file's extension without affecting the ".gz" extension, returns an empty GUrl if any error occurs
    static GUrl changeFileExt(const GUrl& url, const DocumentFormatId& newFormatId);

    // returns url suitable for backup renaming (increments name for rolling file until non-existing name found)
    static QString rollFileName(const QString& url, const QString& rolledSuffix, const QSet<QString>& excludeList = QSet<QString>());

    // same as above but with empty suffix
    static QString rollFileName(const QString& url, const QSet<QString>& excludeList) {
        return rollFileName(url, "", excludeList);
    }

    /**
     * Inserts 'suffix' into the 'url' before the extension and returns the new url.
     * If no extension exits, appends the suffix to the URL.
     * If 'url' looks like extension ('.fasta') prepends the suffix.
     */
    static QString insertSuffix(const QString& url, const QString& baseNameSuffix);

    // renames actual file by rolling its name
    static bool renameFileWithNameRoll(const QString& url, TaskStateInfo& ti, const QSet<QString>& excludeList = QSet<QString>(), Logger* log = nullptr);

    // converts GUrl to QUrl
    static QUrl gUrl2qUrl(const GUrl& gurl);

    // converts QUrl to GUrl
    static GUrl qUrl2gUrl(const QUrl& qurl);

    static QList<GUrl> qUrls2gUrls(const QList<QUrl>& qurls);

    // adds baseSuffix to the url. Ensures that URL ends with one of the exts from typeExt
    static QString prepareFileName(const QString& url, const QString& baseSuffix, const QStringList& typeExt);

    // adds count to the url. Ensures that URL ends with one of the exts from typeExt
    static QString prepareFileName(const QString& url, int count, const QStringList& typeExt);

    // checks that file path is valid: creates required folder if needed.
    // Returns canonical path to file. Does not create nor remove file, affects just folder
    // Returns empty string and error message if some error occurs
    // Sample usage: processing URLs in "save file" inputs
    static QString prepareFileLocation(const QString& filePath, U2OpStatus& os);

    // checks that dir path is valid. Creates the folder if needed.
    // Returns canonical folder path. Does not affect folder if already exists.
    // Returns empty string and error message if some error occurs
    // Sample usage: processing URLs in "save dir" inputs
    static QString prepareDirLocation(const QString& dirPath, U2OpStatus& os);

    static QString prepareTmpFileLocation(const QString& dir, const QString& prefix, const QString& ext, U2OpStatus& os);

    static void removeDir(const QString& path, U2OpStatus& os);

    /*removes file if exists and if its a file*/
    static void removeFile(const QString& filePath, U2OpStatus& os);

    // checks if filePath is writable
    // creates and deletes a tmp file to check permissions
    // it seems the only way to check permissions correctly on all platforms
    static bool canWriteFile(const QString& path);

    // returns default path for UGENE data
    // returns empty string if path is not ready
    static QString getDefaultDataPath();

    // Get quoted input string if it has spaces
    static QString getQuotedString(const QString& inString);

    // Creates the folder with a rolled path: @path + @suffix + "num". Returns the new path
    static QString createDirectory(const QString& path, const QString& suffix, U2OpStatus& os);

    // If url is local returns values from it, else returns default values: default data dir path from settings and @defaultBaseFileName
    static void getLocalPathFromUrl(const GUrl& url, const QString& defaultBaseFileName, QString& dirPath, QString& baseFileName);

    // If url is local returns values from it, else returns default values
    static QString getLocalUrlFromUrl(const GUrl& url, const QString& defaultBaseFileName, const QString& dotExtension, const QString& suffix);

    // Rolls the result of getLocalUrlFromUrl()
    static QString getNewLocalUrlByFormat(const GUrl& url, const QString& defaultBaseFileName, const DocumentFormatId& format, const QString& suffix);
    static QString getNewLocalUrlByExtension(const GUrl& url, const QString& defaultBaseFileName, const QString& dotExtension, const QString& suffix);

    // Check that @url is the path to the local file. Creates the path if it does not exist
    static void validateLocalFileUrl(const GUrl& url, U2OpStatus& os, const QString& urlName = tr("Output URL"));

    // Gets base name of a FASTQ file with paired-end reads in case of several well-known file naming approaches
    static QString getPairedFastqFilesBaseName(const QString& sourceFileUrl, bool truncate);

    /**
     * Replaces from the filename all symbols except 0-9, a-z, A-Z, '.', '_', and '-' with '_' symbol,
     * so file name will both POSIX-compatible and Windows-compatible.
     */
    static QString fixFileName(const QString& fileName);

    static QString getSlashEndedPath(const QString& dirPath);

    static bool containSpaces(const QString& string);
    /**
     * Returns, for example, "/home/user/Desktop/File.txt" on Unix, "\\?\C:\Users\User\Desktop\File.txt" on Windows.
     * Can be used for platform specific system calls. Doesn't check the correctness of the path,
     * the existence of the directory/file, and other situations. For file systems only.
     */
    static QString getNativeAbsolutePath(const GUrl& url);
};

}  // namespace U2
