///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoBTreeValue.cc
// -----------------
// Cego index value class implementation
//     
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2013 Bjoern Lemke
//
// 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, 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; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: CegoBTreeValue
// 
// Description: This class handles all operations on btree values. Since the values are sequentially stored
//              in a byte array, conversion methods are required to store, retrieve and for compare these values 
//
// Status : 2.16
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfc/Exception.h>

// cego includes
#include "CegoFieldValue.h"
#include "CegoBTreeValue.h"

#include <string.h>
#include <stdlib.h>

CegoBTreeValue::CegoBTreeValue()
{
    _pI = _idxArray;
}

CegoBTreeValue::CegoBTreeValue(char* p)
{
    _pI = p;
}

CegoBTreeValue::~CegoBTreeValue()
{
}

void CegoBTreeValue::valueFromSchema(ListT<CegoField>* pSchema, int len)
{        
    if ( len > TABMNG_MAXINDEXVALUE )
	throw Exception(EXLOC, "Index value exceeded");

    char* idxPtr = _pI;
    CegoField *pF = pSchema->First();
    while (pF)
    {
	int len = pF->getValue().getLength();
	if ( len > 0 )
	{
	    memcpy(idxPtr, pF->getValue().getValue(), len);

	    if ( pF->getLength() > len )
	    {		
		idxPtr += len;
		// mark end with zero byte
		*idxPtr = 0;
		idxPtr += pF->getLength() - ( len + 1 );
	    }
	    else
	    {
		idxPtr += len;
	    }
	}
	pF = pSchema->Next();
    }
}

void CegoBTreeValue::valueFromSchema(const ListT<CegoField> tableSchema, const ListT<CegoField> indexSchema)
{
    
    // get Index len
    int len = 0;
    CegoField* pIF = indexSchema.First();
    while (pIF)
    {
	len += pIF->getValue().getLength();
	pIF = indexSchema.Next();
    }

    if ( len > TABMNG_MAXINDEXVALUE )
	throw Exception(EXLOC, "Index value exceeded");

    char* idxPtr = _pI;
    pIF = indexSchema.First();
    while (pIF)
    {

	CegoField *pTF = tableSchema.First();

	while ( pTF )
	{
	    if ( (Chain)pTF->getAttrName() == (Chain)pIF->getAttrName() )
	    {

		int len = pTF->getValue().getLength();
		if ( len > 0 )
		{
		    memcpy(idxPtr, pTF->getValue().getValue(), len);
		    
		    if ( pTF->getLength() > len )
		    {		
			idxPtr += len;
			// mark end with zero byte
			*idxPtr = 0;
			idxPtr += pTF->getLength() - ( len + 1 );
		    }
		    else
		    {
			idxPtr += len;
		    }
		}
	    }
	    
	    pTF = tableSchema.Next();
	}

	pIF = indexSchema.Next();
    }    
}

ListT<CegoFieldValue> CegoBTreeValue::valueToFVL(const ListT<CegoField>& schema) const
{

    ListT<CegoFieldValue> fvl;

    char* idxPtr = _pI;
    CegoField* pF = schema.First();
    while (pF)
    {
	int len = pF->getLength();
	
	CegoFieldValue fv;
	
	if ( pF->getType() == VARCHAR_TYPE
	     || pF->getType() == BIGINT_TYPE
	     || pF->getType() == DECIMAL_TYPE
	     || pF->getType() == FIXED_TYPE )
	{
	    fv = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr));
	}
	else
	{
	    fv = CegoFieldValue(pF->getType(), idxPtr, len);
	}
		   	
	idxPtr+=len;
	
	fvl.Insert(fv);
	pF = schema.Next();
    }

    return fvl;
}

void CegoBTreeValue::setPtr(char* p)
{
    _pI = p;
 }

char* CegoBTreeValue::getPtr() const
{
    return _pI;
}
 
CegoBTreeValue& CegoBTreeValue::operator = (const CegoBTreeValue& iv)
{
    _pI = iv._pI;
    memcpy(_idxArray, iv._idxArray, TABMNG_MAXINDEXVALUE);
    return (*this);
}


