/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



#ifndef SC_CELL_HXX
#define SC_CELL_HXX

#include <stddef.h>

#include <set>
#include <tools/mempool.hxx>
#include <svl/listener.hxx>
#include "global.hxx"
#include "rangenam.hxx"
#include "formula/grammar.hxx"
#include "tokenarray.hxx"
#include "formularesult.hxx"
#include <rtl/ustrbuf.hxx>
#include <unotools/fontcvt.hxx>
#include "scdllapi.h"

#include <cellform.hxx>

#define USE_MEMPOOL
#define TEXTWIDTH_DIRTY		0xffff

// in addition to SCRIPTTYPE_... flags from scripttypeitem.hxx:
// set (in nScriptType) if type has not been determined yet
#define SC_SCRIPTTYPE_UNKNOWN	0x08

class ScDocument;
class EditTextObject;
class ScMatrix;
class SvtBroadcaster;
class ScCodeArray;
class ScProgress;
class ScPostIt;

// ============================================================================

/** Default cell clone flags: do not start listening, do not adjust 3D refs to
    old position, clone note captions of cell notes. */
const int SC_CLONECELL_DEFAULT          = 0x0000;

/** If set, cloned formula cells will start to listen to the document. */
const int SC_CLONECELL_STARTLISTENING   = 0x0001;

/** If set, relative 3D references of cloned formula cells will be adjusted to
    old position (used while swapping cells for sorting a cell range). */
const int SC_CLONECELL_ADJUST3DREL      = 0x0002;

/** If set, the caption object of a cell note will not be cloned (used while
    copying cells to undo document, where captions are handled in drawing undo). */
const int SC_CLONECELL_NOCAPTION        = 0x0004;

// ============================================================================

class SC_DLLPUBLIC ScBaseCell
{
protected:
					~ScBaseCell();	// nicht virtuell -> darf nicht direkt aufgerufen werden

public:
    explicit        ScBaseCell( CellType eNewType );

    /** Base copy constructor. Does NOT clone cell note or broadcaster! */
                    ScBaseCell( const ScBaseCell& rCell );

    /** Returns a clone of this cell at the same position, cell note and
        broadcaster will not be cloned. */
    ScBaseCell*     CloneWithoutNote( ScDocument& rDestDoc, int nCloneFlags = SC_CLONECELL_DEFAULT ) const;

    /** Returns a clone of this cell for the passed document position, cell
        note and broadcaster will not be cloned. */
    ScBaseCell*     CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags = SC_CLONECELL_DEFAULT ) const;

    /** Returns a clone of this cell, clones cell note and caption object too
        (unless SC_CLONECELL_NOCAPTION flag is set). Broadcaster will not be cloned. */
    ScBaseCell*     CloneWithNote( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags = SC_CLONECELL_DEFAULT ) const;

    /** Due to the fact that ScBaseCell does not have a vtable, this function
        deletes the cell by calling the appropriate d'tor of the derived class. */
    void            Delete();

    inline CellType GetCellType() const	{ return (CellType)eCellType; }

    /** Returns true, if the cell is empty (neither value nor formula nor cell note).
        Returns false for formula cells returning nothing, use HasEmptyData() for that. */
    bool            IsBlank( bool bIgnoreNotes = false ) const;

