#ifndef JOIN_IRESULTSETOPERATOR_HPP
#define JOIN_IRESULTSETOPERATOR_HPP
/*!
 * @file
 * @brief generic interface for join result handling
 *
 * @author GertG
 * @ingroup Join
 *
 * @par last changed by:
 * <br>
 * $Author: d026026 $ $DateTime: 2007/04/10 17:59:46 $
 *
 * @sa Join_Execute.cpp
 */
/*

    ========== licence begin  GPL
    Copyright (c) 2003-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



*/
#include "Join/Join_Trace.hpp"
#include "Join/Join_Types.hpp"
#include "SAPDBCommon/SAPDB_Types.hpp"
#include "Container/Container_Vector.hpp"
#include "SQLManager/SQLMan_Context.hpp"
#include "ggg00.h"
#include "hak07.h"
#include "hgg01_3.h"
#include "hsp20.h"
#include "hta01.h"
#include "hkb721.h"

//! generic interface for join result handling
class Join_IResultSetOperator
{
public:
    //! @name constructor / destructor
    //@{
    //! constructor
    /*! 
     * @param acv [in] global context
     * @param rec_desc [in] pointer to result record description
     * @param rescnt [in] amount of records already in result set
     * @param maxrescnt [in] maximal amount of records in result set
     */
    Join_IResultSetOperator( 
            SQLMan_Context&         acv, 
            Join_StackListPtr&      rec_desc,
            const SAPDB_Int4&       rescnt,
            const SAPDB_Int4&       maxrescnt) : 
        m_acv(acv), m_ResultCnt(rescnt), m_MaxResultCnt(abs(maxrescnt)), 
        m_RecordDesc(rec_desc), m_opened(false),
        m_RecordCounterPositions( acv.GetAllocator() )
        {
            SAPDBTRACE_METHOD_DEBUG( "Join_IResultSetOperator::ctor", Join_Trace, 5 );
            SAPDBTRACE_WRITELN( Join_Trace, 3, "m_ResultCnt: " << m_ResultCnt << "\tm_MaxResultCnt: " << m_MaxResultCnt );
            m_RecordCounterPositions.Reserve(2);
            m_SetWarning = !( maxrescnt < 0 );
        }
        
    //! destructor
    virtual ~Join_IResultSetOperator() 
    {
        SAPDBTRACE_METHOD_DEBUG( "Join_IResultSetOperator::dtor", Join_Trace, 5 );
    }
    //@}

    //! initializes operator
    /*!
      * default implementation analyses result record and
      * detect ROWNO/ROWNUM positions
      */
    virtual void Open() 
    {
        SAPDBTRACE_METHOD_DEBUG( "Join_IResultSetOperator::Open", Join_Trace, 1 );
        // loop over record description and search st_rowno with st_output
        SAPDB_UInt4 _i = 1;
        SAPDB_UInt4 _outstop = (*m_RecordDesc)[ 0 ].epos() - 1;
        bool _mem_ok = true;

        while ( _i <= _outstop )
        {
            //loop to ROWNO 
            while ( _i <= _outstop && 
                   ( st_rowno != (*m_RecordDesc)[ _i - 1 ].etype() ))
                ++_i;
            // if no ROWNO found --> _i > _outstop!
            if ( _i <= _outstop && 
                 st_rowno == (*m_RecordDesc)[ _i - 1 ].etype() )
            {
                // loop to output column
                _i = k721out_entry( (tgg00_StackList*) m_RecordDesc.GetPtr(), _i );
                if ( st_output == (*m_RecordDesc)[ _i - 1 ].etype() ||
                     st_output_join == (*m_RecordDesc)[ _i - 1 ].etype() )
                {
                    if ( m_RecordCounterPositions.IsFull() ) 
                        m_RecordCounterPositions.Reserve( 2*m_RecordCounterPositions.GetSize() );
                    if ( st_output_join == (*m_RecordDesc)[ _i - 1 ].etype() )
                        _mem_ok = m_RecordCounterPositions.InsertEnd( (*m_RecordDesc)[ _i - 1 ].ecol_pos() );
                    else
                        _mem_ok = m_RecordCounterPositions.InsertEnd( (*m_RecordDesc)[ _i - 1 ].epos() );
                    if ( ! _mem_ok ) 
                    {
                        a07_b_put_error( m_acv, e_no_more_memory, 1 ); return;
                    }
                }
            }
            ++_i;
        }
#ifdef SAPDB_SLOW
        if ( !m_RecordCounterPositions.IsEmpty() )
        {
            SAPDBTRACE_WRITELN( Join_Trace, 3, "ROWNUM positions:" );
            Container_Vector<SAPDB_Int4>::Iterator _iter;
            for ( _iter = m_RecordCounterPositions.Begin(); _iter != m_RecordCounterPositions.End(); ++_iter) 
            {
                SAPDBTRACE_WRITELN( Join_Trace, 3, *_iter );
            }
        }
#endif
        m_opened = true;
    }

    //! finalize operator
    virtual void Close() { m_opened = false; }
    //! determine if operator is open
    SAPDB_Bool IsOpened() const { return m_opened; }

    //! @name manipulation of result set
    //@{
    //! add record to result set
    /*!
     * @param record [in] record to be added
     * @return information code <tt>[e_ok, e_no_next_record]</tt> / error code
     */
    virtual tgg00_BasisError Add( tgg00_Rec& record ) =0;
    //@}

    //! @name properties
    //@{
    //! return amount of records in result set
    virtual SAPDB_Int4 ResultCount() const { return m_ResultCnt; }
    //@}
    
protected:
    //! write result counter into record
    /*!
     * @param record [in] record on which to write result counter
     * @param count [in] result counter to write
     */
    void set_result_counter( tgg00_Rec &record, const SAPDB_Int4 count ) const
    {
        // add result counter to record
        s20ch4sw( count, g01code.kernel_swap, 
                record.recBody_gg00(), record.recKeyLen_gg00() - 3, 
                sw_normal );
    }


    // member variables
    SQLMan_Context&                 m_acv; //!< global context
    SAPDB_Int4                      m_ResultCnt; //!< ammount of result rows in result set
    SAPDB_Int4                      m_MaxResultCnt; //!< max. amount of result rows
    const Join_StackListPtr&       m_RecordDesc; //!< result record description
    SAPDB_Bool                      m_SetWarning; //!< set warning if result count exceed ROWNO amount
    
    Container_Vector<SAPDB_Int4>    m_RecordCounterPositions;
private:
    SAPDB_Bool              m_opened;
};

#endif // JOIN_IRESULTSETOPERATOR_HPP
