///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoOrderSpace.cc
// ------------------
// Cego order space 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: CegoOrderSpace
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

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

// cego includes
#include "CegoOrderSpace.h"
#include "CegoDataType.h"
#include "CegoTableManager.h"

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

CegoOrderSpace::CegoOrderSpace()
{
    _pAVL = new AVLTreeT<CegoOrderNode>;
}

CegoOrderSpace::~CegoOrderSpace()
{
    if ( _pAVL )
	delete _pAVL;
}

void CegoOrderSpace::initOrderSpace(ListT<CegoExpr*>* pOrderList, ListT<CegoOrderNode::Ordering>* pOrderOptList, long maxOrderSize)
{
    _pOrderList = pOrderList;
    _pOrderOptList = pOrderOptList;
    _maxOrderSize = maxOrderSize;
    _orderSize = 0;

    CegoExpr **pExpr = pOrderList->First();
    int id=1;
    while ( pExpr )
    {
	ListT<CegoAggregation*> aggList = (*pExpr)->getAggregationList();
	if ( aggList.Size() == 0 )
	{
	    // if no aggregation, we take all used attributes in order schema

	    ListT<CegoAttrDesc*> attrRefList = (*pExpr)->getAttrRefList();
	    
	    CegoAttrDesc** pAttrRef = attrRefList.First();
	    
	    while ( pAttrRef )
	    {
		CegoField f((*pAttrRef)->getTableName(), (*pAttrRef)->getAttrName());
		f.setId(id);
		_orderSchema.Insert(f);
		id++;
		pAttrRef = attrRefList.Next();
	    }
	}
	else
	{
	    // if aggregation, this is a grouping order, we just take the aggregated values

	    CegoAggregation **pAgg = aggList.First();
	    while ( pAgg )
	    {	    
		CegoField f;
		f.setAttrName("AGG");
		f.setId((*pAgg)->getAggregationId());
		_orderSchema.Insert(f);
		
		pAgg = aggList.Next();
	    }
	}
	pExpr = pOrderList->Next();
    }    
}

void CegoOrderSpace::insertTuple(ListT<CegoField>& addKey, ListT<CegoField>& addTuple)
{

    CegoField* pKF = addKey.First();
    CegoField* pOF = _orderSchema.First();
    while (pKF && pOF )
    {        
        pKF->setId(pOF->getId());
        pKF = addKey.Next();
        pOF = _orderSchema.Next();        
    }

    int id=1;
    CegoField *pF = addTuple.First();
    while (pF)
    {
	pF->setId(id);
	id++;
	pF = addTuple.Next();
    }

    ListT<CegoFieldValue> orderKey;
    
    CegoExpr **pExpr = _pOrderList->First();
    while ( pExpr )
    {
	setAggregationValue(*pExpr, addKey);	
	(*pExpr)->setFieldListArray(&addKey, 1);
	
	(*pExpr)->clearAttrCache();
	
	CegoFieldValue fv = (*pExpr)->evalFieldValue();
	
	orderKey.Insert(fv);
	
	pExpr = _pOrderList->Next();
    }
    
    CegoOrderNode n(orderKey, addTuple, _pOrderOptList);
    _orderSize += sizeof(n);

    if ( _orderSize > _maxOrderSize )
    {
	throw Exception(EXLOC, "Order size exceeded");
    }

    _pAVL->Insert(n);
}

void CegoOrderSpace::resetOrderSpace()
{    
    _pAVL->Empty();
    _orderSize = 0;
}

CegoOrderCursor* CegoOrderSpace::getCursor()
{
    CegoOrderCursor *pOC = new CegoOrderCursor(_pAVL);
    return pOC;
}

long CegoOrderSpace::numAllocated() const
{
    return _orderSize;
}

void CegoOrderSpace::setAggregationValue(CegoExpr *pExpr, ListT<CegoField>& fl)
{
    ListT<CegoAggregation*> aggList = pExpr->getAggregationList();
    
    CegoAggregation **pAgg = aggList.First();
    while ( pAgg )
    {
	CegoField *pF = fl.First();
	while ( pF )
	{
	    if ( pF->getId() == (*pAgg)->getAggregationId() )
	    {	
		(*pAgg)->setFieldValue(pF->getValue());
		pF = 0;
	    }
	    else
	    {
		pF = fl.Next();
	    }
	}
	pAgg = aggList.Next();
    }
}