// fuer Idle-Berechnung
    inline sal_uInt16   GetTextWidth() const { return nTextWidth; }
    inline void     SetTextWidth( sal_uInt16 nNew ) { nTextWidth = nNew; }

    inline sal_uInt8     GetScriptType() const { return nScriptType; }
    inline void     SetScriptType( sal_uInt8 nNew ) { nScriptType = nNew; }

    /** Returns true, if the cell contains a note. */
    inline bool     HasNote() const { return mpNote != 0; }
    /** Returns the pointer to a cell note object (read-only). */
    inline const ScPostIt* GetNote() const { return mpNote; }
    /** Returns the pointer to a cell note object. */
    inline ScPostIt* GetNote() { return mpNote; }
    /** Takes ownership of the passed cell note object. */
    void            TakeNote( ScPostIt* pNote );
    /** Returns and forgets the own cell note object. Caller takes ownership! */
    ScPostIt*       ReleaseNote();
    /** Deletes the own cell note object. */
    void            DeleteNote();

    /** Returns true, if the cell contains a broadcaster. */
    inline bool     HasBroadcaster() const { return mpBroadcaster != 0; }
    /** Returns the pointer to the cell broadcaster. */
    inline SvtBroadcaster* GetBroadcaster() const { return mpBroadcaster; }
    /** Takes ownership of the passed cell broadcaster. */
    void            TakeBroadcaster( SvtBroadcaster* pBroadcaster );
    /** Returns and forgets the own cell broadcaster. Caller takes ownership! */
    SvtBroadcaster* ReleaseBroadcaster();
    /** Deletes the own cell broadcaster. */
    void            DeleteBroadcaster();

						// String- oder EditCell
	static ScBaseCell* CreateTextCell( const String& rString, ScDocument* );

    // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
	void			StartListeningTo( ScDocument* pDoc );
	void			EndListeningTo( ScDocument* pDoc,
									ScTokenArray* pArr = NULL,
									ScAddress aPos = ScAddress() );

    /** Error code if ScFormulaCell, else 0. */
    sal_uInt16          GetErrorCode() const;
    /** ScFormulaCell with formula::svEmptyCell result, or ScNoteCell (may have been
        created due to reference to empty cell). */
	sal_Bool			HasEmptyData() const;
	sal_Bool			HasValueData() const;
	sal_Bool			HasStringData() const;
	String			GetStringData() const;			// nur echte Strings

	static sal_Bool		CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 );

private:
    ScBaseCell&     operator=( const ScBaseCell& );

private:
    ScPostIt*       mpNote;         /// The cell note. Cell takes ownership!
    SvtBroadcaster* mpBroadcaster;  /// Broadcaster for changed values. Cell takes ownership!

protected:
    sal_uInt16          nTextWidth;
    sal_uInt8            eCellType;      // enum CellType - sal_uInt8 spart Speicher
    sal_uInt8            nScriptType;
};

// ============================================================================

class SC_DLLPUBLIC ScNoteCell : public ScBaseCell
{
public:
#ifdef USE_MEMPOOL
	DECL_FIXEDMEMPOOL_NEWDEL( ScNoteCell )
#endif

    /** Cell takes ownership of the passed broadcaster. */
    explicit        ScNoteCell( SvtBroadcaster* pBC = 0 );
    /** Cell takes ownership of the passed note and broadcaster. */
    explicit        ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC = 0 );

#ifdef DBG_UTIL
					~ScNoteCell();
#endif

private:
                    ScNoteCell( const ScNoteCell& );
};

// ============================================================================

class SC_DLLPUBLIC ScValueCell : public ScBaseCell
{
public:
#ifdef USE_MEMPOOL
	DECL_FIXEDMEMPOOL_NEWDEL( ScValueCell )
#endif
					ScValueCell();
    explicit		ScValueCell( double fValue );

#ifdef DBG_UTIL
					~ScValueCell();
#endif

    inline void     SetValue( double fValue ) { mfValue = fValue; }
    inline double   GetValue() const { return mfValue; }

private:
	double		    mfValue;
};

// ============================================================================

class SC_DLLPUBLIC ScStringCell : public ScBaseCell
{
public:
#ifdef USE_MEMPOOL
	DECL_FIXEDMEMPOOL_NEWDEL( ScStringCell )
#endif

					ScStringCell();
    explicit		ScStringCell( const String& rString );

#ifdef DBG_UTIL
					~ScStringCell();
#endif

    inline void		SetString( const String& rString ) { maString = rString; }
    inline void		GetString( String& rString ) const { rString = maString; }
	inline const String& GetString() const { return maString; }

private:
	String		    maString;
};

// ============================================================================

class SC_DLLPUBLIC ScEditCell : public ScBaseCell
{
private:
	EditTextObject*		pData;
	String*				pString;		// fuer schnelleren Zugriff von Formeln
	ScDocument*			pDoc;			// fuer EditEngine Zugriff mit Pool

