/* This file is part of the KDE project
 * Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
 * Copyright (C) 2004 - 2010 Dag Andersen <danders@get2net.dk>
 * Copyright (C) 2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
 * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
 * Copyright (C) 2019 Dag Andersen <danders@get2net.dk>
 * 
 * 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 KPTMAINDOCUMENT_H
#define KPTMAINDOCUMENT_H

#include "plan_export.h"

#include "kptpackage.h"
#include "kpttask.h"
#include "kptconfig.h"
#include "kptwbsdefinition.h"
#include "kptxmlloaderobject.h"
#include "about/aboutpage.h"

#include "KoDocument.h"

#include <QFileInfo>
#include <QDomDocument>


#define PLAN_MIME_TYPE "application/x-vnd.kde.plan"

class KDirWatch;

/// The main namespace.
namespace KPlato
{

class DocumentChild;
class Project;
class Context;
class SchedulerPlugin;
class ViewListItem;
class View;

class Package;

class PLAN_EXPORT MainDocument : public KoDocument
{
    Q_OBJECT

public:
    explicit MainDocument(KoPart *part);
    ~MainDocument() override;

    void initEmpty() override;

    /// reimplemented from KoDocument
    QByteArray nativeFormatMimeType() const override { return PLAN_MIME_TYPE; }
    /// reimplemented from KoDocument
    QByteArray nativeOasisMimeType() const override { return ""; }
    /// reimplemented from KoDocument
    QStringList extraNativeMimeTypes() const override
    {
        return QStringList() << PLAN_MIME_TYPE;
    }

    void setReadWrite(bool rw) override;
    void configChanged();

    void paintContent(QPainter& painter, const QRect& rect) override;

    void setProject(Project *project);
    Project *project() const override { return m_project; }
    Project &getProject() { return *m_project; }
    const Project &getProject() const { return * m_project; }
    QString projectName() const override { return m_project->name(); }

    /**
     * Return the set of SupportedSpecialFormats that the kplato wants to
     * offer in the "Save" file dialog.
     * Note: SaveEncrypted is not supported.
     */
    int supportedSpecialFormats() const override { return SaveAsDirectoryStore; }

    // The load and save functions. Look in the file kplato.dtd for info
    bool loadXML(const KoXmlDocument &document, KoStore *store) override;
    QDomDocument saveXML() override;
    /// Save a workpackage file containing @p node with schedule identity @p id, owned by @p resource
    QDomDocument saveWorkPackageXML(const Node *node, long id, Resource *resource = 0);

    bool saveOdf(SavingContext &/*documentContext */) override { return false; }
    bool loadOdf(KoOdfReadStore & odfStore) override;

    Config &config() { return m_config; }
    Context *context() const { return m_context; }

    WBSDefinition &wbsDefinition() { return m_project->wbsDefinition(); }

    const XMLLoaderObject &xmlLoader() const { return m_xmlLoader; }

    DocumentChild *createChild(KoDocument *doc, const QRect &geometry = QRect());

    bool saveWorkPackageToStream(QIODevice * dev, const Node *node, long id, Resource *resource = 0);
    bool saveWorkPackageFormat(const QString &file, const Node *node, long id, Resource *resource = 0);
    bool saveWorkPackageUrl(const QUrl & _url, const Node *node, long id, Resource *resource = 0  );

    /// Load the workpackage from @p url into @p project. Return true if successful, else false.
    bool loadWorkPackage(Project &project, const QUrl &url);
    Package *loadWorkPackageXML(Project& project, QIODevice*, const KoXmlDocument& document, const QUrl& url);
    QMap<QDateTime, Package*> workPackages() const { return m_workpackages; }
    void clearWorkPackages() {
        qDeleteAll(m_workpackages);
        m_workpackages.clear();
        m_checkingForWorkPackages = false;
    }

    void insertFile(const QUrl &url, Node *parent, Node *after = 0);
    bool insertProject(Project &project, Node *parent, Node *after);
    bool mergeResources(Project &project);

    KPlatoAboutPage &aboutPage() { return m_aboutPage; }

    bool extractFiles(KoStore *store, Package *package);
    bool extractFile(KoStore *store, Package *package, const Document *doc);

    void registerView(View *view);

    /// Create a new project from this project
    /// Generates new project id and task ids
    /// Keeps resource- and calendar ids
    void createNewProject();

    bool isTaskModule() const;

    using KoDocument::setModified;
