/*
 * This file is part of KDevelop
 *
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library 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.
 */

#ifndef CLANGPARSINGENVIRONMENT_H
#define CLANGPARSINGENVIRONMENT_H

#include <util/path.h>
#include <language/duchain/parsingenvironment.h>

#include "clangprivateexport.h"

#include "clangsettings/clangsettingsmanager.h"

class KDEVCLANGPRIVATE_EXPORT ClangParsingEnvironment : public KDevelop::ParsingEnvironment
{
public:
    ~ClangParsingEnvironment() override = default;
    int type() const override;

    /**
     * Sets the list of project paths.
     *
     * Any include path outside these project paths is considered
     * to be a system include.
     */
    void setProjectPaths(const KDevelop::Path::List& projectPaths);
    KDevelop::Path::List projectPaths() const;

    /**
     * Add the given list of @p include paths to this environment.
     */
    void addIncludes(const KDevelop::Path::List& includes);

    /**
     * Add the given list of @p framework-directories to this environment.
     */
    void addFrameworkDirectories(const KDevelop::Path::List& frameworkDirectories);

    struct IncludePaths
    {
        /// This list contains all include paths outside the known projects paths.
        KDevelop::Path::List system;
        /// This list contains all include paths inside the known projects paths.
        KDevelop::Path::List project;
    };
    /**
     * Returns the list of includes, split into a list of system includes and project includes.
     */
    IncludePaths includes() const;

    struct FrameworkDirectories
    {
        /// This list contains all framework directories outside the known projects paths.
        KDevelop::Path::List system;
        /// This list contains all framework directories inside the known projects paths.
        KDevelop::Path::List project;
    };
    /**
     * Returns the list of framework directories, split into a list of system paths and project paths.
     */
    FrameworkDirectories frameworkDirectories() const;

    void addDefines(const QHash<QString, QString>& defines);
    QMap<QString, QString> defines() const;

    void setPchInclude(const KDevelop::Path& path);
    KDevelop::Path pchInclude() const;

    void setWorkingDirectory(const KDevelop::Path& path);
    KDevelop::Path workingDirectory() const;

    void setTranslationUnitUrl(const KDevelop::IndexedString& url);
    KDevelop::IndexedString translationUnitUrl() const;

    enum Quality
    {
        Unknown,
        Source,
        BuildSystem
    };

    void setQuality(Quality quality);
    Quality quality() const;

    void setParserSettings(const ParserSettings& arguments);

    ParserSettings parserSettings() const;
    void addParserArguments(const QString &parserArguments);

    /**
     * Hash all contents of this environment and return the result.
     *
     * This is useful for a quick comparison, and enough to store on-disk
     * to figure out if the environment changed or not.
     */
    uint hash() const;

    bool operator==(const ClangParsingEnvironment& other) const;
    bool operator!=(const ClangParsingEnvironment& other) const
    {
        return !(*this == other);
    }

private:
    KDevelop::Path::List m_projectPaths;
    KDevelop::Path::List m_includes;
    KDevelop::Path::List m_frameworkDirectories;
    // NOTE: As elements in QHash stored in an unordered sequence, we're using QMap instead
    QMap<QString, QString> m_defines;
    KDevelop::Path m_pchInclude;
    KDevelop::Path m_workingDirectory;
    KDevelop::IndexedString m_tuUrl;
    Quality m_quality = Unknown;
    ParserSettings m_parserSettings;
};

#endif // CLANGPARSINGENVIRONMENT_H