	void			SetTextObject( const EditTextObject* pObject,
									const SfxItemPool* pFromPool );

					// not implemented
					ScEditCell( const ScEditCell& );

public:

#ifdef USE_MEMPOOL
	DECL_FIXEDMEMPOOL_NEWDEL( ScEditCell )
#endif

					~ScEditCell();				// wegen pData immer!

					ScEditCell( const EditTextObject* pObject, ScDocument*,
								const SfxItemPool* pFromPool /* = NULL */ );
                    ScEditCell( const ScEditCell& rCell, ScDocument& rDoc );
					// fuer Zeilenumbrueche
					ScEditCell( const String& rString, ScDocument* );

	void			SetData( const EditTextObject* pObject,
							const SfxItemPool* pFromPool /* = NULL */ );
	void			GetData( const EditTextObject*& rpObject ) const;
	void			GetString( String& rString ) const;

	const EditTextObject* GetData() const	{ return pData; }
};

// ============================================================================

enum ScMatrixMode {
    MM_NONE      = 0,                   // No matrix formula
    MM_FORMULA   = 1,                   // Upper left matrix formula cell
    MM_REFERENCE = 2,                   // Remaining cells, via ocMatRef reference token
    MM_FAKE      = 3                    // Interpret "as-if" matrix formula (legacy)
};

class SC_DLLPUBLIC ScFormulaCell : public ScBaseCell, public SvtListener
{
private:
    ScFormulaResult aResult;
    formula::FormulaGrammar::Grammar  eTempGrammar;   // used between string (creation) and (re)compilation
    ScTokenArray*   pCode;              // The (new) token array
    ScDocument*     pDocument;
    ScFormulaCell*  pPrevious;
    ScFormulaCell*  pNext;
    ScFormulaCell*  pPreviousTrack;
    ScFormulaCell*  pNextTrack;
    sal_uLong           nFormatIndex;       // Number format set by calculation
    short           nFormatType;        // Number format type set by calculation
    sal_uInt16          nSeenInIteration;   // Iteration cycle in which the cell was last encountered
    sal_uInt8            cMatrixFlag;        // One of ScMatrixMode
    sal_Bool            bDirty         : 1; // Must be (re)calculated
    sal_Bool            bChanged       : 1; // Whether something changed regarding display/representation
    sal_Bool            bRunning       : 1; // Already interpreting right now
    sal_Bool            bCompile       : 1; // Must be (re)compiled
    sal_Bool            bSubTotal      : 1; // Cell is part of or contains a SubTotal
    sal_Bool            bIsIterCell    : 1; // Cell is part of a circular reference
    sal_Bool            bInChangeTrack : 1; // Cell is in ChangeTrack
    sal_Bool            bTableOpDirty  : 1; // Dirty flag for TableOp
    sal_Bool            bNeedListening : 1; // Listeners need to be re-established after UpdateReference

                    enum ScInterpretTailParameter
                    {
                        SCITP_NORMAL,
                        SCITP_FROM_ITERATION,
                        SCITP_CLOSE_ITERATION_CIRCLE
                    };
	void			InterpretTail( ScInterpretTailParameter );

    ScFormulaCell( const ScFormulaCell& );

public:

#ifdef USE_MEMPOOL
	DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
#endif

	ScAddress		aPos;

					~ScFormulaCell();
					ScFormulaCell();

    /** Empty formula cell, or with a preconstructed token array. */
    ScFormulaCell( ScDocument*, const ScAddress&, const ScTokenArray* = NULL,
                    const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
                    sal_uInt8 = MM_NONE );