public Q_SLOTS:
    void setModified(bool mod) override;

    /// Inserts an item into all other views than @p view
    void insertViewListItem(KPlato::View *view, const KPlato::ViewListItem *item, const KPlato::ViewListItem *parent, int index);
    /// Removes the view list item from all other views than @p view
    void removeViewListItem(KPlato::View *view, const KPlato::ViewListItem *item);
    /// View selector has been modified
    void slotViewlistModified();
    /// Check for workpackages
    /// If @p keep is true, packages that has been refused will not be checked for again
    void checkForWorkPackages(bool keep);
    /// Remove @p package
    void terminateWorkPackage(const KPlato::Package *package);

    void setLoadingTemplate(bool);
    void setLoadingSharedResourcesTemplate(bool);

    void insertResourcesFile(const QUrl &url, const QUrl &projects = QUrl());
    void slotProjectCreated();

    /// Prepare for insertion of resource assignments of shared resources from the project(s) in @p urls
    void insertSharedProjects(const QList<QUrl> &urls);

    /// Prepare for insertion of resource assignments of shared resources from the project(s) in @p url
    void insertSharedProjects(const QUrl &url);

    /// Clear resource assignments of shared resources
    void clearResourceAssignments();
    /// Load resource assignments of shared resources from the project(s) in @p url
    void loadResourceAssignments(QUrl url);

    void setIsTaskModule(bool value);

    void autoCheckForWorkPackages();

Q_SIGNALS:
    void changed();
    void workPackageLoaded();
    void viewlistModified(bool);
    void viewListItemAdded(const KPlato::ViewListItem *item, const KPlato::ViewListItem *parent, int index);
    void viewListItemRemoved(const KPlato::ViewListItem *item);

    void insertSharedProject();

protected:
    /// Load kplato specific files
    bool completeLoading(KoStore* store) override;
    /// Save kplato specific files
    bool completeSaving(KoStore* store) override;

    // used by insert file
    struct InsertFileInfo {
        QUrl url;
        Node *parent;
        Node *after;
    } m_insertFileInfo;


protected Q_SLOTS:
    void slotViewDestroyed();
    void addSchedulerPlugin(const QString&, KPlato::SchedulerPlugin *plugin);

    void checkForWorkPackage();

    void insertFileCompleted();
    void insertResourcesFileCompleted();
    void insertFileCancelled(const QString&);

    void slotInsertSharedProject();
    void insertSharedProjectCompleted();
    void insertSharedProjectCancelled(const QString&);

    void slotNodeChanged(KPlato::Node*, int);
    void slotScheduleManagerChanged(KPlato::ScheduleManager *sm, int property);
    void setCalculationNeeded();
    void slotCalculationFinished(KPlato::Project *project, KPlato::ScheduleManager *sm);
    void slotStartCalculation();

    void setTaskModulesWatch();
    void taskModuleDirChanged();

private:
    bool loadAndParse(KoStore* store, const QString& filename, KoXmlDocument& doc);

    void loadSchedulerPlugins();

private:
    Project *m_project;
    QWidget* m_parentWidget;

    Config m_config;
    Context *m_context;

    XMLLoaderObject m_xmlLoader;
    bool m_loadingTemplate;
    bool m_loadingSharedResourcesTemplate;

    QMap<QString, SchedulerPlugin*> m_schedulerPlugins;
    QMap<QDateTime, Package*> m_workpackages;
    QFileInfoList m_infoList;
    QList<QUrl> m_skipUrls;
    QMap<QDateTime, Project*> m_mergedPackages;

    KPlatoAboutPage m_aboutPage;

    QDomDocument m_reports;

    bool m_viewlistModified;
    bool m_checkingForWorkPackages;

    QList<QPointer<View> > m_views;

    bool m_loadingSharedProject;
    QList<QUrl> m_sharedProjectsFiles;
    bool m_skipSharedProjects;

    bool m_isTaskModule;

    KUndo2Command* m_calculationCommand;
    ScheduleManager* m_currentCalculationManager;
    ScheduleManager* m_nextCalculationManager;

    KDirWatch *m_taskModulesWatch;
};


}  //KPlato namespace

#endif
