/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SC_TOKEN_HXX
#define SC_TOKEN_HXX

#include <bf_svtools/bf_solar.h>

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

#include "opcode.hxx"

#include "refdata.hxx"
namespace binfilter {


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
};

#ifndef DBG_UTIL
// 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  StackVar        GetType() const         { return eType; }
    inline  OpCode              GetOpCode() const       { return eOp;   }
            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;

    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 )
                                    , aExternal( r )
                                    , nByte( n )
                                    {}
                                ScExternalToken( OpCode e, const String& r )
                                    : ScToken( e, svExternal )
                                    , aExternal( r )
                                    , nByte( 0 )
                                    {}
                                ScExternalToken( const ScExternalToken& r )
                                    : ScToken( r )
                                    , aExternal( r.aExternal )
                                    , nByte( r.nByte )
                                    {}
    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()
                    {}
};

} //namespace binfilter
#endif

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