CegoBTreeValue::Comparison CegoBTreeValue::comp(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
{

    char* idxPtr1 = _pI;
    char* idxPtr2 = iv.getPtr();
    
    CegoField* pF = pSchema->First();
    while (pF)
    {
	int len = pF->getLength();
	    
	CegoFieldValue fv1;
	CegoFieldValue fv2;
	
	/*
	if ( pF->getType() == VARCHAR_TYPE
	     || pF->getType() == BIGINT_TYPE
	     || pF->getType() == DECIMAL_TYPE
	     || pF->getType() == FIXED_TYPE )
	{
	    fv1 = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr1));
	    fv2 = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr2));
	}
	else
	{
	    fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
	    fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);	    
	}
	*/

	/* for performance reasons, we construct fieldvalue with pointer reference
           in case of VARCHAR & friend values len might be not correct, but for 
	   the used methods, it does't matter */

	fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
	fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);	    
	
	CegoFieldValue::Comparison c = fv1.comp(fv2);

	if ( c == CegoFieldValue::MORE )
	    return MORE;
	else if ( c == CegoFieldValue::LESS )
	    return LESS;

	idxPtr1+=len;
	idxPtr2+=len;	    
	pF = pSchema->Next();
		
    }

    return EQUAL;
}


bool CegoBTreeValue::isHigher(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
{

    char* idxPtr1 = _pI;
    char* idxPtr2 = iv.getPtr();
    
    CegoField* pF = pSchema->First();
    while (pF)
    {
	int len = pF->getLength();
	    
	CegoFieldValue fv1;
	CegoFieldValue fv2;

	/*
	if ( pF->getType() == VARCHAR_TYPE
	     || pF->getType() == BIGINT_TYPE
	     || pF->getType() == DECIMAL_TYPE
	     || pF->getType() == FIXED_TYPE )
	{
	    fv1 = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr1));
	    fv2 = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr2));
	}
	else
	{
	    fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
	    fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);
	    
	}
	*/

	fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
	fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);	    


	CegoFieldValue::Comparison c = fv1.comp(fv2);

	if ( c == CegoFieldValue::MORE )
	    return true;
	else if ( c == CegoFieldValue::LESS )
	    return false;

	idxPtr1+=len;
	idxPtr2+=len;	    
	pF = pSchema->Next();
		
    }

    return false;
}


bool CegoBTreeValue::isEqual(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
{
    
    char* idxPtr1 = _pI;
    char* idxPtr2 = iv.getPtr();
    
    CegoField* pF = pSchema->First();
    while (pF)
    {
	int len = pF->getLength();
	    
	CegoFieldValue fv1;
	CegoFieldValue fv2;
	
	/*
	if ( pF->getType() == VARCHAR_TYPE
	     || pF->getType() == BIGINT_TYPE
	     || pF->getType() == DECIMAL_TYPE
	     || pF->getType() == FIXED_TYPE )
	{
	    fv1 = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr1));
	    fv2 = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr2));
	}
	else
	{
	    fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
	    fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);
	    
	}
	*/

	fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
	fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);


	CegoFieldValue::Comparison c = fv1.comp(fv2);

	if ( c == CegoFieldValue::MORE )
	    return false;
	else if ( c == CegoFieldValue::LESS )
	    return false;

	idxPtr1+=len;
	idxPtr2+=len;	    
	pF = pSchema->Next();
		
    }

    return true;
}



bool CegoBTreeValue::operator > ( const CegoBTreeValue& iv) const
{
    return false;
}


Chain CegoBTreeValue::toChain(ListT<CegoField>* pSchema) const
{
    Chain s;

    char* idxPtr = _pI;
    CegoField* pF = pSchema->First();
    while (pF)
    {
	int len = pF->getLength();
	
	CegoFieldValue fv;
	
	if ( pF->getType() == VARCHAR_TYPE
	     || pF->getType() == BIGINT_TYPE
	     || pF->getType() == DECIMAL_TYPE
	     || pF->getType() == FIXED_TYPE )
	{
	    fv = CegoFieldValue(VARCHAR_TYPE, Chain(idxPtr));
	}
	else
	{
	    fv = CegoFieldValue(pF->getType(), idxPtr, len);
	}
	
	idxPtr+=len;
	
	s += fv.valAsChain();
	pF = pSchema->Next();
	if ( pF )
	    s += Chain(",");
    }
    
    return s;
}
