/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_SW_INC_NDARR_HXX
#define INCLUDED_SW_INC_NDARR_HXX

#include <sal/config.h>

#include <limits>
#include <vector>
#include <memory>

#include "bparr.hxx"
#include "ndtyp.hxx"
#include <rtl/ustring.hxx>
#include <o3tl/sorted_vector.hxx>

class Graphic;
class GraphicObject;
class SwAttrSet;
class SfxItemSet;
class SwContentNode;
class SwDoc;
class SwGrfFormatColl;
class SwGrfNode;
class SwNode;
class SwNodeIndex;
class SwNodeRange;
class SwOLENode;
class SwPaM;
class SwSectionData;
class SwSectionFormat;
class SwTOXBase;
class SwSectionNode;
class SwStartNode;
class SwTableBoxFormat;
class SwTableFormat;
class SwTableLine;
class SwTableLineFormat;
class SwTableNode;
class SwTextFormatColl;
class SwTextNode;
class SwUndoTableToText;
class SwUndoTextToTable;
struct SwPosition;

namespace sw { class DocumentContentOperationsManager; }
namespace svt { class EmbeddedObjectRef; }


typedef SwNode * SwNodePtr;
typedef bool (*FnForEach_SwNodes)( const SwNodePtr&, void* pArgs );
typedef struct _xmlTextWriter *xmlTextWriterPtr;

struct CompareSwOutlineNodes
{
    bool operator()( SwNode* const& lhs, SwNode* const& rhs) const;
};

class SwOutlineNodes : public o3tl::sorted_vector<SwNode*, CompareSwOutlineNodes>
{
public:
    static constexpr auto npos = std::numeric_limits<size_type>::max();

    bool Seek_Entry(SwNode* rP, size_type* pnPos) const;
};

struct SwTableToTextSave;
using SwTableToTextSaves = std::vector<std::unique_ptr<SwTableToTextSave>>;

class SW_DLLPUBLIC SwNodes final
    : private BigPtrArray
{
    friend class SwDoc;
    friend class SwNode;
    friend class SwNodeIndex;
    friend class SwStartNode;
    friend class ::sw::DocumentContentOperationsManager;

    SwNodeIndex* m_vIndices; ///< ring of all indices on nodes.
    void RemoveNode( sal_uLong nDelPos, sal_uLong nLen, bool bDel );

    void InsertNode( const SwNodePtr pNode,
                     const SwNodeIndex& rPos );
    void InsertNode( const SwNodePtr pNode,
                     sal_uLong nPos );

    SwDoc* m_pMyDoc;                      ///< This Doc contains the nodes-array.

    SwNode *m_pEndOfPostIts, *m_pEndOfInserts,  ///< These are the fixed ranges.
           *m_pEndOfAutotext, *m_pEndOfRedlines;
    std::unique_ptr<SwNode> m_pEndOfContent;

    mutable std::unique_ptr<SwOutlineNodes> m_pOutlineNodes;        ///< Array of all outline nodes.

    bool m_bInNodesDel : 1;           /**< In Case of recursive calling.
                                           Do not update Num/Outline. */
    bool m_bInDelUpdOutline : 1;         ///< Flag for updating of Outline.

    // Actions on the nodes.
    static void SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd );
    void DelNodes( const SwNodeIndex& rStart, sal_uLong nCnt = 1 );

    void ChgNode( SwNodeIndex const & rDelPos, sal_uLong nSize,
                  SwNodeIndex& rInsPos, bool bNewFrames );

    void UpdateOutlineIdx( const SwNode& );   ///< Update all OutlineNodes starting from Node.

    void CopyNodes( const SwNodeRange&, const SwNodeIndex&,
                    bool bNewFrames, bool bTableInsDummyNode = false ) const;
    void DelDummyNodes( const SwNodeRange& rRg );

    SwNodes(SwNodes const&) = delete;
    SwNodes& operator=(SwNodes const&) = delete;

    SwNodes( SwDoc* pDoc );