    /** With formula string and grammar to compile with.
       formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
        also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefor uses the address
        convention associated with rPos::nTab by default. */
    ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
                    const String& rFormula,
                    const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
                    sal_uInt8 cMatInd = MM_NONE );

    ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT );

	void			GetFormula( String& rFormula,
								const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
	void			GetFormula( rtl::OUStringBuffer& rBuffer,
								const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;

	void			SetDirty();
	inline void		SetDirtyVar() { bDirty = sal_True; }
    // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
    void            SetDirtyAfterLoad();
	inline void		ResetTableOpDirtyVar() { bTableOpDirty = sal_False; }
	void			SetTableOpDirty();
	sal_Bool			IsDirtyOrInTableOpDirty() const;
	sal_Bool			GetDirty() const { return bDirty; }
    sal_Bool            NeedsListening() const { return bNeedListening; }
    void            SetNeedsListening( sal_Bool bVar ) { bNeedListening = bVar; }
	void			Compile(const String& rFormula,
							sal_Bool bNoListening = sal_False,
                            const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT );
	void			CompileTokenArray( sal_Bool bNoListening = sal_False );
	void			CompileXML( ScProgress& rProgress );		// compile temporary string tokens
	void			CalcAfterLoad();
    bool            MarkUsedExternalReferences();
	void			Interpret();
    inline sal_Bool     IsIterCell() const { return bIsIterCell; }
    inline sal_uInt16   GetSeenInIteration() const { return nSeenInIteration; }

	sal_Bool			HasOneReference( ScRange& r ) const;
    /* Checks if the formula contains reference list that can be
       expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
       reference list is not required to be sorted (i.e. A3;A1;A2 is
       still recognized as A1:A3), but no overlapping is allowed.
       If one reference is recognized, the rRange is filled.

       It is similar to HasOneReference(), but more general.
     */
    bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
	sal_Bool			HasRelNameReference() const;
	sal_Bool			HasColRowName() const;

	void			UpdateReference(UpdateRefMode eUpdateRefMode,
									const ScRange& r,
									SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
                                    ScDocument* pUndoDoc = NULL,
                                    const ScAddress* pUndoCellPos = NULL );

	void			TransposeReference();
	void			UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
										ScDocument* pUndoDoc );

	void			UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );

	void			UpdateInsertTab(SCTAB nTable);
	void 			UpdateInsertTabAbs(SCTAB nTable);
	sal_Bool			UpdateDeleteTab(SCTAB nTable, sal_Bool bIsMove = sal_False);
	void			UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo);
	void			UpdateRenameTab(SCTAB nTable, const String& rName);
	sal_Bool 			TestTabRefAbs(SCTAB nTable);
	void			UpdateCompile( sal_Bool bForceIfNameInUse = sal_False );
	sal_Bool			IsRangeNameInUse(sal_uInt16 nIndex) const;
    void            FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes) const;
	void 			ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap );
	sal_Bool			IsSubTotal() const 						{ return bSubTotal; }
	sal_Bool			IsChanged() const  						{ return bChanged; }
	void			ResetChanged()							{ bChanged = sal_False; }
	sal_Bool			IsEmpty();      // formula::svEmptyCell result
                    // display as empty string if formula::svEmptyCell result
	sal_Bool			IsEmptyDisplayedAsString();
	sal_Bool			IsValue();      // also sal_True if formula::svEmptyCell
	double			GetValue();
	double			GetValueAlways();	// ignore errors
	void			GetString( String& rString );
	const ScMatrix* GetMatrix();
	sal_Bool			GetMatrixOrigin( ScAddress& rPos ) const;
	void			GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
	sal_uInt16 			GetMatrixEdge( ScAddress& rOrgPos );
	sal_uInt16			GetErrCode();   // interpret first if necessary
	sal_uInt16			GetRawError();  // don't interpret, just return code or result error
	short			GetFormatType() const   				{ return nFormatType; }
	sal_uLong			GetFormatIndex() const					{ return nFormatIndex; }
	void			GetFormatInfo( short& nType, sal_uLong& nIndex ) const
						{ nType = nFormatType; nIndex = nFormatIndex; }
	sal_uInt8			GetMatrixFlag() const   				{ return cMatrixFlag; }
	ScTokenArray*   GetCode() const                         { return pCode; }

	sal_Bool			IsRunning() const						{ return bRunning; }
	void			SetRunning( sal_Bool bVal )					{ bRunning = bVal; }
	void 			CompileDBFormula();
	void 			CompileDBFormula( sal_Bool bCreateFormulaString );
	void 			CompileNameFormula( sal_Bool bCreateFormulaString );
	void 			CompileColRowNameFormula();
	ScFormulaCell*	GetPrevious() const					{ return pPrevious; }
	ScFormulaCell*	GetNext() const						{ return pNext; }
	void			SetPrevious( ScFormulaCell* pF )	{ pPrevious = pF; }
	void			SetNext( ScFormulaCell* pF )		{ pNext = pF; }
	ScFormulaCell*	GetPreviousTrack() const				{ return pPreviousTrack; }
	ScFormulaCell*	GetNextTrack() const					{ return pNextTrack; }
	void			SetPreviousTrack( ScFormulaCell* pF )	{ pPreviousTrack = pF; }
	void			SetNextTrack( ScFormulaCell* pF )		{ pNextTrack = pF; }

	virtual void    Notify( SvtBroadcaster& rBC, const SfxHint& rHint);
	void			SetCompile( sal_Bool bVal ) { bCompile = bVal; }
	ScDocument*		GetDocument() const		{ return pDocument; }
	void			SetMatColsRows( SCCOL nCols, SCROW nRows );
	void			GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;

					// ob Zelle im ChangeTrack und nicht im echten Dokument ist
	void			SetInChangeTrack( sal_Bool bVal ) { bInChangeTrack = bVal; }
	sal_Bool			IsInChangeTrack() const { return bInChangeTrack; }

					// Zu Typ und Format das entsprechende Standardformat.
					// Bei Format "Standard" evtl. das in die Formelzelle
					// uebernommene Format.
	sal_uLong			GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const;

	// For import filters!
    void 			AddRecalcMode( formula::ScRecalcMode );
    /** For import only: set a double result. */
	void			SetHybridDouble( double n )     { aResult.SetHybridDouble( n); }
    /** For import only: set a string result.
        If for whatever reason you have to use both, SetHybridDouble() and
        SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
        for performance reasons.*/
    void            SetHybridString( const String& r )
                        { aResult.SetHybridString( r); }
    /** For import only: set a temporary formula string to be compiled later.
        If for whatever reason you have to use both, SetHybridDouble() and
        SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
        for performance reasons.*/
    void            SetHybridFormula( const String& r,
                                    const formula::FormulaGrammar::Grammar eGrammar )
                        { aResult.SetHybridFormula( r); eTempGrammar = eGrammar; }
	void			SetErrCode( sal_uInt16 n );
	inline sal_Bool		IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); }
	EditTextObject*		CreateURLObject() ;
    void            GetURLResult( String& rURL, String& rCellText );

    /** Determines whether or not the result string contains more than one paragraph */
    bool            IsMultilineResult();
};

