/*!
  @file           Table_Test.cpp
  @ingroup		  Table
  @author         UweH

\if EMIT_LICENCE
    ========== licence begin  GPL
    Copyright (c) 2000-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

\endif
*/

#include <memory.h> // memset

#include "SAPDBCommon/Algorithms/SAPDBAlgo_FunnelMerge.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_IRawAllocator.hpp"
#include "SAPDBCommon/Tracing/SAPDBTrace_Usage.hpp"
#include "SAPDBCommon/Fields/SAPDBFields_FieldList.hpp"
#include "RunTime/RTE_Message.hpp"
#include "KernelCommon/Kernel_VTrace.hpp"
#include "KernelCommon/Kernel_BlobDescription.hpp"
#include "Logging/Log_Transaction.hpp"
#include "Table/Table_Exceptions.hpp"
#include "Table/Table_TempHashTable.hpp"
#include "Table/Table_Table.hpp"
#include "Table/Table_UnsortedResult.hpp"
#include "Table/Table_Messages.hpp"
#include "Table/Table_Test.hpp"
#include "hkb53.h"
#include "ggg200.h"
#include "heo52.h"

/* --------------------------------------------------------------------------- */

class TestDataMerger : public Table_TempHashTableAggregate_IDataMerger
{
public:
    TestDataMerger( void ) { }

    virtual void MergeData(const SAPDB_Byte* Source, SAPDB_Byte* Destination, SAPDB_UInt2 Length, bool Found, bool SourceIsPartialAggregate)
    {
        if (!Found)
            memcpy(Destination, Source, Length);
        else
            *((SAPDB_UInt2*)&Destination[2]) += *((SAPDB_UInt2*)&Source[2]);
    }
};

/* --------------------------------------------------------------------------- */

bool TempHashTable_Test (tgg00_TransContext& TransContext, SAPDBErr_MessageList& errList)
{
    SAPDB_Byte  Data[512];
    SAPDB_Byte* DataPtr;

    SAPDBMem_IRawAllocator& Allocator = *( REINTERPRET_CAST(SAPDBMem_IRawAllocator*, TransContext.trAllocator_gg00) );

    Table_FixSizeEntry_FieldDescription     FieldDescription(Allocator);
    FieldDescription.Reserve(2);
    FieldDescription.InsertEnd(Table_OffsetLengthTuple(0,                  sizeof(SAPDB_Int4)));    // Data
    FieldDescription.InsertEnd(Table_OffsetLengthTuple(sizeof(SAPDB_Int4), sizeof(SAPDB_UInt4)));   // Key

    Table_FixSizeEntry_KeyNoList    KeyNoList(Allocator);
    KeyNoList.Reserve(1);
    KeyNoList.InsertEnd(1);

    SAPDB_UInt4 DataCnt = 100000;
    SAPDB_UInt4 KeyCnt  =   59; // must be smaller than DataCnt for testing

    TestDataMerger  DataMerger;

    TransContext.trError_gg00 = 0;

    Table_FixSizeTempHashTableAggregate TempHashTable
                                (   
                                    TransContext, 
                                    DataMerger, 
                                    512,
                                    FieldDescription, 
                                    KeyNoList,
                                    (SAPDB_UInt8) KeyCnt/2,
                                    errList
                                );

    if ( !TempHashTable.CompletelyConstructed() )
        return false;

    for (SAPDB_UInt4 i=0; i<DataCnt; i++)
    {
        *((SAPDB_Int4* )&Data[0]) = i%KeyCnt;
        *((SAPDB_UInt4*)&Data[4]) = i;

        SAPDB_Byte* D = Data;
        if ( !TempHashTable.InsertOrReplace(D, errList) )
            return false;
    }

    SAPDB_UInt4 Count = 0, Sum=0;
    if ( !TempHashTable.First(errList) )
        return false;

    do
    {
        DataPtr = TempHashTable.Get();
        SAPDB_Int4 Key; SAPDB_UInt4 Val;
        Key = *((SAPDB_Int4* )&DataPtr[0]);
        Val = *((SAPDB_UInt4*)&DataPtr[4]);
        ++Count;
        Sum+=Val;
    } while ( TempHashTable.Next() );

    if ( Count == KeyCnt && Sum == (DataCnt*(DataCnt-1)) >> 1 )
        return true;
    else
    {
        errList = Table_Exception(__CONTEXT__,TABLE_COMPONENT_TEST_FAILED,"IncorrectData");
        return false;
    }
}

/* --------------------------------------------------------------------------- */
externCpp void Table_Test (tgg00_TransContext& Trans)
{
    Table_Trace.SetTraceLevel(9);
    
    SAPDBTRACE_ROUTINE_DEBUG ("Table_Test", Table_Trace, 5);

    if ( 0 == Trans.trLogContext_gg00 )
    {
        Trans.trError_gg00 = e_not_implemented;
        return;
    }
    
    bool                                  anyErrorOccured = false;
    Table_Id                              tableId;
    Kernel_IndexDescription::IndexNumber  indexno = 1;
    SAPDBErr_MessageList                  errlist;
    tgg00_TransContext                    AuxTrans;

    Trans.trError_gg00 = e_ok;

    k53StartInternalSession (Trans, AuxTrans);
    if ( Trans.trError_gg00 != e_ok )
        return;

    Log_Transaction &transContext = *(reinterpret_cast<Log_Transaction*>(Trans.trLogContext_gg00));

    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;

        Table_Table table (transContext);
        
        if ( table.Create( Table_Table::visibilityLocal,
                           Table_Table::removeKindEndOfTrans,
                           tableId,
                           errlist ) != Table_Table::createOk )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }
    
    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;

        Kernel_IndexDescription indexDescr (transContext.Allocator(), indexno, true);
        Table_Table             table      (transContext, tableId);
        
        if ( table.AddIndex(indexDescr, errlist) != Table_Table::addIndexOk )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }
    
    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;

        Table_Table           table (transContext, tableId);
        SAPDBFields_FieldList fields;        

        if ( table.Insert(fields, errlist) != Table_Table::insertOk )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }
    
    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;

        Table_Table table (transContext, tableId);
        
        if ( table.DeleteIndex(indexno, errlist) != Table_Table::deleteIndexOk )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }

    
    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;

        Table_Table table (transContext, tableId);
        
        if ( table.DeleteIndex(indexno, errlist) != Table_Table::deleteIndexOk )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }
    
    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;

        Table_Table          table (transContext, tableId);
        Table_UnsortedResult result;
        
        if ( ! table.Select(result, errlist) )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }

    if ( ! anyErrorOccured )
    {
        Trans.trError_gg00 = e_ok;
        if ( !TempHashTable_Test(Trans, errlist) )
        {
            RTE_Message(errlist);
            errlist.ClearMessageList();
            // anyErrorOccured = true;
        }
    }

    k53StopInternalSession  (Trans, AuxTrans, m_rollback);

    if ( anyErrorOccured )
        Trans.trError_gg00 = e_invalid;

    Table_Trace.SetTraceLevel(0);
}
