/*************************************************************************
 *
 *  $RCSfile: token.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: vg $ $Date: 2003-06-12 10:17:25 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_TOKEN_HXX
#define SC_TOKEN_HXX

#include <string.h>     // memcpy(), don't use memory.h (MAC)

#ifndef SC_OPCODE_HXX
#include "opcode.hxx"
#endif

#ifndef SC_REFDATA_HXX
#include "refdata.hxx"
#endif


enum StackVarEnum
{
    svByte,
    svDouble,
    svString,
    svSingleRef,
    svDoubleRef,
    svMatrix,
    svIndex,
    svJump,
    svExternal,                         // Byte + String

    svFAP,                              // FormulaAutoPilot only, ever exported

    svMissing = 0x70,                   // 0 or ""
    svErr                               // unknown StackType
};

#ifdef PRODUCT
// save memory since compilers tend to int an enum
typedef BYTE StackVar;
#else
// have enum names in debugger
typedef StackVarEnum StackVar;
#endif


class ScMatrix;

class ScToken
{
private:

            OpCode              eOp;            // OpCode
            const StackVar      eType;          // type of data
            USHORT              nRefCnt;        // reference count

                                // not implemented, prevent usage
                                ScToken();
            ScToken&            operator=( const ScToken& );

protected:

    static  SingleRefData       aDummySingleRef;
    static  ComplRefData        aDummyDoubleRef;
    static  String              aDummyString;

                                ScToken( OpCode eOpP, StackVar eTypeP ) :
                                    eOp( eOpP ), eType( eTypeP ), nRefCnt(0) {}
                                ScToken( const ScToken& r ) :
                                    eOp( r.eOp ), eType( r.eType ), nRefCnt(0) {}

public:

    virtual                     ~ScToken();

    inline  void                Delete()                { delete this; }
    inline  const StackVar      GetType() const         { return eType; }
    inline  OpCode              GetOpCode() const       { return eOp;   }
            BOOL                IsFunction() const; // pure functions, no operators
            BOOL                IsMatrixFunction() const;   // if a function _always_ returns a Matrix
            BYTE                GetParamCount() const;
    inline  void                NewOpCode( OpCode e )   { eOp = e; }
    inline  void                IncRef()                { nRefCnt++;       }
    inline  void                DecRef()                { if( !--nRefCnt ) Delete(); }
    inline  USHORT              GetRef() const          { return nRefCnt; }

    // Dummy methods to avoid switches and casts where possible,
    // the real token classes have to overload the appropriate method[s].
    // The only method valid anytime if not overloaded is GetByte() since
    // this represents the count of parameters to a function which of course
    // is 0 on non-functions. ScByteToken and ScExternal do overload it.
    // Any other non-overloaded method pops up an assertion.
    virtual BYTE                GetByte() const;
    virtual void                SetByte( BYTE n );
    virtual double              GetDouble() const;
    virtual const String&       GetString() const;
    virtual const SingleRefData&    GetSingleRef() const;
    virtual SingleRefData&      GetSingleRef();
    virtual const ComplRefData& GetDoubleRef() const;
    virtual ComplRefData&       GetDoubleRef();
    virtual const SingleRefData&    GetSingleRef2() const;
    virtual SingleRefData&      GetSingleRef2();
    virtual void                CalcAbsIfRel( const ScAddress& );
    virtual void                CalcRelFromAbs( const ScAddress& );
    virtual ScMatrix*           GetMatrix() const;
    virtual USHORT              GetIndex() const;
    virtual void                SetIndex( USHORT n );
    virtual short*              GetJump() const;
    virtual const String&       GetExternal() const;
    virtual BYTE*               GetUnknown() const;
    virtual ScToken*            GetFAPOrigToken() const;

            ScToken*            Clone() const;

            void                Store( SvStream& ) const;

    virtual BOOL                operator==( const ScToken& rToken ) const;
            BOOL                TextEqual( const ScToken& rToken ) const;
            BOOL                Is3DRef() const;    // reference with 3D flag set

    // If token in RPN resulted from resolving a name and contains an absolute
    // reference. Token must be obtained through ScTokenArray::GetNextReferenceRPN()
    // or similar.
            BOOL                IsRPNReferenceAbsName() const;

    static  size_t              GetStrLenBytes( xub_StrLen nLen )
                                    { return nLen * sizeof(sal_Unicode); }
    static  size_t              GetStrLenBytes( const String& rStr )
                                    { return GetStrLenBytes( rStr.Len() ); }
};


class ScTokenRef
{
    ScToken* p;
public:
    inline ScTokenRef() { p = NULL; }
    inline ScTokenRef( const ScTokenRef& r ) { if( ( p = r.p ) != NULL ) p->IncRef(); }
    inline ScTokenRef( ScToken *t )          { if( ( p = t ) != NULL ) t->IncRef(); }
    inline void Clear()                      { if( p ) p->DecRef(); }
    inline ~ScTokenRef()                     { if( p ) p->DecRef(); }
    inline ScTokenRef& operator=( const ScTokenRef& r ) { return *this = r.p; }
    inline ScTokenRef& operator=( ScToken* t )
    { if( t ) t->IncRef(); if( p ) p->DecRef(); p = t; return *this; }
    inline BOOL Is() const                  { return p != NULL; }
    inline BOOL operator ! () const         { return p == NULL; }
    inline ScToken* operator&() const       { return p; }
    inline ScToken* operator->() const      { return p; }
    inline ScToken& operator*() const       { return *p; }
    inline operator ScToken*() const        { return p; }
};


class ScByteToken : public ScToken
{
private:
            BYTE                nByte;
protected:
                                ScByteToken( OpCode e, BYTE n, StackVar v ) :
                                    ScToken( e, v ), nByte( n ) {}
public:
                                ScByteToken( OpCode e, BYTE n ) :
                                    ScToken( e, svByte ), nByte( n ) {}
                                ScByteToken( OpCode e ) :
                                    ScToken( e, svByte ), nByte( 0 ) {}
                                ScByteToken( const ScByteToken& r ) :
                                    ScToken( r ), nByte( r.nByte ) {}
    virtual BYTE                GetByte() const;
    virtual void                SetByte( BYTE n );
    virtual BOOL                operator==( const ScToken& rToken ) const;

    DECL_FIXEDMEMPOOL_NEWDEL( ScByteToken );
};


// A special token for the FormulaAutoPilot only. Keeps a reference pointer of
// the token of which it was created for comparison.
class ScFAPToken : public ScByteToken
{
private:
            ScTokenRef          pOrigToken;
public:
                                ScFAPToken( OpCode e, BYTE n, ScToken* p ) :
                                    ScByteToken( e, n, svFAP ), pOrigToken( p ) {}
                                ScFAPToken( const ScFAPToken& r ) :
                                    ScByteToken( r ), pOrigToken( r.pOrigToken ) {}
    virtual ScToken*            GetFAPOrigToken() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScDoubleToken : public ScToken
{
private:
            double              fDouble;
public:
                                ScDoubleToken( double f ) :
                                    ScToken( ocPush, svDouble ), fDouble( f ) {}
                                ScDoubleToken( OpCode e, double f ) :
                                    ScToken( e, svDouble ), fDouble( f ) {}
                                ScDoubleToken( const ScDoubleToken& r ) :
                                    ScToken( r ), fDouble( r.fDouble ) {}
    virtual double              GetDouble() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;

    DECL_FIXEDMEMPOOL_NEWDEL( ScDoubleToken );
};


class ScStringToken : public ScToken
{
private:
            String              aString;
public:
                                ScStringToken( const String& r ) :
                                    ScToken( ocPush, svString ), aString( r ) {}
                                ScStringToken( OpCode e, const String& r ) :
                                    ScToken( e, svString ), aString( r ) {}
                                ScStringToken( const ScStringToken& r ) :
                                    ScToken( r ), aString( r.aString ) {}
    virtual const String&       GetString() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;

    DECL_FIXEDMEMPOOL_NEWDEL( ScStringToken );
};


class ScSingleRefToken : public ScToken
{
private:
            SingleRefData       aSingleRef;
public:
                                ScSingleRefToken( const SingleRefData& r ) :
                                    ScToken( ocPush, svSingleRef ), aSingleRef( r ) {}
                                ScSingleRefToken( OpCode e, const SingleRefData& r ) :
                                    ScToken( e, svSingleRef ), aSingleRef( r ) {}
                                ScSingleRefToken( const ScSingleRefToken& r ) :
                                    ScToken( r ), aSingleRef( r.aSingleRef ) {}
    virtual const SingleRefData&    GetSingleRef() const;
    virtual SingleRefData&      GetSingleRef();
    virtual void                CalcAbsIfRel( const ScAddress& );
    virtual void                CalcRelFromAbs( const ScAddress& );
    virtual BOOL                operator==( const ScToken& rToken ) const;

    DECL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken );
};


class ScDoubleRefToken : public ScToken
{
private:
            ComplRefData        aDoubleRef;
public:
                                ScDoubleRefToken( const ComplRefData& r ) :
                                    ScToken( ocPush, svDoubleRef ), aDoubleRef( r ) {}
                                ScDoubleRefToken( OpCode e, const ComplRefData& r ) :
                                    ScToken( e, svDoubleRef ), aDoubleRef( r ) {}
                                ScDoubleRefToken( OpCode e, const SingleRefData& r ) :
                                    ScToken( e, svDoubleRef )
                                {
                                    aDoubleRef.Ref1 = r;
                                    aDoubleRef.Ref2 = r;
                                }
                                ScDoubleRefToken( const ScDoubleRefToken& r ) :
                                    ScToken( r ), aDoubleRef( r.aDoubleRef ) {}
    virtual const SingleRefData&    GetSingleRef() const;
    virtual SingleRefData&      GetSingleRef();
    virtual const ComplRefData& GetDoubleRef() const;
    virtual ComplRefData&       GetDoubleRef();
    virtual const SingleRefData&    GetSingleRef2() const;
    virtual SingleRefData&      GetSingleRef2();
    virtual void                CalcAbsIfRel( const ScAddress& );
    virtual void                CalcRelFromAbs( const ScAddress& );
    virtual BOOL                operator==( const ScToken& rToken ) const;

    DECL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken );
};


class ScMatrixToken : public ScToken
{
private:
            ScMatrix*           pMatrix;
public:
                                ScMatrixToken( ScMatrix* p ) :
                                    ScToken( ocPush, svMatrix ), pMatrix( p ) {}
                                ScMatrixToken( OpCode e, ScMatrix* p ) :
                                    ScToken( e, svMatrix ), pMatrix( p ) {}
                                ScMatrixToken( const ScMatrixToken& r ) :
                                    ScToken( r ), pMatrix( r.pMatrix ) {}
    virtual ScMatrix*           GetMatrix() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScIndexToken : public ScToken
{
private:
            USHORT              nIndex;
public:
                                ScIndexToken( OpCode e, USHORT n ) :
                                    ScToken( e, svIndex ), nIndex( n ) {}
                                ScIndexToken( const ScIndexToken& r ) :
                                    ScToken( r ), nIndex( r.nIndex ) {}
    virtual USHORT              GetIndex() const;
    virtual void                SetIndex( USHORT n );
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScJumpToken : public ScToken
{
private:
            short*              pJump;
public:
                                ScJumpToken( OpCode e, short* p ) :
                                    ScToken( e, svJump )
                                {
                                    pJump = new short[ p[0] + 1 ];
                                    memcpy( pJump, p, (p[0] + 1) * sizeof(short) );
                                }
                                ScJumpToken( const ScJumpToken& r ) :
                                    ScToken( r )
                                {
                                    pJump = new short[ r.pJump[0] + 1 ];
                                    memcpy( pJump, r.pJump, (r.pJump[0] + 1) * sizeof(short) );
                                }
    virtual                     ~ScJumpToken();
    virtual short*              GetJump() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScExternalToken : public ScToken
{
private:
            String              aExternal;
            BYTE                nByte;
public:
                                ScExternalToken( OpCode e, BYTE n, const String& r ) :
                                    ScToken( e, svExternal ), nByte( n ),
                                    aExternal( r ) {}
                                ScExternalToken( OpCode e, const String& r ) :
                                    ScToken( e, svExternal ), nByte( 0 ),
                                    aExternal( r ) {}
                                ScExternalToken( const ScExternalToken& r ) :
                                    ScToken( r ), nByte( r.nByte ),
                                    aExternal( r.aExternal ) {}
    virtual const String&       GetExternal() const;
    virtual BYTE                GetByte() const;
    virtual void                SetByte( BYTE n );
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScMissingToken : public ScToken
{
public:
                                ScMissingToken() :
                                    ScToken( ocPush, svMissing ) {}
                                ScMissingToken( OpCode e ) :
                                    ScToken( e, svMissing ) {}
                                ScMissingToken( const ScMissingToken& r ) :
                                    ScToken( r ) {}
    virtual double              GetDouble() const;
    virtual const String&       GetString() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScErrToken : public ScToken
{
public:
                                ScErrToken( OpCode e ) :
                                    ScToken( e, svErr ) {}
                                ScErrToken( const ScErrToken& r ) :
                                    ScToken( r ) {}
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


class ScUnknownToken : public ScToken
{
private:
            BYTE*               pUnknown;
public:
                                ScUnknownToken( OpCode e, StackVar v, BYTE* p ) :
                                    ScToken( e, v )
                                {
                                    pUnknown = new BYTE[ int(p[0]) + 1 ];
                                    memcpy( pUnknown, p, int(p[0]) + 1 );
                                }
                                ScUnknownToken( const ScUnknownToken& r ) :
                                    ScToken( r )
                                {
                                    pUnknown = new BYTE[ int(r.pUnknown[0]) + 1 ];
                                    memcpy( pUnknown, r.pUnknown, int(r.pUnknown[0]) + 1 );
                                }
    virtual                     ~ScUnknownToken();
    virtual BYTE*               GetUnknown() const;
    virtual BOOL                operator==( const ScToken& rToken ) const;
};


// Simplify argument passing to RefUpdate methods with ScSingleRefToken or
// ScDoubleRefToken
class SingleDoubleRefModifier
{
    ComplRefData    aDub;
    SingleRefData*  pS;
    ComplRefData*   pD;

                // not implemented, prevent usage
                SingleDoubleRefModifier( const SingleDoubleRefModifier& );
        SingleDoubleRefModifier& operator=( const SingleDoubleRefModifier& );

public:
                SingleDoubleRefModifier( ScToken& rT )
                    {
                        if ( rT.GetType() == svSingleRef )
                        {
                            pS = &rT.GetSingleRef();
                            aDub.Ref1 = aDub.Ref2 = *pS;
                            pD = &aDub;
                        }
                        else
                        {
                            pS = 0;
                            pD = &rT.GetDoubleRef();
                        }
                    }
                SingleDoubleRefModifier( SingleRefData& rS )
                    {
                        pS = &rS;
                        aDub.Ref1 = aDub.Ref2 = *pS;
                        pD = &aDub;
                    }
                ~SingleDoubleRefModifier()
                    {
                        if ( pS )
                            *pS = (*pD).Ref1;
                    }
    inline  ComplRefData& Ref() { return *pD; }
};

class SingleDoubleRefProvider
{
public:

    const SingleRefData&    Ref1;
    const SingleRefData&    Ref2;

                SingleDoubleRefProvider( const ScToken& r )
                        : Ref1( r.GetSingleRef() ),
                        Ref2( r.GetType() == svDoubleRef ?
                        r.GetDoubleRef().Ref2 : Ref1 )
                    {}
                SingleDoubleRefProvider( const SingleRefData& r )
                        : Ref1( r ), Ref2( r )
                    {}
                SingleDoubleRefProvider( const ComplRefData& r )
                        : Ref1( r.Ref1 ), Ref2( r.Ref2 )
                    {}
                ~SingleDoubleRefProvider()
                    {}
};

#endif