/*
    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.
*/

#include <QtCore/QStringList>

#include "file.h"
#include <QDebug>

using namespace KODE;

class File::Private
{
public:
    Private() : mProject() {}

    QString mHeaderFilename;
    QString mImplFilename;
    QString mNameSpace;
    QString mProject;
    QStringList mCopyrightStrings;
    License mLicense;
    QStringList mIncludes;
    Class::List mClasses;
    Variable::List mFileVariables;
    Function::List mFileFunctions;
    Enum::List mFileEnums;
    QStringList mExternCDeclarations;
    Code mFileCode;
};

File::File() : d(new Private) {}

File::File(const File &other) : d(new Private)
{
    *d = *other.d;
}

File::~File()
{
    delete d;
}

File &File::operator=(const File &other)
{
    if (this == &other)
        return *this;

    *d = *other.d;

    return *this;
}

void File::setFilename(const QString &filename)
{
    d->mImplFilename = filename + ".cpp";
    d->mHeaderFilename = filename + ".h";
}

void File::setImplementationFilename(const QString &filename)
{
    d->mImplFilename = filename;
}

void File::setHeaderFilename(const QString &filename)
{
    d->mHeaderFilename = filename;
}

QString File::filenameHeader() const
{
    if (!d->mHeaderFilename.isEmpty())
        return d->mHeaderFilename;

    if (!d->mClasses.isEmpty()) {
        QString className = d->mClasses[0].name();
        return className.toLower() + ".h";
    }

    return QString();
}

QString File::filenameImplementation() const
{
    if (!d->mImplFilename.isEmpty())
        return d->mImplFilename;

    if (!d->mClasses.isEmpty()) {
        QString className = d->mClasses[0].name();
        return className.toLower() + ".cpp";
    }

    return QString();
}

void File::setNameSpace(const QString &nameSpace)
{
    d->mNameSpace = nameSpace;
}

QString File::nameSpace() const
{
    return d->mNameSpace;
}

void File::setProject(const QString &project)
{
    if (project.isEmpty())
        return;

    d->mProject = project;
}

QString File::project() const
{
    return d->mProject;
}

void File::addCopyright(int year, const QString &name, const QString &email)
{
    QString str = "Copyright (c) " + QString::number(year) + ' ' + name + " <" + email + '>';

    d->mCopyrightStrings.append(str);
}

QStringList File::copyrightStrings() const
{
    return d->mCopyrightStrings;
}

void File::setLicense(const License &license)
{
    d->mLicense = license;
}

License File::license() const
{
    return d->mLicense;
}

void File::addInclude(const QString &_include)
{
    QString include = _include;
    if (!include.endsWith(".h"))
        include.append(".h");

    if (!d->mIncludes.contains(include))
        d->mIncludes.append(include);
}

QStringList File::includes() const
{
    return d->mIncludes;
}

void File::insertClass(const Class &newClass)
{
    Q_ASSERT(!newClass.name().isEmpty());
    Class::List::Iterator it;
    for (it = d->mClasses.begin(); it != d->mClasses.end(); ++it) {
        if ((*it).qualifiedName() == newClass.qualifiedName()) {
            // This happens often, probably due to usage of shared types
            // qDebug() << "WARNING: Already having class" << newClass.qualifiedName() << "in file"
            // << filenameHeader() << filenameImplementation();
            it = d->mClasses.erase(it);
            d->mClasses.insert(it, newClass);
            return;
        }
    }

    d->mClasses.append(newClass);
}

Class::List File::classes() const
{
    return d->mClasses;
}

bool File::hasClass(const QString &name)
{
    Class::List::ConstIterator it;
    for (it = d->mClasses.constBegin(); it != d->mClasses.constEnd(); ++it) {
        if ((*it).name() == name)
            break;
    }

    return it != d->mClasses.constEnd();
}

Class File::findClass(const QString &name)
{
    Class::List::ConstIterator it;
    for (it = d->mClasses.constBegin(); it != d->mClasses.constEnd(); ++it) {
        if ((*it).name() == name)
            return *it;
    }

    return Class();
}

void File::addFileVariable(const Variable &variable)
{
    d->mFileVariables.append(variable);
}

Variable::List File::fileVariables() const
{
    return d->mFileVariables;
}

void File::addFileFunction(const Function &function)
{
    d->mFileFunctions.append(function);
}

Function::List File::fileFunctions() const
{
    return d->mFileFunctions;
}

void File::addFileEnum(const Enum &enumValue)
{
    d->mFileEnums.append(enumValue);
}

Enum::List File::fileEnums() const
{
    return d->mFileEnums;
}

void File::addExternCDeclaration(const QString &externalCDeclaration)
{
    d->mExternCDeclarations.append(externalCDeclaration);
}

QStringList File::externCDeclarations() const
{
    return d->mExternCDeclarations;
}

void File::addFileCode(const Code &code)
{
    d->mFileCode = code;
}

Code File::fileCode() const
{
    return d->mFileCode;
}

void File::clearClasses()
{
    d->mClasses.clear();
}

void File::clearFileFunctions()
{
    d->mFileFunctions.clear();
}

void File::clearFileVariables()
{
    d->mFileVariables.clear();
}

void File::clearCode()
{
    clearClasses();
    clearFileFunctions();
    clearFileVariables();
}