//			Iterator fuer Referenzen in einer Formelzelle
class ScDetectiveRefIter
{
private:
	ScTokenArray* pCode;
	ScAddress aPos;
public:
				ScDetectiveRefIter( ScFormulaCell* pCell );
	sal_Bool		GetNextRef( ScRange& rRange );
};

// ============================================================================
inline double GetValueFromCell( const ScBaseCell * pCell )
{
    switch (pCell->GetCellType())
    {
    case CELLTYPE_VALUE:
        return ((ScValueCell*)pCell)->GetValue();
    case CELLTYPE_FORMULA:
        {
            if (((ScFormulaCell*)pCell)->IsValue())
                return ((ScFormulaCell*)pCell)->GetValue();
            else
                return 0.0;
        }
    default:
        return 0.0;
    }
}
// ============================================================================


inline String GetStringFromCell( const ScBaseCell * pCell, sal_uLong nFormat, SvNumberFormatter* pFormatter )
{
    if (pCell->GetCellType() != CELLTYPE_NOTE)
    {
        String strResult;
	Color* pColor = NULL;
        ScCellFormat::GetString( const_cast<ScBaseCell*>(pCell), nFormat, strResult, &pColor, *(pFormatter) );
        return strResult;
    }
    else
        return String();
}

#endif

