/*
    This file is part of kdepim.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This library 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 library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/
#ifndef KODE_CLASS_H
#define KODE_CLASS_H

#include <QtCore/QList>
#include <QtCore/QStringList>

#include "enum.h"
#include "include.h"
#include "function.h"
#include "membervariable.h"
#include "typedef.h"

#include <kode_export.h>

namespace KODE {

class ClassList;
/**
 * This class abstracts a class object with functions,
 * member variables etc.
 */
class KODE_EXPORT Class
{
public:
    typedef ClassList List;

    /**
     * Creates a new class object.
     */
    Class();

    /**
     * Creates a new class object from @param other.
     */
    Class(const Class &other);

    /**
     * Creates a new class object with a given @param name.
     *
     * @param nameSpace The namespace the class object should be part of.
     */
    Class(const QString &name, const QString &nameSpace = QString());

    /**
     * Destroys the class object.
     */
    ~Class();

    /**
     * Assignment operator.
     */
    Class &operator=(const Class &other);

    /**
     * Returns whether this class object is valid.
     */
    bool isValid() const;

    /**
     * Sets the name of the class object, possibly splitting out the namespace part of it.
     * E.g. Foo::Bar will set namespace = Bar, class name = Foo.
     *
     * This will treat anything except the last substring, as a namespace.
     * So this is not suited for nested classes. Use Class(A::B, NS) for nested classes.
     */
    void setNamespaceAndName(const QString &name);

    /**
     * Sets the @param name of the class object.
     */
    void setName(const QString &name);

    /**
     * Returns the name of the class object.
     */
    QString name() const;

    /**
     * Sets the namespace the class object should be part of.
     */
    void setNameSpace(const QString &nameSpace);

    /**
     * Returns the namespace the class object is part of.
     */
    QString nameSpace() const;

    /**
     * Returns the fully qualified class name including namespaces, e.g. NS1::NS2::ClassName
     */
    QString qualifiedName() const;

    /**
      Set export declaration with given name. This adds an include of a file
      name_export.h and a prefix to class declaration of NAME_EXPORT.
    */
    void setExportDeclaration(const QString &name);

    /**
      Return name of export declaration.
    */
    QString exportDeclaration() const;

    /**
     * Sets whether the class object shall use a d-pointer to store
     * its member variables.
     */
    void setUseDPointer(bool useDPointer, const QString &dPointer = "d");

    /**
     * Returns whether the class object uses a d-pointer.
     */
    bool useDPointer() const;

    /**
     * Returns the name of the d pointer.
     * Usually d, but can be set to something else to avoid clashes with a d() method for instance.
     */
    QString dPointerName() const;

    /**
     * Sets whether the class object shall use a QSharedDataPointer d-pointer
     * and a private class that derives from QSharedData.
     * This is for implicitly-shared value classes (classes that can be copied).
     *
     * Setting this to true automatically sets canBeCopied to true and useDPointer to true.
     */
    void setUseSharedData(bool b, const QString &dPointer = "d");

    /**
     * Returns whether the class object uses a QSharedDataPointer d-pointer.
     */
    bool useSharedData() const;

    /**
     * Sets whether the class can be copied (generates a copy constructor
     * and an operator= implementations, in case a d pointer is used).
     */
    void setCanBeCopied(bool b);

    /**
     * Returns whether the class instances can be copied.
     */
    bool canBeCopied() const;

    /**
     * Adds an include to the class object.
     *
     * @param file The include file like 'qfile.h' which will be
     *             printed as '#include <qfile.h>' in the header file.
     * @param forwardDeclaration The forward declaration like 'QFile'
     */
    void addInclude(const QString &file, const QString &forwardDeclaration = QString());

    /**
     * Adds several includes to the class object.
     *
     * @param files A list of include files like 'qfile.h'
     * @param forwardDeclaration A list of forward declarations like 'QFile'
     */
    void addIncludes(const QStringList &files,
                     const QStringList &forwardDeclarations = QStringList());

    /**
     * Returns the list of includes.
     */
    QStringList includes() const;

    /**
     * Returns the list of forward declarations.
     */
    QStringList forwardDeclarations() const;