public:
    ~SwNodes();

    typedef std::vector<SwNodeRange> NodeRanges_t;
    typedef std::vector<NodeRanges_t> TableRanges_t;

    SwNodePtr operator[]( sal_uLong n ) const; // defined in node.hxx

    sal_uLong Count() const { return BigPtrArray::Count(); }
    void ForEach( FnForEach_SwNodes fnForEach, void* pArgs = nullptr )
    {
        ForEach( 0, BigPtrArray::Count(), fnForEach, pArgs );
    }
    void ForEach( sal_uLong nStt, sal_uLong nEnd, FnForEach_SwNodes fnForEach, void* pArgs );
    void ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
                    FnForEach_SwNodes fnForEach, void* pArgs );

    /// A still empty section.
    SwNode& GetEndOfPostIts() const     { return *m_pEndOfPostIts; }
    /// Section for all footnotes.
    SwNode& GetEndOfInserts() const     { return *m_pEndOfInserts; }
    /// Section for all Flys/Header/Footers.
    SwNode& GetEndOfAutotext() const    { return *m_pEndOfAutotext; }
    /// Section for all Redlines.
    SwNode& GetEndOfRedlines() const    { return *m_pEndOfRedlines; }
    /** This is the last EndNode of a special section. After it
       there is only the regular ContentSection (i.e. the BodyText). */
    SwNode& GetEndOfExtras() const      { return *m_pEndOfRedlines; }
    /// Regular ContentSection (i.e. the BodyText).
    SwNode& GetEndOfContent() const     { return *m_pEndOfContent; }

    /** Is the NodesArray the regular one of Doc? (and not the UndoNds, ...)
       Implementation in doc.hxx (because one needs to know Doc for it) ! */
    bool IsDocNodes() const;

    static sal_uInt16 GetSectionLevel(const SwNodeIndex &rIndex);
    void Delete(const SwNodeIndex &rPos, sal_uLong nNodes = 1);

    bool MoveNodes( const SwNodeRange&, SwNodes& rNodes, const SwNodeIndex&,
                bool bNewFrames = true );
    void MoveRange( SwPaM&, SwPosition&, SwNodes& rNodes );

    void Copy_( const SwNodeRange& rRg, const SwNodeIndex& rInsPos,
                bool bNewFrames = true ) const
        {   CopyNodes( rRg, rInsPos, bNewFrames ); }

    void SectionUp( SwNodeRange *);
    void SectionDown( SwNodeRange *pRange, SwStartNodeType = SwNormalStartNode );

    static void GoStartOfSection(SwNodeIndex *);
    static void GoEndOfSection(SwNodeIndex *);

    SwContentNode* GoNext(SwNodeIndex *) const;
    static SwContentNode* GoPrevious(SwNodeIndex *);

    /** Go to next content-node that is not protected or hidden
       (Both set FALSE ==> GoNext/GoPrevious!!!). */
    SwContentNode* GoNextSection( SwNodeIndex *, bool bSkipHidden  = true,
                                           bool bSkipProtect = true ) const;
    static SwContentNode* GoPrevSection( SwNodeIndex *, bool bSkipHidden  = true,
                                           bool bSkipProtect = true );

    /** Create an empty section of Start- and EndNote. It may be called
       only if a new section with content is to be created,
       e.g. at filters/Undo/... */
    static SwStartNode* MakeEmptySection( const SwNodeIndex& rIdx,
                                    SwStartNodeType = SwNormalStartNode );

    /// Implementations of "Make...Node" are in the given .cxx-files.
    SwTextNode *MakeTextNode( const SwNodeIndex & rWhere,
                            SwTextFormatColl *pColl,
                            bool bNewFrames = true); ///< in ndtxt.cxx
    SwStartNode* MakeTextSection( const SwNodeIndex & rWhere,
                            SwStartNodeType eSttNdTyp,
                            SwTextFormatColl *pColl );

    static SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const OUString& rGrfName,
                            const OUString& rFltName,
                            const Graphic* pGraphic,
                            SwGrfFormatColl *pColl,
                            SwAttrSet const * pAutoAttr = nullptr );    ///< in ndgrf.cxx

    static SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const GraphicObject& rGrfObj,
                            SwGrfFormatColl *pColl ); ///< in ndgrf.cxx

    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const svt::EmbeddedObjectRef&,
                            SwGrfFormatColl *pColl ); ///< in ndole.cxx
    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const OUString &rName,
                            sal_Int64 nAspect,
                            SwGrfFormatColl *pColl,
                            SwAttrSet const * pAutoAttr ); ///< in ndole.cxx

    /// Array of all OutlineNodes.
    const SwOutlineNodes& GetOutLineNds() const { return *m_pOutlineNodes;}

    /// Update all Nodes - Rule/Format-Change.
    void UpdateOutlineNode(SwNode & rNd);

    /** Insert nodes for tables. If Lines is given, create the matrix
       from lines and boxes, else only the count of boxes.

       New parameter pAttrSet: If pAttrSet is non-null and contains an
       adjust item it is propagated to the table cells. If there is an
       adjust in pContentTextColl or pHeadlineTextColl this adjust item
       overrides the item in pAttrSet. */

    static SwTableNode* InsertTable( const SwNodeIndex& rNdIdx,
                        sal_uInt16 nBoxes, SwTextFormatColl* pContentTextColl,
                        sal_uInt16 nLines, sal_uInt16 nRepeat,
                        SwTextFormatColl* pHeadlineTextColl,
                        const SwAttrSet * pAttrSet);

    /// Create balanced table from selected range.
    SwTableNode* TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                                SwTableFormat* pTableFormat,
                                SwTableLineFormat* pLineFormat,
                                SwTableBoxFormat* pBoxFormat,
                                SwTextFormatColl* pTextColl,
                                SwUndoTextToTable* pUndo );

    std::unique_ptr<SwNodeRange> ExpandRangeForTableBox(const SwNodeRange & rRange);

    /// create a table from a vector of NodeRanges - API support
    SwTableNode* TextToTable( const TableRanges_t& rTableNodes,
                                SwTableFormat* pTableFormat,
                                SwTableLineFormat* pLineFormat,
                                SwTableBoxFormat* pBoxFormat );

    /// Create regular text from what was table.
    bool TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
                        SwUndoTableToText* );
    /// Is in untbl.cxx and may called only by Undo-object.
    SwTableNode* UndoTableToText( sal_uLong nStt, sal_uLong nEnd,
                        const SwTableToTextSaves& rSavedData );

    /** Insert a new box in the line before InsPos. Its format
       is taken from the following one (or from the previous one if we are
       at the end). In the line there must be a box already. */
    bool InsBoxen( SwTableNode*, SwTableLine*, SwTableBoxFormat*,
                        /// Formats for TextNode of box.
                        SwTextFormatColl*, const SfxItemSet* pAutoAttr,
                        sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 );
    /** Splits a table at the base-line which contains the index.
       All base lines behind it are moved to a new table/ -node.
       Is the flag bCalcNewSize set to TRUE, the new SSize for both
       tables is calculated from the Maximum of the boxes, provided
       SSize is set "absolute" (LONG_MAX).
       (Momentarily this is needed only for the RTF-parser.) */
    SwTableNode* SplitTable( const SwNodeIndex& rPos, bool bAfter = true,
                                bool bCalcNewSize = false );
    /// Two Tables that are following one another are merged.
    bool MergeTable( const SwNodeIndex& rPos, bool bWithPrev = true,
                    sal_uInt16 nMode = 0 );

    /// Insert a new SwSection.
    SwSectionNode* InsertTextSection(SwNodeIndex const& rNdIdx,
                                SwSectionFormat& rSectionFormat,
                                SwSectionData const&,
                                SwTOXBase const*const pTOXBase,
                                SwNodeIndex const*const pEnd,
                                bool const bInsAtStart = true,
                                bool const bCreateFrames = true);

    /// Which Doc contains the nodes-array?
            SwDoc* GetDoc()         { return m_pMyDoc; }
    const   SwDoc* GetDoc() const   { return m_pMyDoc; }

    /** Search previous / next content node or table node with frames.
     If no end is given begin with the FrameIndex, else start search
     with that before rFrameIdx and pEnd at the back.
     If no valid node is found, return 0. rFrameIdx points to the node with frames. **/
    SwNode* FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx,
                                const SwNode* pEnd ) const;

    SwNode * DocumentSectionStartNode(SwNode * pNode) const;
    SwNode * DocumentSectionEndNode(SwNode * pNode) const;

    /**
     * Dumps the entire nodes structure to the given destination (file nodes.xml in the current directory by default)
     */
    void dumpAsXml( xmlTextWriterPtr pWriter ) const;
};


#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