    /**
     * Adds a header include to the class object.
     *
     * @param file The header include file like 'qfile.h' which
     *             will be printed as '#include "qfile.h"' in the
     *             implementation.
     */
    void addHeaderInclude(const QString &file, Include::IncludeType type = Include::Global);

    /**
     * Adds a list of header includes to the class object.
     */
    void addHeaderIncludes(const QStringList &files, Include::IncludeType type = Include::Global);

    /**
     * Returns the list of header includes.
     */
    Include::List headerIncludes() const;

    /**
     * Adds a @param function to the class object.
     */
    void addFunction(const Function &function);

    /**
     * Returns the list of all functions.
     */
    Function::List functions() const;

    /**
     * Adds a member @param variable to the class object.
     */
    void addMemberVariable(const MemberVariable &variable);

    /**
     * Returns the list of all member variables.
     */
    MemberVariable::List memberVariables() const;

    /**
     * Adds a base class definition to the class object.
     *
     * @param baseClass A class object which describes the base class.
     */
    void addBaseClass(const Class &baseClass);

    /**
     * Returns the list of all base classes.
     */
    Class::List baseClasses() const;

    /**
     * Adds a typedef to the class object.
     */
    void addTypedef(const Typedef &typedefValue);

    /**
     * Returns the list of all typedefs.
     */
    Typedef::List typedefs() const;

    /**
     * Adds an enum to the class object.
     */
    void addEnum(const Enum &enumValue);

    /**
     * Returns the list of all enums.
     */
    Enum::List enums() const;

    /**
     * Returns true, if the enum with the given name already exists. Returns
     * false, if not.
     */
    bool hasEnum(const QString &name) const;

    /**
     * Sets the @param documentation of the class object.
     */
    void setDocs(const QString &documentation);

    /**
     * Returns the documentation of the class object.
     */
    QString docs() const;

    /**
     * Returns whether the class object has a function with
     * the given @param name.
     */
    bool hasFunction(const QString &name) const;

    /**
     * Sets whether the Q_OBJECT macro should be generated at the first private
     * section. The Q_OBJECT macro will be generated if any signals or slots
     * added to the class, so this function is mainly useful when generating
     * intermediate classes derived from QObject, but not having any added signals
     * or slots.
     */
    void setQObject(bool isQObject);

    /**
     * Returns whether the class object is a QObject.
     *
     * That's the case when one of its functions has the Signal
     * or Slot flag set.
     */
    bool isQObject() const;

    /**
     * Returns whether the class should have a Q_GADGET macro
     */
    bool isQGadget() const;

    /**
     * Sets whether the Q_GADGET macro should be generated at the first private
     * section. Please note if isQObject is set only the Q_OBJECT macro will
     * be genrated since adding Q_GADGET is useless this case.
     */
    void setQGadget(const bool isQGadget);

    /**
     * Adds a nested class to this class.
     */
    void addNestedClass(const Class &nestedClass);

    /**
     * Return the list of all nested classes.
     */
    Class::List nestedClasses() const;

    /**
     * Return the name of the parent class name in a nested class.
     */
    QString parentClassName() const;
    /**
     * Set the name of the parent class in a nested class.
     */
    void setParentClassName(const QString &name);

    /**
     * Adds a declaration macro at the top of the class, like Q_PROPERTY(...)
     * or Q_INTERFACES(...).
     */
    void addDeclarationMacro(const QString &macro);

    /**
     * Returns the list of declaration macros added by addDeclarationMacro()
     */
    QStringList declarationMacros() const;

private:
    class Private;
    Private *d;
};

class ClassList : public QList<Class>
{
public:
    /**
     * Sort the classes so that the result compiles, i.e. so that a class using another
     * (via member vars or via inheritance) is after it in the list.
     *
     * @param excludedClasses list of base classes which can be excluded from the search
     * for dependencies, usually because them come from underlying libraries.
     * All classes starting with Q are automatically excluded
     */
    void sortByDependencies(const QStringList &excludedClasses = QStringList());
    // maybe we could have a bool ignoreUnknownClasses, too, for people who write bugfree code...

    void sortAlphabetically();

    void addClass(const Class &cl);

    QStringList classNames() const;

    const_iterator findClass(const QString &qualifiedName) const;
};
}

#endif
