/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"



// INCLUDE ---------------------------------------------------------------

#include <tools/debug.hxx>
#include <rtl/math.hxx>

#include "dptabdat.hxx"
#include "dptabres.hxx"
#include "dptabsrc.hxx"
#include "global.hxx"
#include "subtotal.hxx"
#include "globstr.hrc"
#include "datauno.hxx"		// ScDataUnoConversion

#include "document.hxx"     // for DumpState only!

#include <math.h>
#include <float.h>			//! Test !!!
#include <algorithm>
#include <hash_map>

#include <com/sun/star/sheet/DataResultFlags.hpp>
#include <com/sun/star/sheet/MemberResultFlags.hpp>
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
#include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>

using namespace com::sun::star;
using ::std::vector;
using ::std::pair;
using ::std::hash_map;
using ::com::sun::star::uno::Sequence;
using ::rtl::OUString;

// -----------------------------------------------------------------------

SV_IMPL_PTRARR( ScDPDataMembers, ScDPDataMemberPtr );

// -----------------------------------------------------------------------

static sal_uInt16 nFuncStrIds[12] =		// passend zum enum ScSubTotalFunc
{
	0,								// SUBTOTAL_FUNC_NONE
	STR_FUN_TEXT_AVG,				// SUBTOTAL_FUNC_AVE
	STR_FUN_TEXT_COUNT,				// SUBTOTAL_FUNC_CNT
	STR_FUN_TEXT_COUNT,				// SUBTOTAL_FUNC_CNT2
	STR_FUN_TEXT_MAX,				// SUBTOTAL_FUNC_MAX
	STR_FUN_TEXT_MIN,				// SUBTOTAL_FUNC_MIN
	STR_FUN_TEXT_PRODUCT,			// SUBTOTAL_FUNC_PROD
	STR_FUN_TEXT_STDDEV,			// SUBTOTAL_FUNC_STD
	STR_FUN_TEXT_STDDEV,			// SUBTOTAL_FUNC_STDP
	STR_FUN_TEXT_SUM,				// SUBTOTAL_FUNC_SUM
	STR_FUN_TEXT_VAR,				// SUBTOTAL_FUNC_VAR
	STR_FUN_TEXT_VAR				// SUBTOTAL_FUNC_VARP
};
namespace {
    template < typename T >
    void lcl_ResizePointVector( T & vec, size_t nSize )
    {

        for ( size_t i = 0 ; i < vec.size(); i++ )
        {
            if ( vec[i] )
                delete vec[i];	
        }
        vec.resize( nSize, NULL );
    }
	sal_Bool lcl_SearchMember( const std::vector <ScDPResultMember *>& list, SCROW nOrder, SCROW& rIndex)
	{
		rIndex = list.size();
		sal_Bool bFound = sal_False;
		SCROW  nLo = 0;
		SCROW nHi = list.size() - 1;
		SCROW nIndex;
		while (nLo <= nHi)
		{
			nIndex = (nLo + nHi) / 2;
			if ( list[nIndex]->GetOrder() < nOrder )
				nLo = nIndex + 1;
			else
			{
				nHi = nIndex - 1;
				if ( list[nIndex]->GetOrder() == nOrder )
				{
					bFound = sal_True;
					nLo = nIndex;
				}
			}
		}
		rIndex = nLo;
		return bFound;
	}
}
// -----------------------------------------------------------------------

//
// function objects for sorting of the column and row members:
//

class ScDPRowMembersOrder
{
    ScDPResultDimension& rDimension;
    long                 nMeasure;
    sal_Bool                 bAscending;

public:
            ScDPRowMembersOrder( ScDPResultDimension& rDim, long nM, sal_Bool bAsc ) :
                rDimension(rDim),
                nMeasure(nM),
                bAscending(bAsc)
            {}
            ~ScDPRowMembersOrder() {}

    sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
};

class ScDPColMembersOrder
{
    ScDPDataDimension& rDimension;
    long               nMeasure;
    sal_Bool               bAscending;

public:
            ScDPColMembersOrder( ScDPDataDimension& rDim, long nM, sal_Bool bAsc ) :
                rDimension(rDim),
                nMeasure(nM),
                bAscending(bAsc)
            {}
            ~ScDPColMembersOrder() {}

    sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
};

static sal_Bool lcl_IsLess( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure, sal_Bool bAscending )
{
    // members can be NULL if used for rows

    ScDPSubTotalState aEmptyState;
    const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : NULL;
    const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : NULL;

    sal_Bool bError1 = pAgg1 && pAgg1->HasError();
    sal_Bool bError2 = pAgg2 && pAgg2->HasError();
    if ( bError1 )
    {
        if ( bError2 )
            return sal_False;       // equal
        else
            return sal_False;       // errors are always sorted at the end
    }
    else if ( bError2 )
        return sal_True;            // errors are always sorted at the end
    else
    {
        double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0;    // no data is sorted as 0
        double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;

        // compare values
        // don't have to check approxEqual, as this is the only sort criterion

        return bAscending ? ( fVal1 < fVal2 ) : ( fVal1 > fVal2 );
    }
}

static sal_Bool lcl_IsEqual( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure )
{
    // members can be NULL if used for rows

    ScDPSubTotalState aEmptyState;
    const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : NULL;
    const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : NULL;

    sal_Bool bError1 = pAgg1 && pAgg1->HasError();
    sal_Bool bError2 = pAgg2 && pAgg2->HasError();
    if ( bError1 )
    {
        if ( bError2 )
            return sal_True;        // equal
        else
            return sal_False;
    }
    else if ( bError2 )
        return sal_False;
    else
    {
        double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0;    // no data is sorted as 0
        double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;

        // compare values
        // this is used to find equal data at the end of the AutoShow range, so approxEqual must be used

        return rtl::math::approxEqual( fVal1, fVal2 );
    }
}

sal_Bool ScDPRowMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
{
    const ScDPResultMember* pMember1 = rDimension.GetMember(nIndex1);
    const ScDPResultMember* pMember2 = rDimension.GetMember(nIndex2);
// Wang Xu Ming -- 3/17/2009

// make the hide item to the largest order.
	if ( !pMember1->IsVisible() || !pMember2->IsVisible() )
		return pMember1->IsVisible();
    const ScDPDataMember* pDataMember1 =  pMember1->GetDataRoot() ;
    const ScDPDataMember* pDataMember2 =  pMember2->GetDataRoot();
// End Comments
    //  GetDataRoot can be NULL if there was no data.
    //  IsVisible == sal_False can happen after AutoShow.
    return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
}

sal_Bool ScDPColMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
{
    ScDPDataMember* pDataMember1 = rDimension.GetMember(nIndex1);
    ScDPDataMember* pDataMember2 = rDimension.GetMember(nIndex2);
    // Wang Xu Ming -- 2009-6-17
        sal_Bool bHide1 = pDataMember1 && !pDataMember1->IsVisible();
        sal_Bool bHide2 =  pDataMember2 && !pDataMember2->IsVisible();
        if ( bHide1 || bHide2 )
            return !bHide1;
    // End Comments
    return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
}

// -----------------------------------------------------------------------

ScDPInitState::ScDPInitState() :
    nCount( 0 )
{
    pIndex = new long[SC_DAPI_MAXFIELDS];
    pData = new SCROW[SC_DAPI_MAXFIELDS];
}

ScDPInitState::~ScDPInitState()
{
    delete[] pIndex;
    delete[] pData;
}

void ScDPInitState::AddMember( long nSourceIndex, SCROW nMember )
{
    DBG_ASSERT( nCount < SC_DAPI_MAXFIELDS, "too many InitState members" );
    if ( nCount < SC_DAPI_MAXFIELDS )
    {
        pIndex[nCount] = nSourceIndex;
        pData[nCount] = nMember;
        ++nCount;
    }
}

void ScDPInitState::RemoveMember()
{
    DBG_ASSERT( nCount > 0, "RemoveColIndex without index" );
    if ( nCount > 0 )
        --nCount;
}

SCROW ScDPInitState::GetNameIdForIndex( long nIndexValue ) const
{
    for (long i=0; i<nCount; i++)
        if ( pIndex[i] == nIndexValue )
            return pData[i];

    return -1;    // not found
}

// -----------------------------------------------------------------------

void lcl_DumpRow( const String& rType, const String& rName, const ScDPAggData* pAggData,
                    ScDocument* pDoc, ScAddress& rPos )
{
    SCCOL nCol = rPos.Col();
    SCROW nRow = rPos.Row();
    SCTAB nTab = rPos.Tab();
    pDoc->SetString( nCol++, nRow, nTab, rType );
    pDoc->SetString( nCol++, nRow, nTab, rName );
    while ( pAggData )
    {
        pDoc->SetValue( nCol++, nRow, nTab, pAggData->GetResult() );
        pAggData = pAggData->GetExistingChild();
    }
    rPos.SetRow( nRow + 1 );
}

void lcl_Indent( ScDocument* pDoc, SCROW nStartRow, const ScAddress& rPos )
{
    SCCOL nCol = rPos.Col();
    SCTAB nTab = rPos.Tab();

    String aString;
    for (SCROW nRow = nStartRow; nRow < rPos.Row(); nRow++)
    {
        pDoc->GetString( nCol, nRow, nTab, aString );
        if ( aString.Len() )
        {
            aString.InsertAscii( "  ", 0 );
            pDoc->SetString( nCol, nRow, nTab, aString );
        }
    }
}

// -----------------------------------------------------------------------

ScDPRunningTotalState::ScDPRunningTotalState( ScDPResultMember* pColRoot, ScDPResultMember* pRowRoot ) :
    pColResRoot( pColRoot ),
    pRowResRoot( pRowRoot ),
    nColIndexPos( 0 ),
    nRowIndexPos( 0 )
{
    pColVisible = new long[SC_DAPI_MAXFIELDS+1];
    pColIndexes = new long[SC_DAPI_MAXFIELDS+1];
    pRowVisible = new long[SC_DAPI_MAXFIELDS+1];
    pRowIndexes = new long[SC_DAPI_MAXFIELDS+1];
    pColIndexes[0] = -1;
    pRowIndexes[0] = -1;
}

ScDPRunningTotalState::~ScDPRunningTotalState()
{
    delete[] pColVisible;
    delete[] pColIndexes;
    delete[] pRowVisible;
    delete[] pRowIndexes;
}

void ScDPRunningTotalState::AddColIndex( long nVisible, long nSorted )
{
    DBG_ASSERT( nColIndexPos < SC_DAPI_MAXFIELDS, "too many column indexes" );
    if ( nColIndexPos < SC_DAPI_MAXFIELDS )
    {
        pColVisible[nColIndexPos] = nVisible;
        pColIndexes[nColIndexPos] = nSorted;
        pColVisible[nColIndexPos+1] = -1;
        pColIndexes[nColIndexPos+1] = -1;
        ++nColIndexPos;
    }
}

void ScDPRunningTotalState::AddRowIndex( long nVisible, long nSorted )
{
    DBG_ASSERT( nRowIndexPos < SC_DAPI_MAXFIELDS, "too many row indexes" );
    if ( nRowIndexPos < SC_DAPI_MAXFIELDS )
    {
        pRowVisible[nRowIndexPos] = nVisible;
        pRowIndexes[nRowIndexPos] = nSorted;
        pRowVisible[nRowIndexPos+1] = -1;
        pRowIndexes[nRowIndexPos+1] = -1;
        ++nRowIndexPos;
    }
}

void ScDPRunningTotalState::RemoveColIndex()
{
    DBG_ASSERT( nColIndexPos > 0, "RemoveColIndex without index" );
    if ( nColIndexPos > 0 )
    {
        --nColIndexPos;
        pColVisible[nColIndexPos] = -1;
        pColIndexes[nColIndexPos] = -1;
    }
}

void ScDPRunningTotalState::RemoveRowIndex()
{
    DBG_ASSERT( nRowIndexPos > 0, "RemoveRowIndex without index" );
    if ( nRowIndexPos > 0 )
    {
        --nRowIndexPos;
        pRowVisible[nRowIndexPos] = -1;
        pRowIndexes[nRowIndexPos] = -1;
    }
}

// -----------------------------------------------------------------------

ScDPRelativePos::ScDPRelativePos( long nBase, long nDir ) :
    nBasePos( nBase ),
    nDirection( nDir )
{
}

// -----------------------------------------------------------------------

void ScDPAggData::Update( const ScDPValueData& rNext, ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
{
	if (nCount<0)		// error?
		return;			// nothing more...

	if ( rNext.nType == SC_VALTYPE_EMPTY )
		return;

	if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
														rSubState.eColForce != rSubState.eRowForce )
		return;
	if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
	if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;

	if ( eFunc == SUBTOTAL_FUNC_NONE )
		return;

	if ( eFunc != SUBTOTAL_FUNC_CNT2 )			// CNT2 counts everything, incl. strings and errors
	{
		if ( rNext.nType == SC_VALTYPE_ERROR )
		{
			nCount = -1;		// -1 for error (not for CNT2)
			return;
		}
		if ( rNext.nType == SC_VALTYPE_STRING )
			return;				// ignore
	}

	++nCount;			// for all functions

	switch (eFunc)
	{
		case SUBTOTAL_FUNC_SUM:
		case SUBTOTAL_FUNC_AVE:
			if ( !SubTotal::SafePlus( fVal, rNext.fValue ) )
				nCount = -1;							// -1 for error
			break;
		case SUBTOTAL_FUNC_PROD:
			if ( nCount == 1 )			// copy first value (fVal is initialized to 0)
				fVal = rNext.fValue;
			else if ( !SubTotal::SafeMult( fVal, rNext.fValue ) )
				nCount = -1;							// -1 for error
			break;
		case SUBTOTAL_FUNC_CNT:
		case SUBTOTAL_FUNC_CNT2:
			//	nothing more than incrementing nCount
			break;
		case SUBTOTAL_FUNC_MAX:
			if ( nCount == 1 || rNext.fValue > fVal )
				fVal = rNext.fValue;
			break;
		case SUBTOTAL_FUNC_MIN:
			if ( nCount == 1 || rNext.fValue < fVal )
				fVal = rNext.fValue;
			break;
		case SUBTOTAL_FUNC_STD:
		case SUBTOTAL_FUNC_STDP:
		case SUBTOTAL_FUNC_VAR:
		case SUBTOTAL_FUNC_VARP:
			{
				// fAux is used to sum up squares
				if ( !SubTotal::SafePlus( fVal, rNext.fValue ) )
					nCount = -1;							// -1 for error
				double fAdd = rNext.fValue;
				if ( !SubTotal::SafeMult( fAdd, rNext.fValue ) ||
					 !SubTotal::SafePlus( fAux, fAdd ) )
					nCount = -1;							// -1 for error
			}
			break;
		default:
			DBG_ERROR("invalid function");
	}
}

void ScDPAggData::Calculate( ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
{
	//	calculate the original result
	//	(without reference value, used as the basis for reference value calculation)

    //  called several times at the cross-section of several subtotals - don't calculate twice then
    if ( IsCalculated() )
        return;

	if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
	if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;

    if ( eFunc == SUBTOTAL_FUNC_NONE )      // this happens when there is no data dimension
    {
        nCount = SC_DPAGG_RESULT_EMPTY;     // make sure there's a valid state for HasData etc.
        return;
    }

	//	check the error conditions for the selected function

	sal_Bool bError = sal_False;
	switch (eFunc)
	{
		case SUBTOTAL_FUNC_SUM:
		case SUBTOTAL_FUNC_PROD:
		case SUBTOTAL_FUNC_CNT:
		case SUBTOTAL_FUNC_CNT2:
			bError = ( nCount < 0 );		// only real errors
			break;

		case SUBTOTAL_FUNC_AVE:
		case SUBTOTAL_FUNC_MAX:
		case SUBTOTAL_FUNC_MIN:
		case SUBTOTAL_FUNC_STDP:
		case SUBTOTAL_FUNC_VARP:
			bError = ( nCount <= 0 );		// no data is an error
			break;

		case SUBTOTAL_FUNC_STD:
		case SUBTOTAL_FUNC_VAR:
			bError = ( nCount < 2 );		// need at least 2 values
			break;

		default:
			DBG_ERROR("invalid function");
	}

	//	calculate the selected function

	double fResult = 0.0;
	if ( !bError )
	{
		switch (eFunc)
		{
			case SUBTOTAL_FUNC_MAX:
			case SUBTOTAL_FUNC_MIN:
			case SUBTOTAL_FUNC_SUM:
			case SUBTOTAL_FUNC_PROD:
				//	different error conditions are handled above
				fResult = fVal;
				break;

			case SUBTOTAL_FUNC_CNT:
			case SUBTOTAL_FUNC_CNT2:
				fResult = nCount;
				break;

			case SUBTOTAL_FUNC_AVE:
				if ( nCount > 0 )
					fResult = fVal / (double) nCount;
				break;

			//!	use safe mul for fVal * fVal

			case SUBTOTAL_FUNC_STD:
				if ( nCount >= 2 )
					fResult = sqrt((fAux - fVal*fVal/(double)(nCount)) / (double)(nCount-1));
				break;
			case SUBTOTAL_FUNC_VAR:
				if ( nCount >= 2 )
					fResult = (fAux - fVal*fVal/(double)(nCount)) / (double)(nCount-1);
				break;
			case SUBTOTAL_FUNC_STDP:
				if ( nCount > 0 )
					fResult = sqrt((fAux - fVal*fVal/(double)(nCount)) / (double)nCount);
				break;
			case SUBTOTAL_FUNC_VARP:
				if ( nCount > 0 )
					fResult = (fAux - fVal*fVal/(double)(nCount)) / (double)nCount;
				break;
			default:
				DBG_ERROR("invalid function");
		}
	}

	sal_Bool bEmpty = ( nCount == 0 );			// no data

	//	store the result
	//	Empty is checked first, so empty results are shown empty even for "average" etc.
	//	If these results should be treated as errors in reference value calculations,
	//	a separate state value (EMPTY_ERROR) is needed.
	//	Now, for compatibility, empty "average" results are counted as 0.

	if ( bEmpty )
		nCount = SC_DPAGG_RESULT_EMPTY;
	else if ( bError )
		nCount = SC_DPAGG_RESULT_ERROR;
	else
		nCount = SC_DPAGG_RESULT_VALID;

	if ( bEmpty || bError )
		fResult = 0.0;		// default, in case the state is later modified

//  fprintf(stdout, "ScDPAggData::Calculate: result = %g\n", fResult);fflush(stdout);
	fVal = fResult;			// used directly from now on
	fAux = 0.0;				// used for running total or original result of reference value
}

sal_Bool ScDPAggData::IsCalculated() const
{
    return ( nCount <= SC_DPAGG_RESULT_EMPTY );
}

double ScDPAggData::GetResult() const
{
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    return fVal;        // use calculated value
}

sal_Bool ScDPAggData::HasError() const
{
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    return ( nCount == SC_DPAGG_RESULT_ERROR );
}

sal_Bool ScDPAggData::HasData() const
{
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    return ( nCount != SC_DPAGG_RESULT_EMPTY );     // values or error
}

void ScDPAggData::SetResult( double fNew )
{
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    fVal = fNew;        // don't reset error flag
}

void ScDPAggData::SetError()
{
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    nCount = SC_DPAGG_RESULT_ERROR;
}

void ScDPAggData::SetEmpty( sal_Bool bSet )
{
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    if ( bSet )
        nCount = SC_DPAGG_RESULT_EMPTY;
    else
        nCount = SC_DPAGG_RESULT_VALID;
}

double ScDPAggData::GetAuxiliary() const
{
    // after Calculate, fAux is used as auxiliary value for running totals and reference values
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    return fAux;
}

void ScDPAggData::SetAuxiliary( double fNew )
{
    // after Calculate, fAux is used as auxiliary value for running totals and reference values
    DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );

    fAux = fNew;
}

ScDPAggData* ScDPAggData::GetChild()
{
    if (!pChild)
        pChild = new ScDPAggData;
    return pChild;
}

void ScDPAggData::Reset()
{
	fVal = 0.0;
	fAux = 0.0;
	nCount = SC_DPAGG_EMPTY;
	delete pChild;
	pChild = NULL;
}

// -----------------------------------------------------------------------

ScDPRowTotals::ScDPRowTotals() :
    bIsInColRoot( sal_False )
{
}

ScDPRowTotals::~ScDPRowTotals()
{
}

ScDPAggData* lcl_GetChildTotal( ScDPAggData* pFirst, long nMeasure )
{
    DBG_ASSERT( nMeasure >= 0, "GetColTotal: no measure" );

    ScDPAggData* pAgg = pFirst;
    long nSkip = nMeasure;

    // subtotal settings are ignored - colum/row totals exist once per measure

    for ( long nPos=0; nPos<nSkip; nPos++ )
        pAgg = pAgg->GetChild();    // column total is constructed empty - children need to be created

    if ( !pAgg->IsCalculated() )
    {
        // for first use, simulate an empty calculation
        ScDPSubTotalState aEmptyState;
        pAgg->Calculate( SUBTOTAL_FUNC_SUM, aEmptyState );
    }

    return pAgg;
}

ScDPAggData* ScDPRowTotals::GetRowTotal( long nMeasure )
{
    return lcl_GetChildTotal( &aRowTotal, nMeasure );
}

ScDPAggData* ScDPRowTotals::GetGrandTotal( long nMeasure )
{
    return lcl_GetChildTotal( &aGrandTotal, nMeasure );
}

// -----------------------------------------------------------------------

static ScSubTotalFunc lcl_GetForceFunc( const ScDPLevel* pLevel, long nFuncNo )
{
	ScSubTotalFunc eRet = SUBTOTAL_FUNC_NONE;
	if ( pLevel )
	{
		//!	direct access via ScDPLevel

		uno::Sequence<sheet::GeneralFunction> aSeq = pLevel->getSubTotals();
        long nSequence = aSeq.getLength();
        if ( nSequence && aSeq[0] != sheet::GeneralFunction_AUTO )
        {
            // For manual subtotals, "automatic" is added as first function.
            // ScDPResultMember::GetSubTotalCount adds to the count, here NONE has to be
            // returned as the first function then.

            --nFuncNo;      // keep NONE for first (check below), move the other entries
        }

		if ( nFuncNo >= 0 && nFuncNo < nSequence )
		{
			sheet::GeneralFunction eUser = aSeq.getConstArray()[nFuncNo];
			if (eUser != sheet::GeneralFunction_AUTO)
				eRet = ScDataUnoConversion::GeneralToSubTotal( eUser );
		}
	}
	return eRet;
}

// -----------------------------------------------------------------------

ScDPResultData::ScDPResultData( ScDPSource* pSrc ) :		//! Ref
	pSource( pSrc ),
	nMeasCount( 0 ),
	pMeasFuncs( NULL ),
	pMeasRefs( NULL ),
	pMeasRefOrient( NULL ),
	pMeasNames( NULL ),
	bLateInit( sal_False ),
	bDataAtCol( sal_False ),
	bDataAtRow( sal_False )
{

	lcl_ResizePointVector( mpDimMembers , SC_DAPI_MAXFIELDS );
}

ScDPResultData::~ScDPResultData()
{
	delete[] pMeasFuncs;
	delete[] pMeasRefs;
	delete[] pMeasRefOrient;
	delete[] pMeasNames;

      lcl_ResizePointVector( mpDimMembers , 0 );
}

void ScDPResultData::SetMeasureData( long nCount, const ScSubTotalFunc* pFunctions,
									const sheet::DataPilotFieldReference* pRefs, const sal_uInt16* pRefOrient,
									const String* pNames )
{
	delete[] pMeasFuncs;
	delete[] pMeasRefs;
	delete[] pMeasRefOrient;
	delete[] pMeasNames;
	if ( nCount )
	{
		nMeasCount = nCount;
		pMeasFuncs = new ScSubTotalFunc[nCount];
		pMeasRefs  = new sheet::DataPilotFieldReference[nCount];
		pMeasRefOrient = new sal_uInt16[nCount];
		pMeasNames = new String[nCount];
		for (long i=0; i<nCount; i++)
		{
			pMeasFuncs[i] = pFunctions[i];
			pMeasRefs[i]  = pRefs[i];
			pMeasRefOrient[i] = pRefOrient[i];
			pMeasNames[i] = pNames[i];
		}
	}
	else
	{
		//	use one dummy measure
		nMeasCount = 1;
		pMeasFuncs = new ScSubTotalFunc[1];
		pMeasFuncs[0] = SUBTOTAL_FUNC_NONE;
		pMeasRefs  = new sheet::DataPilotFieldReference[1];	// default ctor is ok
		pMeasRefOrient = new sal_uInt16[1];
		pMeasRefOrient[0] = sheet::DataPilotFieldOrientation_HIDDEN;
		pMeasNames = new String[1];
		pMeasNames[0] = ScGlobal::GetRscString( STR_EMPTYDATA );
	}
}

void ScDPResultData::SetDataLayoutOrientation( sal_uInt16 nOrient )
{
	bDataAtCol = ( nOrient == sheet::DataPilotFieldOrientation_COLUMN );
	bDataAtRow = ( nOrient == sheet::DataPilotFieldOrientation_ROW );
}

void ScDPResultData::SetLateInit( sal_Bool bSet )
{
	bLateInit = bSet;
}

long ScDPResultData::GetColStartMeasure() const
{
	if ( nMeasCount == 1 ) return 0;
	return bDataAtCol ? SC_DPMEASURE_ALL : SC_DPMEASURE_ANY;
}

long ScDPResultData::GetRowStartMeasure() const
{
	if ( nMeasCount == 1 ) return 0;
	return bDataAtRow ? SC_DPMEASURE_ALL : SC_DPMEASURE_ANY;
}

ScSubTotalFunc ScDPResultData::GetMeasureFunction(long nMeasure) const
{
	DBG_ASSERT( pMeasFuncs && nMeasure < nMeasCount, "bumm" );
	return pMeasFuncs[nMeasure];
}

const sheet::DataPilotFieldReference& ScDPResultData::GetMeasureRefVal(long nMeasure) const
{
    DBG_ASSERT( pMeasRefs && nMeasure < nMeasCount, "bumm" );
    return pMeasRefs[nMeasure];
}

sal_uInt16 ScDPResultData::GetMeasureRefOrient(long nMeasure) const
{
    DBG_ASSERT( pMeasRefOrient && nMeasure < nMeasCount, "bumm" );
    return pMeasRefOrient[nMeasure];
}

String ScDPResultData::GetMeasureString(long nMeasure, sal_Bool bForce, ScSubTotalFunc eForceFunc, bool& rbTotalResult) const
{
	//	with bForce==sal_True, return function instead of "result" for single measure
	//	with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
    rbTotalResult = false;
	if ( nMeasure < 0 || ( nMeasCount == 1 && !bForce && eForceFunc == SUBTOTAL_FUNC_NONE ) )
	{
		//	for user-specified subtotal function with all measures,
		//	display only function name
		if ( eForceFunc != SUBTOTAL_FUNC_NONE )
			return ScGlobal::GetRscString(nFuncStrIds[eForceFunc]);

        rbTotalResult = true;
		return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS);
	}
	else
	{
		DBG_ASSERT( pMeasNames && nMeasure < nMeasCount, "bumm" );
        ScDPDimension* pDataDim = pSource->GetDataDimension(nMeasure);
        if (pDataDim)
        {
            const OUString* pLayoutName = pDataDim->GetLayoutName();
            if (pLayoutName)
                return *pLayoutName;
        }
		String aRet;
		ScSubTotalFunc eFunc = ( eForceFunc == SUBTOTAL_FUNC_NONE ) ?
									GetMeasureFunction(nMeasure) : eForceFunc;
		sal_uInt16 nId = nFuncStrIds[eFunc];
		if (nId)
		{
			aRet += ScGlobal::GetRscString(nId);		// function name
			aRet.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " - " ));
		}
		aRet += pMeasNames[nMeasure];					// field name

		return aRet;
	}
}

String ScDPResultData::GetMeasureDimensionName(long nMeasure) const
{
	if ( nMeasure < 0 )
	{
		DBG_ERROR("GetMeasureDimensionName: negative");
		return String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("***"));
	}

	return pSource->GetDataDimName( nMeasure );
}

sal_Bool ScDPResultData::IsBaseForGroup( long nDim ) const
{
    return pSource->GetData()->IsBaseForGroup( nDim );
}

long ScDPResultData::GetGroupBase( long nGroupDim ) const
{
    return pSource->GetData()->GetGroupBase( nGroupDim );
}

sal_Bool ScDPResultData::IsNumOrDateGroup( long nDim ) const
{
    return pSource->GetData()->IsNumOrDateGroup( nDim );
}

sal_Bool ScDPResultData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
                                long nBaseDataId, long nBaseIndex ) const
{
    const ScDPItemData* pData = pSource->GetItemDataById( nGroupIndex , nBaseDataId);
    if ( pData )
         return pSource->GetData()->IsInGroup( rGroupData, nGroupIndex, *pData , nBaseIndex );
    else 
        return sal_False;
}
sal_Bool ScDPResultData::IsInGroup( SCROW nGroupDataId, long nGroupIndex,
                                                               const ScDPItemData& rBaseData, long nBaseIndex ) const
{
    const ScDPItemData* pGroupData = pSource->GetItemDataById( nGroupIndex , nGroupDataId);
    if ( pGroupData )
        return pSource->GetData()->IsInGroup( *pGroupData, nGroupIndex, rBaseData , nBaseIndex );
    else 
        return sal_False;
}

sal_Bool ScDPResultData::HasCommonElement(/* const ScDPItemData& rFirstData*/SCROW nFirstDataId, long nFirstIndex,
                                       const ScDPItemData& rSecondData, long nSecondIndex ) const
{
    const ScDPItemData* pFirstData = pSource->GetItemDataById( nFirstIndex , nFirstDataId);
    if ( pFirstData )
        return pSource->GetData()->HasCommonElement( *pFirstData, nFirstIndex, rSecondData, nSecondIndex );
    else
        return sal_False;
}

const ScDPSource* ScDPResultData::GetSource() const
{
    return pSource;
}

ResultMembers* ScDPResultData::GetDimResultMembers( long nDim ,  ScDPDimension* pDim, ScDPLevel*   pLevel) const 
{
 	 if ( mpDimMembers[ nDim ] == NULL ) 
        {

                //long nDimSource = pDim->GetDimension(); 
            	 
	            ResultMembers* pResultMembers = new ResultMembers();
	            // global order is used to initialize aMembers, so it doesn't have to be looked at later
	            const ScMemberSortOrder& rGlobalOrder = pLevel->GetGlobalOrder();
            	 	 
	            ScDPMembers* pMembers = pLevel->GetMembersObject();
	            long nMembCount = pMembers->getCount();
	            for ( long i=0; i<nMembCount; i++ )
	            {
		            long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
		            ScDPMember* pMember = pMembers->getByIndex(nSorted);
		            if ( NULL == pResultMembers->FindMember( pMember->GetItemDataId() ) )
		            {
			                ScDPParentDimData* pNew = new ScDPParentDimData( i, pDim, pLevel, pMember );
                          		  pResultMembers->InsertMember(  pNew );
		            }
	            }

                mpDimMembers[ nDim ] = pResultMembers;
        }
        return   mpDimMembers[ nDim ];

}

// -----------------------------------------------------------------------


ScDPResultMember::ScDPResultMember(  const ScDPResultData* pData, const ScDPParentDimData& rParentDimData ,
									sal_Bool bForceSub ) :
	pResultData( pData ),
   	aParentDimData( rParentDimData ),
	pChildDimension( NULL ),
	pDataRoot( NULL ),
	bHasElements( sal_False ),
	bForceSubTotal( bForceSub ),
	bHasHiddenDetails( sal_False ),
	bInitialized( sal_False ),
    bAutoHidden( sal_False ),
    nMemberStep( 1 )
{
	// pParentLevel/pMemberDesc is 0 for root members
}

ScDPResultMember::ScDPResultMember(  const ScDPResultData* pData, 
									sal_Bool bForceSub ) :
	pResultData( pData ),
    	pChildDimension( NULL ),
	pDataRoot( NULL ),
	bHasElements( sal_False ),
	bForceSubTotal( bForceSub ),
	bHasHiddenDetails( sal_False ),
	bInitialized( sal_False ),
    bAutoHidden( sal_False ),
    nMemberStep( 1 )
{
}
ScDPResultMember::~ScDPResultMember()
{
	delete pChildDimension;
	delete pDataRoot;
}

String ScDPResultMember::GetName() const
{
  const ScDPMember*   pMemberDesc = GetDPMember();
	if (pMemberDesc)
		return pMemberDesc->GetNameStr();
	else
		return ScGlobal::GetRscString(STR_PIVOT_TOTAL);			// root member
}

void ScDPResultMember::FillItemData( ScDPItemData& rData ) const
{
    const ScDPMember*   pMemberDesc = GetDPMember();
    if (pMemberDesc)
        pMemberDesc->FillItemData( rData );
    else
        rData.SetString( ScGlobal::GetRscString(STR_PIVOT_TOTAL) );     // root member
}

sal_Bool ScDPResultMember::IsNamedItem( SCROW nIndex ) const
{
	//!	store ScDPMember pointer instead of ScDPMember ???
  const ScDPMember*   pMemberDesc = GetDPMember();
	if (pMemberDesc)
		return ((ScDPMember*)pMemberDesc)->IsNamedItem( nIndex  );
	return sal_False;
}

bool ScDPResultMember::IsValidEntry( const vector< SCROW >& aMembers ) const
{
    if ( !IsValid() )
        return false;

    const ScDPResultDimension* pChildDim = GetChildDimension();
    if (pChildDim)
    {
        if (aMembers.size() < 2)
            return false;

        vector<SCROW>::const_iterator itr = aMembers.begin();
        vector<SCROW> aChildMembers(++itr, aMembers.end());
        return pChildDim->IsValidEntry(aChildMembers);
    }
    else
        return true;
}

void ScDPResultMember::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev, 
                                 size_t nPos, ScDPInitState& rInitState ,
                                 sal_Bool bInitChild /*= sal_True */)
{
	//	with LateInit, initialize only those members that have data
	if ( pResultData->IsLateInit() )
		return;

	bInitialized = sal_True;

    if (nPos >= ppDim.size())
        return;

	//	skip child dimension if details are not shown
	if ( GetDPMember() && !GetDPMember()->getShowDetails() )
	{
         // Wang Xu Ming -- 2009-6-16
        // Show DataLayout dimention
        nMemberStep = 1;
        while ( nPos < ppDim.size() )
        {
            if (  ppDim[nPos] ->getIsDataLayoutDimension() )
            {
                 if ( !pChildDimension )
                        pChildDimension = new ScDPResultDimension( pResultData );
                    pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState , sal_False );
					return;
            }
            else 
            { //find next dim
                nPos ++;
                nMemberStep ++;
            }
        }
        // End Comments
        bHasHiddenDetails = sal_True;	// only if there is a next dimension
		return;
	}
    
    if ( bInitChild )
    {
        pChildDimension = new ScDPResultDimension( pResultData );
        pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState, sal_True  );
    }
}

void ScDPResultMember::LateInitFrom( LateInitParams& rParams/*const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev*/, 
                                     const vector< SCROW >& pItemData,   size_t nPos,
                                     ScDPInitState& rInitState )
{
	//	without LateInit, everything has already been initialized
	if ( !pResultData->IsLateInit() )
		return;

	bInitialized = sal_True;

    if ( rParams.IsEnd( nPos )  /*nPos >= ppDim.size()*/)
        // No next dimension.  Bail out.
        return;

    //	skip child dimension if details are not shown
    if ( GetDPMember() && !GetDPMember()->getShowDetails() )
    {
        // Wang Xu Ming -- 2009-6-16
        // DataPilot Migration
        // Show DataLayout dimention
        nMemberStep = 1;
        while ( !rParams.IsEnd( nPos ) )
        {
            if (  rParams.GetDim( nPos ) ->getIsDataLayoutDimension() )
            {
                if ( !pChildDimension )
                    pChildDimension = new ScDPResultDimension( pResultData );

                // #i111462# reset InitChild flag only for this child dimension's LateInitFrom call,
                // not for following members of parent dimensions
                sal_Bool bWasInitChild = rParams.GetInitChild();
                rParams.SetInitChild( sal_False );
                pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
                rParams.SetInitChild( bWasInitChild );
                return;
            }
            else 
            { //find next dim
                nPos ++;
                nMemberStep ++;
            }
        }
        // End Comments
        bHasHiddenDetails = sal_True;   // only if there is a next dimension
        return;
    }

    //	LateInitFrom is called several times...
    if ( rParams.GetInitChild() )
    {
        if ( !pChildDimension )
            pChildDimension = new ScDPResultDimension( pResultData );
        pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
    }
}

sal_Bool ScDPResultMember::IsSubTotalInTitle(long nMeasure) const
{
    sal_Bool bRet = sal_False;
    if ( pChildDimension && /*pParentLevel*/GetParentLevel() &&
         /*pParentLevel*/GetParentLevel()->IsOutlineLayout() && /*pParentLevel*/GetParentLevel()->IsSubtotalsAtTop() )
    {
        long nUserSubStart;
        long nSubTotals = GetSubTotalCount( &nUserSubStart );
        nSubTotals -= nUserSubStart;            // visible count
        if ( nSubTotals )
        {
            if ( nMeasure == SC_DPMEASURE_ALL )
                nSubTotals *= pResultData->GetMeasureCount();   // number of subtotals that will be inserted

            // only a single subtotal row will be shown in the outline title row
            if ( nSubTotals == 1 )
                bRet = sal_True;
        }
    }
    return bRet;
}

long ScDPResultMember::GetSize(long nMeasure) const
{
	if ( !IsVisible() )
		return 0;
    const ScDPLevel*	   pParentLevel = GetParentLevel();
    long nExtraSpace = 0;
    if ( pParentLevel && pParentLevel->IsAddEmpty() )
        ++nExtraSpace;

	if ( pChildDimension )
	{
        //  outline layout takes up an extra row for the title only if subtotals aren't shown in that row
        if ( pParentLevel && pParentLevel->IsOutlineLayout() && !IsSubTotalInTitle( nMeasure ) )
            ++nExtraSpace;

		long nSize = pChildDimension->GetSize(nMeasure);
		long nUserSubStart;
		long nUserSubCount = GetSubTotalCount( &nUserSubStart );
		nUserSubCount -= nUserSubStart;     // for output size, use visible count
		if ( nUserSubCount )
		{
			if ( nMeasure == SC_DPMEASURE_ALL )
				nSize += pResultData->GetMeasureCount() * nUserSubCount;
			else
				nSize += nUserSubCount;
		}
		return nSize + nExtraSpace;
	}
	else
	{
		if ( nMeasure == SC_DPMEASURE_ALL )
			return pResultData->GetMeasureCount() + nExtraSpace;
		else
			return 1 + nExtraSpace;
	}
}

sal_Bool ScDPResultMember::IsVisible() const
{
	//	not initialized -> shouldn't be there at all
	//	(allocated only to preserve ordering)
   const ScDPLevel*	pParentLevel = GetParentLevel();
	return ( bHasElements || ( pParentLevel && pParentLevel->getShowEmpty() ) ) && IsValid() && bInitialized;
}

sal_Bool ScDPResultMember::IsValid() const
{
	//	non-Valid members are left out of calculation

	//	was member set no invisible at the DataPilotSource?
  const ScDPMember*		pMemberDesc =GetDPMember();
	if ( pMemberDesc && !pMemberDesc->getIsVisible() )
		return sal_False;

    if ( bAutoHidden )
        return sal_False;

	return sal_True;
}

sal_Bool ScDPResultMember::HasHiddenDetails() const
{
    // bHasHiddenDetails is set only if the "show details" flag is off,
    // and there was a child dimension to skip

    return bHasHiddenDetails;
}

long ScDPResultMember::GetSubTotalCount( long* pUserSubStart ) const
{
    if ( pUserSubStart )
        *pUserSubStart = 0;     // default

   const ScDPLevel*	pParentLevel = GetParentLevel();

	if ( bForceSubTotal )		// set if needed for root members
		return 1;				// grand total is always "automatic"
	else if ( pParentLevel )
	{
		//!	direct access via ScDPLevel

        uno::Sequence<sheet::GeneralFunction> aSeq = pParentLevel->getSubTotals();
        long nSequence = aSeq.getLength();
        if ( nSequence && aSeq[0] != sheet::GeneralFunction_AUTO )
        {
            // For manual subtotals, always add "automatic" as first function
            // (used for calculation, but not for display, needed for sorting, see lcl_GetForceFunc)

            ++nSequence;
            if ( pUserSubStart )
                *pUserSubStart = 1;     // visible subtotals start at 1
        }
        return nSequence;
	}
	else
		return 0;
}

void ScDPResultMember::ProcessData( const vector< SCROW >& aChildMembers, const ScDPResultDimension* pDataDim,
                                    const vector< SCROW >& aDataMembers, const vector<ScDPValueData>& aValues )
{
    SetHasElements();

    if (pChildDimension)
        pChildDimension->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );

    if ( !pDataRoot )
    {
        pDataRoot = new ScDPDataMember( pResultData, NULL );
        if ( pDataDim )
            pDataRoot->InitFrom( pDataDim );            // recursive
    }

    ScDPSubTotalState aSubState;        // initial state

    long nUserSubCount = GetSubTotalCount();

    // Calculate at least automatic if no subtotals are selected,
    // show only own values if there's no child dimension (innermost).
    if ( !nUserSubCount || !pChildDimension )
        nUserSubCount = 1;
  
    const ScDPLevel*	pParentLevel = GetParentLevel();

    for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++)   // including hidden "automatic"
    {
        // #i68338# if nUserSubCount is 1 (automatic only), don't set nRowSubTotalFunc
        if ( pChildDimension && nUserSubCount > 1 )
        {
            aSubState.nRowSubTotalFunc = nUserPos;
            aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
        }

        pDataRoot->ProcessData( aDataMembers, aValues, aSubState );
    }
}

/** 
 * Parse subtotal string and replace all occurrences of '?' with the caption
 * string.  Do ensure that escaped characters are not translated.
 */ 
static String lcl_parseSubtotalName(const String& rSubStr, const String& rCaption)
{
    String aNewStr;
    xub_StrLen n = rSubStr.Len();
    bool bEscaped = false;
    for (xub_StrLen i = 0; i < n; ++i)
    {
        sal_Unicode c = rSubStr.GetChar(i);
        if (!bEscaped && c == sal_Unicode('\\'))
        {
            bEscaped = true;
            continue;
        }

        if (!bEscaped && c == sal_Unicode('?'))
            aNewStr.Append(rCaption);
        else
            aNewStr.Append(c);
        bEscaped = false;
    }
    return aNewStr;
}

void ScDPResultMember::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
											long& rPos, long nMeasure, sal_Bool bRoot,
											const String* pMemberName,
											const String* pMemberCaption )
{
	//	IsVisible() test is in ScDPResultDimension::FillMemberResults
	//	(not on data layout dimension)

	long nSize = GetSize(nMeasure);
	sheet::MemberResult* pArray = pSequences->getArray();
	DBG_ASSERT( rPos+nSize <= pSequences->getLength(), "bumm" );

    sal_Bool bIsNumeric = sal_False;
	String aName;
	if ( pMemberName )			// if pMemberName != NULL, use instead of real member name
		aName = *pMemberName;
	else
	{
        ScDPItemData aItemData;
        FillItemData( aItemData );
        aName = aItemData.GetString();
        bIsNumeric = aItemData.IsValue();
	}
    const ScDPDimension*		pParentDim = GetParentDim();
    if ( bIsNumeric && pParentDim && pResultData->IsNumOrDateGroup( pParentDim->GetDimension() ) )
    {
        // Numeric group dimensions use numeric entries for proper sorting,
        // but the group titles must be output as text.
        bIsNumeric = sal_False;
    }

	String aCaption = aName;
    const ScDPMember* pMemberDesc = GetDPMember();
    if (pMemberDesc)
    {
        const OUString* pLayoutName = pMemberDesc->GetLayoutName();
        if (pLayoutName)
        {
            aCaption = *pLayoutName;
            bIsNumeric = false; // layout name is always non-numeric.
        }
    }

	if ( pMemberCaption )					// use pMemberCaption if != NULL
		aCaption = *pMemberCaption;
	if (!aCaption.Len())
		aCaption = ScGlobal::GetRscString(STR_EMPTYDATA);

    if (bIsNumeric)
        pArray[rPos].Flags |= sheet::MemberResultFlags::NUMERIC;
    else
        pArray[rPos].Flags &= ~sheet::MemberResultFlags::NUMERIC;

	if ( nSize && !bRoot )					// root is overwritten by first dimension
	{
		pArray[rPos].Name    = rtl::OUString(aName);
		pArray[rPos].Caption = rtl::OUString(aCaption);
		pArray[rPos].Flags	|= sheet::MemberResultFlags::HASMEMBER;

		//	set "continue" flag (removed for subtotals later)
		for (long i=1; i<nSize; i++)
			pArray[rPos+i].Flags |= sheet::MemberResultFlags::CONTINUE;
	}
 
    const ScDPLevel*	pParentLevel = GetParentLevel();
    long nExtraSpace = 0;
    if ( pParentLevel && pParentLevel->IsAddEmpty() )
        ++nExtraSpace;

    sal_Bool bTitleLine = sal_False;
    if ( pParentLevel && pParentLevel->IsOutlineLayout() )
        bTitleLine = sal_True;

    // if the subtotals are shown at the top (title row) in outline layout,
	// no extra row for the subtotals is needed
    sal_Bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );

	sal_Bool bHasChild = ( pChildDimension != NULL );
	if (bHasChild)
	{
        if ( bTitleLine )           // in tabular layout the title is on a separate row
            ++rPos;                 // -> fill child dimension one row below

		if (bRoot)		// same sequence for root member
			pChildDimension->FillMemberResults( pSequences, rPos, nMeasure );
		else
			//pChildDimension->FillMemberResults( pSequences + 1, rPos, nMeasure );
            pChildDimension->FillMemberResults( pSequences + nMemberStep/*1*/, rPos, nMeasure ); 

        if ( bTitleLine )           // title row is included in GetSize, so the following
            --rPos;                 // positions are calculated with the normal values
	}

	rPos += nSize;

    long nUserSubStart;
	long nUserSubCount = GetSubTotalCount(&nUserSubStart);
	if ( nUserSubCount && pChildDimension && !bSubTotalInTitle )
	{
		long nMemberMeasure = nMeasure;
		long nSubSize = pResultData->GetCountForMeasure(nMeasure);

		rPos -= nSubSize * (nUserSubCount - nUserSubStart);     // GetSize includes space for SubTotal
        rPos -= nExtraSpace;                                    // GetSize includes the empty line

		for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
		{
			for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
			{
				if ( nMeasure == SC_DPMEASURE_ALL )
					nMemberMeasure = nSubCount;

				ScSubTotalFunc eForce = SUBTOTAL_FUNC_NONE;
				if (bHasChild)
					eForce = lcl_GetForceFunc( pParentLevel, nUserPos );

                bool bTotalResult = false;
				String aSubStr = aCaption;
				aSubStr += ' ';
				aSubStr += pResultData->GetMeasureString(nMemberMeasure, sal_False, eForce, bTotalResult);

                if (bTotalResult)
                {
                    if (pMemberDesc)
                    {
                        // single data field layout.
                        const OUString* pSubtotalName = pParentDim->GetSubtotalName();
                        if (pSubtotalName)
                            aSubStr = lcl_parseSubtotalName(*pSubtotalName, aCaption);
                        pArray[rPos].Flags &= ~sheet::MemberResultFlags::GRANDTOTAL;
                    }
                    else
                    {
                        // root member - subtotal (grand total?) for multi-data field layout.
                        const rtl::OUString* pGrandTotalName = pResultData->GetSource()->GetGrandTotalName();
                        if (pGrandTotalName)
                            aSubStr = *pGrandTotalName;
                        pArray[rPos].Flags |= sheet::MemberResultFlags::GRANDTOTAL;
                    }
                }

				pArray[rPos].Name    = rtl::OUString(aName);
				pArray[rPos].Caption = rtl::OUString(aSubStr);
				pArray[rPos].Flags = ( pArray[rPos].Flags |
									( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL) ) &
									~sheet::MemberResultFlags::CONTINUE;

				if ( nMeasure == SC_DPMEASURE_ALL )
				{
					//	data layout dimension is (direct/indirect) child of this.
					//	data layout dimension must have name for all entries.

					uno::Sequence<sheet::MemberResult>* pLayoutSeq = pSequences;
					if (!bRoot)
						++pLayoutSeq;
					ScDPResultDimension* pLayoutDim = pChildDimension;
					while ( pLayoutDim && !pLayoutDim->IsDataLayout() )
					{
						pLayoutDim = pLayoutDim->GetFirstChildDimension();
						++pLayoutSeq;
					}
					if ( pLayoutDim )
					{
						sheet::MemberResult* pLayoutArray = pLayoutSeq->getArray();
						String aDataName = pResultData->GetMeasureDimensionName(nMemberMeasure);
						pLayoutArray[rPos].Name = rtl::OUString(aDataName);
					}
				}

				rPos += 1;
			}
		}

        rPos += nExtraSpace;                                    // add again (subtracted above)
	}
}

void ScDPResultMember::FillDataResults( const ScDPResultMember* pRefMember,
							uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence,
							long& rRow, long nMeasure ) const
{
	//	IsVisible() test is in ScDPResultDimension::FillDataResults
	//	(not on data layout dimension)
    const ScDPLevel*	 pParentLevel = GetParentLevel();
    long nStartRow = rRow;

    long nExtraSpace = 0;
    if ( pParentLevel && pParentLevel->IsAddEmpty() )
        ++nExtraSpace;

    sal_Bool bTitleLine = sal_False;
    if ( pParentLevel && pParentLevel->IsOutlineLayout() )
        bTitleLine = sal_True;

    sal_Bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );

	sal_Bool bHasChild = ( pChildDimension != NULL );
	if (bHasChild)
	{
        if ( bTitleLine )           // in tabular layout the title is on a separate row
            ++rRow;                 // -> fill child dimension one row below

		pChildDimension->FillDataResults( pRefMember, rSequence, rRow, nMeasure );  // doesn't modify rRow
		rRow += GetSize( nMeasure );

        if ( bTitleLine )           // title row is included in GetSize, so the following
            --rRow;                 // positions are calculated with the normal values
	}

    long nUserSubStart;
	long nUserSubCount = GetSubTotalCount(&nUserSubStart);
	if ( nUserSubCount || !bHasChild )
	{
        // Calculate at least automatic if no subtotals are selected,
        // show only own values if there's no child dimension (innermost).
		if ( !nUserSubCount || !bHasChild )
		{
			nUserSubCount = 1;
			nUserSubStart = 0;
		}

		long nMemberMeasure = nMeasure;
		long nSubSize = pResultData->GetCountForMeasure(nMeasure);
		if (bHasChild)
        {
			rRow -= nSubSize * ( nUserSubCount - nUserSubStart );   // GetSize includes space for SubTotal
            rRow -= nExtraSpace;                                    // GetSize includes the empty line
        }

        long nMoveSubTotal = 0;
        if ( bSubTotalInTitle )
        {
            nMoveSubTotal = rRow - nStartRow;   // force to first (title) row
            rRow = nStartRow;
        }

		if ( pDataRoot )
		{
			ScDPSubTotalState aSubState;		// initial state

			for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
			{
				if ( bHasChild && nUserSubCount > 1 )
				{
					aSubState.nRowSubTotalFunc = nUserPos;
					aSubState.eRowForce = lcl_GetForceFunc( /*pParentLevel*/GetParentLevel() , nUserPos );
				}

				for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
				{
					if ( nMeasure == SC_DPMEASURE_ALL )
						nMemberMeasure = nSubCount;
					else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
						nMemberMeasure = SC_DPMEASURE_ALL;

					DBG_ASSERT( rRow < rSequence.getLength(), "bumm" );
					uno::Sequence<sheet::DataResult>& rSubSeq = rSequence.getArray()[rRow];
					long nSeqCol = 0;
					pDataRoot->FillDataRow( pRefMember, rSubSeq, nSeqCol, nMemberMeasure, bHasChild, aSubState );

					rRow += 1;
				}
			}
		}
		else
			rRow += nSubSize * ( nUserSubCount - nUserSubStart );   // empty rows occur when ShowEmpty is true

        // add extra space again if subtracted from GetSize above,
        // add to own size if no children
        rRow += nExtraSpace;

        rRow += nMoveSubTotal;
	}
}

void ScDPResultMember::UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const
{
    //  IsVisible() test is in ScDPResultDimension::FillDataResults
    //  (not on data layout dimension)

    sal_Bool bHasChild = ( pChildDimension != NULL );

    long nUserSubCount = GetSubTotalCount();
    // process subtotals even if not shown
//  if ( nUserSubCount || !bHasChild )
    {
        // Calculate at least automatic if no subtotals are selected,
        // show only own values if there's no child dimension (innermost).
        if ( !nUserSubCount || !bHasChild )
            nUserSubCount = 1;

        long nMemberMeasure = nMeasure;
        long nSubSize = pResultData->GetCountForMeasure(nMeasure);

        if ( pDataRoot )
        {
            ScDPSubTotalState aSubState;        // initial state

            for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++)   // including hidden "automatic"
            {
                if ( bHasChild && nUserSubCount > 1 )
                {
                    aSubState.nRowSubTotalFunc = nUserPos;
                    aSubState.eRowForce = lcl_GetForceFunc( /*pParentLevel*/GetParentLevel() , nUserPos );
                }

                for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
                {
                    if ( nMeasure == SC_DPMEASURE_ALL )
                        nMemberMeasure = nSubCount;
                    else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
                        nMemberMeasure = SC_DPMEASURE_ALL;

                    pDataRoot->UpdateDataRow( pRefMember, nMemberMeasure, bHasChild, aSubState );
                }
            }
        }
    }

    if (bHasChild)  // child dimension must be processed last, so the column total is known
    {
        pChildDimension->UpdateDataResults( pRefMember, nMeasure );
    }
}

void ScDPResultMember::SortMembers( ScDPResultMember* pRefMember )
{
    sal_Bool bHasChild = ( pChildDimension != NULL );
    if (bHasChild)
        pChildDimension->SortMembers( pRefMember );     // sorting is done at the dimension

    if ( IsRoot() && pDataRoot )
    {
        // use the row root member to sort columns
        // sub total count is always 1

        pDataRoot->SortMembers( pRefMember );
    }
}

void ScDPResultMember::DoAutoShow( ScDPResultMember* pRefMember )
{
    sal_Bool bHasChild = ( pChildDimension != NULL );
    if (bHasChild)
        pChildDimension->DoAutoShow( pRefMember );     // sorting is done at the dimension

    if ( IsRoot()&& pDataRoot )
    {
        // use the row root member to sort columns
        // sub total count is always 1

        pDataRoot->DoAutoShow( pRefMember );
    }
}

void ScDPResultMember::ResetResults( sal_Bool /*bRoot*/ )
{
    if (pDataRoot)
        pDataRoot->ResetResults();

    if (pChildDimension)
        pChildDimension->ResetResults();

 //   if (!bRoot)
 //       bHasElements = sal_False;
}

void ScDPResultMember::UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
                                            ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
{
    //  IsVisible() test is in ScDPResultDimension::FillDataResults
    //  (not on data layout dimension)

    rTotals.SetInColRoot( IsRoot() );

    sal_Bool bHasChild = ( pChildDimension != NULL );

    long nUserSubCount = GetSubTotalCount();
	//if ( nUserSubCount || !bHasChild )
    {
        // Calculate at least automatic if no subtotals are selected,
        // show only own values if there's no child dimension (innermost).
        if ( !nUserSubCount || !bHasChild )
            nUserSubCount = 1;

        long nMemberMeasure = nMeasure;
        long nSubSize = pResultData->GetCountForMeasure(nMeasure);

        if ( pDataRoot )
        {
            ScDPSubTotalState aSubState;        // initial state

            for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++)   // including hidden "automatic"
            {
                if ( bHasChild && nUserSubCount > 1 )
                {
                    aSubState.nRowSubTotalFunc = nUserPos;
                    aSubState.eRowForce = lcl_GetForceFunc( /*pParentLevel*/GetParentLevel(), nUserPos );
                }

                for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
                {
                    if ( nMeasure == SC_DPMEASURE_ALL )
                        nMemberMeasure = nSubCount;
                    else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
                        nMemberMeasure = SC_DPMEASURE_ALL;

                    pDataRoot->UpdateRunningTotals( pRefMember, nMemberMeasure,
                                        bHasChild, aSubState, rRunning, rTotals, *this );
                }
            }
        }
    }

    if (bHasChild)  // child dimension must be processed last, so the column total is known
    {
        pChildDimension->UpdateRunningTotals( pRefMember, nMeasure, rRunning, rTotals );
    }
}

void ScDPResultMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
{
    lcl_DumpRow( String::CreateFromAscii("ScDPResultMember"), GetName(), NULL, pDoc, rPos );
    SCROW nStartRow = rPos.Row();

    if (pDataRoot)
        pDataRoot->DumpState( pRefMember, pDoc, rPos );

    if (pChildDimension)
        pChildDimension->DumpState( pRefMember, pDoc, rPos );

    lcl_Indent( pDoc, nStartRow, rPos );
}

ScDPAggData* ScDPResultMember::GetColTotal( long nMeasure ) const
{
    return lcl_GetChildTotal( const_cast<ScDPAggData*>(&aColTotal), nMeasure );
}

void ScDPResultMember::FillVisibilityData(ScDPResultVisibilityData& rData) const
{
    if (pChildDimension)
        pChildDimension->FillVisibilityData(rData);
}

// -----------------------------------------------------------------------

ScDPDataMember::ScDPDataMember( const ScDPResultData* pData, const ScDPResultMember* pRes ) :
	pResultData( pData ),
	pResultMember( pRes ),
	pChildDimension( NULL )
{
	// pResultMember is 0 for root members
}

ScDPDataMember::~ScDPDataMember()
{
	delete pChildDimension;
}

String ScDPDataMember::GetName() const
{
	if (pResultMember)
		return pResultMember->GetName();
	else
		return EMPTY_STRING;
}

sal_Bool ScDPDataMember::IsVisible() const
{
	if (pResultMember)
		return pResultMember->IsVisible();
	else
		return sal_False;
}

sal_Bool ScDPDataMember::IsNamedItem( /*const ScDPItemData& r*/SCROW r ) const
{
	if (pResultMember)
		return pResultMember->IsNamedItem(r);
	else
		return sal_False;
}

sal_Bool ScDPDataMember::HasHiddenDetails() const
{
	if (pResultMember)
		return pResultMember->HasHiddenDetails();
	else
		return sal_False;
}

void ScDPDataMember::InitFrom( const ScDPResultDimension* pDim )
{
	if ( !pChildDimension )
		pChildDimension = new ScDPDataDimension(pResultData);
	pChildDimension->InitFrom(pDim);
}

const long SC_SUBTOTALPOS_AUTO = -1;    // default
const long SC_SUBTOTALPOS_SKIP = -2;    // don't use

long lcl_GetSubTotalPos( const ScDPSubTotalState& rSubState )
{
    if ( rSubState.nColSubTotalFunc >= 0 && rSubState.nRowSubTotalFunc >= 0 &&
         rSubState.nColSubTotalFunc != rSubState.nRowSubTotalFunc )
    {
        // #i68338# don't return the same index for different combinations (leading to repeated updates),
        // return a "don't use" value instead

        return SC_SUBTOTALPOS_SKIP;
    }

	long nRet = SC_SUBTOTALPOS_AUTO;
	if ( rSubState.nColSubTotalFunc >= 0 ) nRet = rSubState.nColSubTotalFunc;
	if ( rSubState.nRowSubTotalFunc >= 0 ) nRet = rSubState.nRowSubTotalFunc;
	return nRet;
}

void ScDPDataMember::UpdateValues( const vector<ScDPValueData>& aValues, const ScDPSubTotalState& rSubState )
{
    //!	find out how many and which subtotals are used

    ScDPAggData* pAgg = &aAggregate;

    long nSubPos = lcl_GetSubTotalPos(rSubState);
    if (nSubPos == SC_SUBTOTALPOS_SKIP)
        return;
    if (nSubPos > 0)
    {
        long nSkip = nSubPos * pResultData->GetMeasureCount();
        for (long i=0; i<nSkip; i++)
            pAgg = pAgg->GetChild();        // created if not there
    }

    size_t nCount = aValues.size();
    for (size_t nPos = 0; nPos < nCount; ++nPos)
    {
        pAgg->Update(aValues[nPos], pResultData->GetMeasureFunction(nPos), rSubState);
        pAgg = pAgg->GetChild();
    }
}

void ScDPDataMember::ProcessData( const vector< SCROW >& aChildMembers, const vector<ScDPValueData>& aValues,
									const ScDPSubTotalState& rSubState )
{
	if ( pResultData->IsLateInit() && !pChildDimension && pResultMember && pResultMember->GetChildDimension() )
	{
		//	if this DataMember doesn't have a child dimension because the ResultMember's
		//	child dimension wasn't there yet during this DataMembers's creation,
		//	create the child dimension now
		InitFrom( pResultMember->GetChildDimension() );
	}

	ScDPSubTotalState aLocalSubState(rSubState);		// keep row state, modify column

	long nUserSubCount = pResultMember ? pResultMember->GetSubTotalCount() : 0;

    // Calculate at least automatic if no subtotals are selected,
    // show only own values if there's no child dimension (innermost).
	if ( !nUserSubCount || !pChildDimension )
		nUserSubCount = 1;

	for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++)   // including hidden "automatic"
	{
		if ( pChildDimension && nUserSubCount > 1 )
		{
			const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
			aLocalSubState.nColSubTotalFunc = nUserPos;
			aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
		}

		UpdateValues( aValues, aLocalSubState );
	}

	if (pChildDimension)
		pChildDimension->ProcessData( aChildMembers, aValues, rSubState );		// with unmodified subtotal state
}

sal_Bool ScDPDataMember::HasData( long nMeasure, const ScDPSubTotalState& rSubState ) const
{
	if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
														rSubState.eColForce != rSubState.eRowForce )
		return sal_False;

	//	#74542# HasData can be different between measures!

	const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
	if (!pAgg)
		return sal_False;			//! error?

	return pAgg->HasData();
}

sal_Bool ScDPDataMember::HasError( long nMeasure, const ScDPSubTotalState& rSubState ) const
{
	const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
	if (!pAgg)
		return sal_True;

	return pAgg->HasError();
}

double ScDPDataMember::GetAggregate( long nMeasure, const ScDPSubTotalState& rSubState ) const
{
	const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
	if (!pAgg)
		return DBL_MAX;			//! error?

	return pAgg->GetResult();
}

ScDPAggData* ScDPDataMember::GetAggData( long nMeasure, const ScDPSubTotalState& rSubState )
{
    DBG_ASSERT( nMeasure >= 0, "GetAggData: no measure" );

    ScDPAggData* pAgg = &aAggregate;
    long nSkip = nMeasure;
    long nSubPos = lcl_GetSubTotalPos(rSubState);
    if (nSubPos == SC_SUBTOTALPOS_SKIP)
        return NULL;
    if (nSubPos > 0)
        nSkip += nSubPos * pResultData->GetMeasureCount();

    for ( long nPos=0; nPos<nSkip; nPos++ )
        pAgg = pAgg->GetChild();        //! need to create children here?

    return pAgg;
}

const ScDPAggData* ScDPDataMember::GetConstAggData( long nMeasure, const ScDPSubTotalState& rSubState ) const
{
    DBG_ASSERT( nMeasure >= 0, "GetConstAggData: no measure" );

    const ScDPAggData* pAgg = &aAggregate;
    long nSkip = nMeasure;
    long nSubPos = lcl_GetSubTotalPos(rSubState);
    if (nSubPos == SC_SUBTOTALPOS_SKIP)
        return NULL;
    if (nSubPos > 0)
        nSkip += nSubPos * pResultData->GetMeasureCount();

    for ( long nPos=0; nPos<nSkip; nPos++ )
    {
        pAgg = pAgg->GetExistingChild();
        if (!pAgg)
            return NULL;
    }

    return pAgg;
}

void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
									uno::Sequence<sheet::DataResult>& rSequence,
									long& rCol, long nMeasure, sal_Bool bIsSubTotalRow,
									const ScDPSubTotalState& rSubState ) const
{
	DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );

	if ( pRefMember->IsVisible() )	//! here or in ScDPDataDimension::FillDataRow ???
	{
        long nStartCol = rCol;

		const ScDPDataDimension* pDataChild = GetChildDimension();
		const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();

        const ScDPLevel* pRefParentLevel = const_cast<ScDPResultMember*>(pRefMember)->GetParentLevel();

        long nExtraSpace = 0;
        if ( pRefParentLevel && pRefParentLevel->IsAddEmpty() )
            ++nExtraSpace;

        sal_Bool bTitleLine = sal_False;
        if ( pRefParentLevel && pRefParentLevel->IsOutlineLayout() )
            bTitleLine = sal_True;

        sal_Bool bSubTotalInTitle = pRefMember->IsSubTotalInTitle( nMeasure );

		//	leave space for children even if the DataMember hasn't been initialized
		//	(pDataChild is null then, this happens when no values for it are in this row)
		sal_Bool bHasChild = ( pRefChild != NULL );

		if ( bHasChild )
		{
            if ( bTitleLine )           // in tabular layout the title is on a separate column
                ++rCol;                 // -> fill child dimension one column below

			if ( pDataChild )
				pDataChild->FillDataRow( pRefChild, rSequence, rCol, nMeasure, bIsSubTotalRow, rSubState );
			rCol += (sal_uInt16)pRefMember->GetSize( nMeasure );

            if ( bTitleLine )           // title column is included in GetSize, so the following
                --rCol;                 // positions are calculated with the normal values
		}

        long nUserSubStart;
		long nUserSubCount = pRefMember->GetSubTotalCount(&nUserSubStart);
		if ( nUserSubCount || !bHasChild )
		{
            // Calculate at least automatic if no subtotals are selected,
            // show only own values if there's no child dimension (innermost).
			if ( !nUserSubCount || !bHasChild )
			{
				nUserSubCount = 1;
				nUserSubStart = 0;
			}

			ScDPSubTotalState aLocalSubState(rSubState);		// keep row state, modify column

			long nMemberMeasure = nMeasure;
			long nSubSize = pResultData->GetCountForMeasure(nMeasure);
			if (bHasChild)
            {
				rCol -= nSubSize * ( nUserSubCount - nUserSubStart );   // GetSize includes space for SubTotal
                rCol -= nExtraSpace;                                    // GetSize includes the empty line
            }

            long nMoveSubTotal = 0;
            if ( bSubTotalInTitle )
            {
                nMoveSubTotal = rCol - nStartCol;   // force to first (title) column
                rCol = nStartCol;
            }

			for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
			{
				if ( pChildDimension && nUserSubCount > 1 )
				{
					const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
					aLocalSubState.nColSubTotalFunc = nUserPos;
					aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
				}

				for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
				{
					if ( nMeasure == SC_DPMEASURE_ALL )
						nMemberMeasure = nSubCount;

					DBG_ASSERT( rCol < rSequence.getLength(), "bumm" );
					sheet::DataResult& rRes = rSequence.getArray()[rCol];

					if ( HasData( nMemberMeasure, aLocalSubState ) )
					{
						if ( HasError( nMemberMeasure, aLocalSubState ) )
						{
							rRes.Value = 0;
							rRes.Flags |= sheet::DataResultFlags::ERROR;
						}
						else
						{
							rRes.Value = GetAggregate( nMemberMeasure, aLocalSubState );
							rRes.Flags |= sheet::DataResultFlags::HASDATA;
						}
					}

					if ( bHasChild || bIsSubTotalRow )
						rRes.Flags |= sheet::DataResultFlags::SUBTOTAL;

					rCol += 1;
				}
			}

            // add extra space again if subtracted from GetSize above,
            // add to own size if no children
            rCol += nExtraSpace;

            rCol += nMoveSubTotal;
		}
	}
}

void ScDPDataMember::UpdateDataRow( const ScDPResultMember* pRefMember,
                                long nMeasure, sal_Bool bIsSubTotalRow,
                                const ScDPSubTotalState& rSubState )
{
    DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );

    // Calculate must be called even if not visible (for use as reference value)
    const ScDPDataDimension* pDataChild = GetChildDimension();
    const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();

    //  leave space for children even if the DataMember hasn't been initialized
    //  (pDataChild is null then, this happens when no values for it are in this row)
    sal_Bool bHasChild = ( pRefChild != NULL );

    // process subtotals even if not shown
    long nUserSubCount = pRefMember->GetSubTotalCount();

    // Calculate at least automatic if no subtotals are selected,
    // show only own values if there's no child dimension (innermost).
    if ( !nUserSubCount || !bHasChild )
        nUserSubCount = 1;

    ScDPSubTotalState aLocalSubState(rSubState);        // keep row state, modify column

    long nMemberMeasure = nMeasure;
    long nSubSize = pResultData->GetCountForMeasure(nMeasure);

    for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++)   // including hidden "automatic"
    {
        if ( pChildDimension && nUserSubCount > 1 )
        {
            const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
            aLocalSubState.nColSubTotalFunc = nUserPos;
            aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
        }

        for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
        {
            if ( nMeasure == SC_DPMEASURE_ALL )
                nMemberMeasure = nSubCount;

            // update data...
            ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
            if (pAggData)
            {
                //! aLocalSubState?
                ScSubTotalFunc eFunc = pResultData->GetMeasureFunction( nMemberMeasure );
                sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
                sal_Int32 eRefType = aReferenceValue.ReferenceType;

                // calculate the result first - for all members, regardless of reference value
                pAggData->Calculate( eFunc, aLocalSubState );

                if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
                     eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
                     eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
                {
                    // copy the result into auxiliary value, so differences can be
                    // calculated in any order
                    pAggData->SetAuxiliary( pAggData->GetResult() );
                }
                // column/row percentage/index is now in UpdateRunningTotals, so it doesn't disturb sorting
            }
        }
    }

    if ( bHasChild )    // child dimension must be processed last, so the row total is known
    {
        if ( pDataChild )
            pDataChild->UpdateDataRow( pRefChild, nMeasure, bIsSubTotalRow, rSubState );
    }
}

void ScDPDataMember::SortMembers( ScDPResultMember* pRefMember )
{
    DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );

    if ( pRefMember->IsVisible() )  //! here or in ScDPDataDimension ???
    {
        ScDPDataDimension* pDataChild = GetChildDimension();
        ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
        if ( pRefChild && pDataChild )
            pDataChild->SortMembers( pRefChild );       // sorting is done at the dimension
    }
}

void ScDPDataMember::DoAutoShow( ScDPResultMember* pRefMember )
{
    DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );

    if ( pRefMember->IsVisible() )  //! here or in ScDPDataDimension ???
    {
        ScDPDataDimension* pDataChild = GetChildDimension();
        ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
        if ( pRefChild && pDataChild )
            pDataChild->DoAutoShow( pRefChild );       // sorting is done at the dimension
    }
}

void ScDPDataMember::ResetResults()
{
    aAggregate.Reset();

    ScDPDataDimension* pDataChild = GetChildDimension();
    if ( pDataChild )
        pDataChild->ResetResults();
}

void ScDPDataMember::UpdateRunningTotals( const ScDPResultMember* pRefMember,
	                            long nMeasure, sal_Bool bIsSubTotalRow,
                                const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
                                ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent )
{
    DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );

    if ( pRefMember->IsVisible() )  //! here or in ScDPDataDimension::UpdateRunningTotals ???
    {
        const ScDPDataDimension* pDataChild = GetChildDimension();
        const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();

        sal_Bool bIsRoot = ( pResultMember == NULL || pResultMember->GetParentLevel() == NULL );

        //  leave space for children even if the DataMember hasn't been initialized
        //  (pDataChild is null then, this happens when no values for it are in this row)
        sal_Bool bHasChild = ( pRefChild != NULL );

        long nUserSubCount = pRefMember->GetSubTotalCount();
		//if ( nUserSubCount || !bHasChild )
        {
            // Calculate at least automatic if no subtotals are selected,
            // show only own values if there's no child dimension (innermost).
            if ( !nUserSubCount || !bHasChild )
                nUserSubCount = 1;

            ScDPSubTotalState aLocalSubState(rSubState);        // keep row state, modify column

            long nMemberMeasure = nMeasure;
            long nSubSize = pResultData->GetCountForMeasure(nMeasure);

            for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++)   // including hidden "automatic"
            {
                if ( pChildDimension && nUserSubCount > 1 )
                {
                    const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
                    aLocalSubState.nColSubTotalFunc = nUserPos;
                    aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
                }

                for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
                {
                    if ( nMeasure == SC_DPMEASURE_ALL )
                        nMemberMeasure = nSubCount;

                    // update data...
                    ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
                    if (pAggData)
                    {
                        //! aLocalSubState?
                        sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
                        sal_Int32 eRefType = aReferenceValue.ReferenceType;

                        if ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL ||
                             eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
                             eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
                             eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
                        {
                            sal_Bool bRunningTotal = ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL );
                            sal_Bool bRelative =
                                ( aReferenceValue.ReferenceItemType != sheet::DataPilotFieldReferenceItemType::NAMED && !bRunningTotal );
                            long nRelativeDir = bRelative ?
                                ( ( aReferenceValue.ReferenceItemType == sheet::DataPilotFieldReferenceItemType::PREVIOUS ) ? -1 : 1 ) : 0;

                            const long* pColVisible = rRunning.GetColVisible();
                            const long* pColIndexes = rRunning.GetColIndexes();
                            const long* pRowVisible = rRunning.GetRowVisible();
                            const long* pRowIndexes = rRunning.GetRowIndexes();

                            String aRefFieldName = aReferenceValue.ReferenceField;

                            //! aLocalSubState?
                            sal_uInt16 nRefOrient = pResultData->GetMeasureRefOrient( nMemberMeasure );
                            sal_Bool bRefDimInCol = ( nRefOrient == sheet::DataPilotFieldOrientation_COLUMN );
                            sal_Bool bRefDimInRow = ( nRefOrient == sheet::DataPilotFieldOrientation_ROW );

                            const ScDPResultDimension* pSelectDim = NULL;
                            long nRowPos = 0;
                            long nColPos = 0;

                            //
                            //  find the reference field in column or row dimensions
                            //

                            if ( bRefDimInRow )     //  look in row dimensions
                            {
                                pSelectDim = rRunning.GetRowResRoot()->GetChildDimension();
                                while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
                                {
                                    long nIndex = pRowIndexes[nRowPos];
                                    if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
                                        pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
                                    else
                                        pSelectDim = NULL;
                                    ++nRowPos;
                                }
                                // child dimension of innermost member?
                                if ( pSelectDim && pRowIndexes[nRowPos] < 0 )
                                    pSelectDim = NULL;
                            }

                            if ( bRefDimInCol )     //  look in column dimensions
                            {
                                pSelectDim = rRunning.GetColResRoot()->GetChildDimension();
                                while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
                                {
                                    long nIndex = pColIndexes[nColPos];
                                    if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
                                        pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
                                    else
                                        pSelectDim = NULL;
                                    ++nColPos;
                                }
                                // child dimension of innermost member?
                                if ( pSelectDim && pColIndexes[nColPos] < 0 )
                                    pSelectDim = NULL;
                            }

                            sal_Bool bNoDetailsInRef = sal_False;
                            if ( pSelectDim && bRunningTotal )
                            {
                                //  Running totals:
                                //  If details are hidden for this member in the reference dimension,
                                //  don't show or sum up the value. Otherwise, for following members,
                                //  the running totals of details and subtotals wouldn't match.

                                long nMyIndex = bRefDimInCol ? pColIndexes[nColPos] : pRowIndexes[nRowPos];
                                if ( nMyIndex >= 0 && nMyIndex < pSelectDim->GetMemberCount() )
                                {
                                    const ScDPResultMember* pMyRefMember = pSelectDim->GetMember(nMyIndex);
                                    if ( pMyRefMember && pMyRefMember->HasHiddenDetails() )
                                    {
                                        pSelectDim = NULL;          // don't calculate
                                        bNoDetailsInRef = sal_True;     // show error, not empty
                                    }
                                }
                            }

                            if ( bRelative )
                            {
                                //  Difference/Percentage from previous/next:
                                //  If details are hidden for this member in the innermost column/row
                                //  dimension (the orientation of the reference dimension), show an
                                //  error value.
                                //  - If the no-details dimension is the reference dimension, its
                                //    members will be skipped when finding the previous/next member,
                                //    so there must be no results for its members.
                                //  - If the no-details dimension is outside of the reference dimension,
                                //    no calculation in the reference dimension is possible.
                                //  - Otherwise, the error isn't strictly necessary, but shown for
                                //    consistency.

                                sal_Bool bInnerNoDetails = bRefDimInCol ? HasHiddenDetails() :
                                                     ( bRefDimInRow ? rRowParent.HasHiddenDetails() : sal_True );
                                if ( bInnerNoDetails )
                                {
                                    pSelectDim = NULL;
                                    bNoDetailsInRef = sal_True;         // show error, not empty
                                }
                            }

                            if ( !bRefDimInCol && !bRefDimInRow )   // invalid dimension specified
                                bNoDetailsInRef = sal_True;             // pSelectDim is then already NULL

                            //
                            //  get the member for the reference item and do the calculation
                            //

                            if ( bRunningTotal )
                            {
                                // running total in (dimension) -> find first existing member

                                if ( pSelectDim )
                                {
                                    ScDPDataMember* pSelectMember;
                                    if ( bRefDimInCol )
                                        pSelectMember = ScDPResultDimension::GetColReferenceMember( NULL, NULL,
                                                                        nColPos, rRunning );
                                    else
                                    {
                                        long nSkip = nRowPos + 1;   // including the reference dimension
                                        pSelectMember = pSelectDim->GetRowReferenceMember( NULL, NULL,
                                                                        pRowIndexes+nSkip, pColIndexes );
                                    }

                                    if ( pSelectMember )
                                    {
                                        // The running total is kept as the auxiliary value in
                                        // the first available member for the reference dimension.
                                        // Members are visited in final order, so each one's result
                                        // can be used and then modified.

                                        ScDPAggData* pSelectData = pSelectMember->
                                                        GetAggData( nMemberMeasure, aLocalSubState );
                                        if ( pSelectData )
                                        {
                                            double fTotal = pSelectData->GetAuxiliary();
                                            fTotal += pAggData->GetResult();
                                            pSelectData->SetAuxiliary( fTotal );
                                            pAggData->SetResult( fTotal );
                                            pAggData->SetEmpty(sal_False);              // always display
                                        }
                                    }
                                    else
                                        pAggData->SetError();
                                }
                                else if (bNoDetailsInRef)
                                    pAggData->SetError();
                                else
                                    pAggData->SetEmpty(sal_True);                       // empty (dim set to 0 above)
                            }
                            else
                            {
                                // difference/percentage -> find specified member

                                if ( pSelectDim )
                                {
                                    String aRefItemName = aReferenceValue.ReferenceItemName;
                                    ScDPRelativePos aRefItemPos( 0, nRelativeDir );     // nBasePos is modified later

                                    const String* pRefName = NULL;
                                    const ScDPRelativePos* pRefPos = NULL;
                                    if ( bRelative )
                                        pRefPos = &aRefItemPos;
                                    else
                                        pRefName = &aRefItemName;

                                    ScDPDataMember* pSelectMember;
                                    if ( bRefDimInCol )
                                    {
                                        aRefItemPos.nBasePos = pColVisible[nColPos];    // without sort order applied
                                        pSelectMember = ScDPResultDimension::GetColReferenceMember( pRefPos, pRefName, 
                                                                        nColPos, rRunning );
                                    }
                                    else
                                    {
                                        aRefItemPos.nBasePos = pRowVisible[nRowPos];    // without sort order applied
                                        long nSkip = nRowPos + 1;   // including the reference dimension
                                        pSelectMember = pSelectDim->GetRowReferenceMember( pRefPos, pRefName,
                                                                        pRowIndexes+nSkip, pColIndexes );
                                    }

                                    // difference or perc.difference is empty for the reference item itself
                                    if ( pSelectMember == this &&
                                         eRefType != sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE )
                                    {
                                        pAggData->SetEmpty(sal_True);
                                    }
                                    else if ( pSelectMember )
                                    {
                                        const ScDPAggData* pOtherAggData = pSelectMember->
                                                            GetConstAggData( nMemberMeasure, aLocalSubState );
                                        DBG_ASSERT( pOtherAggData, "no agg data" );
                                        if ( pOtherAggData )
                                        {
                                            // Reference member may be visited before or after this one,
                                            // so the auxiliary value is used for the original result.

                                            double fOtherResult = pOtherAggData->GetAuxiliary();
                                            double fThisResult = pAggData->GetResult();
                                            sal_Bool bError = sal_False;
                                            switch ( eRefType )
                                            {
                                                case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE:
                                                    fThisResult = fThisResult - fOtherResult;
                                                    break;
                                                case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
                                                    if ( fOtherResult == 0.0 )
                                                        bError = sal_True;
                                                    else
                                                        fThisResult = fThisResult / fOtherResult;
                                                    break;
                                                case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
                                                    if ( fOtherResult == 0.0 )
                                                        bError = sal_True;
                                                    else
                                                        fThisResult = ( fThisResult - fOtherResult ) / fOtherResult;
                                                    break;
                                                default:
                                                    DBG_ERROR("invalid calculation type");
                                            }
                                            if ( bError )
                                            {
                                                pAggData->SetError();
                                            }
                                            else
                                            {
                                                pAggData->SetResult(fThisResult);
                                                pAggData->SetEmpty(sal_False);              // always display
                                            }
                                            //! errors in data?
                                        }
                                    }
                                    else if (bRelative && !bNoDetailsInRef)
                                        pAggData->SetEmpty(sal_True);                   // empty
                                    else
                                        pAggData->SetError();                       // error
                                }
                                else if (bNoDetailsInRef)
                                    pAggData->SetError();                           // error
                                else
                                    pAggData->SetEmpty(sal_True);                       // empty
                            }
                        }
                        else if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE ||
                                  eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE ||
                                  eRefType == sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE ||
                                  eRefType == sheet::DataPilotFieldReferenceType::INDEX )
                        {
                            //
                            //  set total values when they are encountered (always before their use)
                            //

                            ScDPAggData* pColTotalData = pRefMember->GetColTotal( nMemberMeasure );
                            ScDPAggData* pRowTotalData = rTotals.GetRowTotal( nMemberMeasure );
                            ScDPAggData* pGrandTotalData = rTotals.GetGrandTotal( nMemberMeasure );

                            double fTotalValue = pAggData->HasError() ? 0 : pAggData->GetResult();

                            if ( bIsRoot && rTotals.IsInColRoot() && pGrandTotalData )
                                pGrandTotalData->SetAuxiliary( fTotalValue );

                            if ( bIsRoot && pRowTotalData )
                                pRowTotalData->SetAuxiliary( fTotalValue );

                            if ( rTotals.IsInColRoot() && pColTotalData )
                                pColTotalData->SetAuxiliary( fTotalValue );

                            //
                            //  find relation to total values
                            //

                            switch ( eRefType )
                            {
                                case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
                                case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
                                case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
                                    {
                                        double nTotal;
                                        if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE )
                                            nTotal = pRowTotalData->GetAuxiliary();
                                        else if ( eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE )
                                            nTotal = pColTotalData->GetAuxiliary();
                                        else
                                            nTotal = pGrandTotalData->GetAuxiliary();

                                        if ( nTotal == 0.0 )
                                            pAggData->SetError();
                                        else
                                            pAggData->SetResult( pAggData->GetResult() / nTotal );
                                    }
                                    break;
                                case sheet::DataPilotFieldReferenceType::INDEX:
                                    {
                                        double nColTotal = pColTotalData->GetAuxiliary();
                                        double nRowTotal = pRowTotalData->GetAuxiliary();
                                        double nGrandTotal = pGrandTotalData->GetAuxiliary();
                                        if ( nRowTotal == 0.0 || nColTotal == 0.0 )
                                            pAggData->SetError();
                                        else
                                            pAggData->SetResult( 
                                                ( pAggData->GetResult() * nGrandTotal ) /
                                                ( nRowTotal * nColTotal ) );
                                    }
                                    break;
                            }
                        }
                    }
                }
            }
        }

        if ( bHasChild )    // child dimension must be processed last, so the row total is known
        {
            if ( pDataChild )
                pDataChild->UpdateRunningTotals( pRefChild, nMeasure,
                                                bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent );
        }
    }
}

void ScDPDataMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
{
    lcl_DumpRow( String::CreateFromAscii("ScDPDataMember"), GetName(), &aAggregate, pDoc, rPos );
    SCROW nStartRow = rPos.Row();

    const ScDPDataDimension* pDataChild = GetChildDimension();
    const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
    if ( pDataChild && pRefChild )
        pDataChild->DumpState( pRefChild, pDoc, rPos );

    lcl_Indent( pDoc, nStartRow, rPos );
}

// -----------------------------------------------------------------------

//  Helper class to select the members to include in
//  ScDPResultDimension::InitFrom or LateInitFrom if groups are used

class ScDPGroupCompare
{
private:
    const ScDPResultData* pResultData;
    const ScDPInitState& rInitState;
    long                 nDimSource;
    sal_Bool                 bIncludeAll;
    sal_Bool                 bIsBase;
    long                 nGroupBase;
    // Wang Xu Ming -- 2009-8-6
    // DataPilot Migration - Cache&&Performance
    SCROW          nBaseDataId;
    // End Comments
public:
            ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension );
            ~ScDPGroupCompare() {}

    sal_Bool    IsIncluded( const ScDPMember& rMember )     { return bIncludeAll || TestIncluded( rMember ); }
    sal_Bool    TestIncluded( const ScDPMember& rMember );
};

ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension ) :
    pResultData( pData ),
    rInitState( rState ),
    nDimSource( nDimension ),
    nBaseDataId( -1 )
{
    bIsBase = pResultData->IsBaseForGroup( nDimSource );
    nGroupBase = pResultData->GetGroupBase( nDimSource );      //! get together in one call?
    if ( nGroupBase >= 0 )
        nBaseDataId = rInitState.GetNameIdForIndex( nGroupBase );

    // if bIncludeAll is set, TestIncluded doesn't need to be called
    bIncludeAll = !( bIsBase || nGroupBase >= 0 );
}

sal_Bool ScDPGroupCompare::TestIncluded( const ScDPMember& rMember )
{
	sal_Bool bInclude = sal_True;
	if ( nBaseDataId >=0 )
	{
        ScDPItemData aMemberData;
        rMember.FillItemData( aMemberData );
        bInclude = pResultData->IsInGroup( aMemberData, nDimSource, nBaseDataId, nGroupBase );
	}
    else if ( bIsBase )
    {
        // need to check all previous groups
        //! get array of groups (or indexes) before loop?
        ScDPItemData aMemberData;
        rMember.FillItemData( aMemberData );
        long nInitCount = rInitState.GetCount();
        const long* pInitSource = rInitState.GetSource();
        /*const ScDPItemData* pInitNames = rInitState.GetNames();*/
        const SCROW* pInitNames = rInitState.GetNameIds();
        for (long nInitPos=0; nInitPos<nInitCount && bInclude; nInitPos++)
            if ( pResultData->GetGroupBase( pInitSource[nInitPos] ) == nDimSource )
            {
                bInclude = pResultData->IsInGroup( pInitNames[nInitPos], pInitSource[nInitPos],
                                                    aMemberData, nDimSource );
            }
    }
    else if ( nGroupBase >= 0 )
    {
        // base isn't used in preceding fields
        // -> look for other groups using the same base

        //! get array of groups (or indexes) before loop?
        ScDPItemData aMemberData;
        rMember.FillItemData( aMemberData );
        long nInitCount = rInitState.GetCount();
        const long* pInitSource = rInitState.GetSource();
       /*const ScDPItemData* pInitNames = rInitState.GetNames();*/
        const SCROW* pInitNames = rInitState.GetNameIds();
        for (long nInitPos=0; nInitPos<nInitCount && bInclude; nInitPos++)
            if ( pResultData->GetGroupBase( pInitSource[nInitPos] ) == nGroupBase )
            {
                // same base (hierarchy between the two groups is irrelevant)
                bInclude = pResultData->HasCommonElement( pInitNames[nInitPos], pInitSource[nInitPos],
                                                        aMemberData, nDimSource );
            }
    }

    return bInclude;
}

// -----------------------------------------------------------------------

ScDPResultDimension::ScDPResultDimension( const ScDPResultData* pData ) :
	pResultData( pData ),
	bInitialized( sal_False ),
	bIsDataLayout( sal_False ),
	bSortByData( sal_False ),
	bSortAscending( sal_False ),
	nSortMeasure( 0 ),
	bAutoShow( sal_False ),
	bAutoTopItems( sal_False ),
	nAutoMeasure( 0 ),
	nAutoCount( 0 )
{
}

ScDPResultDimension::~ScDPResultDimension()
{
	for( int i = maMemberArray.size () ; i-- > 0 ; )
		delete maMemberArray[i];
}

ScDPResultMember *ScDPResultDimension::FindMember(  SCROW  iData ) const
{
	if( bIsDataLayout )
		return maMemberArray[0];

	MemberHash::const_iterator aRes = maMemberHash.find( iData );
	if( aRes != maMemberHash.end()) {
	   	if ( aRes->second->IsNamedItem( iData ) )
			return aRes->second;
        DBG_ERROR("problem!  hash result is not the same as IsNamedItem");
	}

	unsigned int i;
	unsigned int nCount = maMemberArray.size();
	ScDPResultMember* pResultMember;
	for( i = 0; i < nCount ; i++ )
	{
		pResultMember = maMemberArray[i];
		if ( pResultMember->IsNamedItem( iData ) )
			return pResultMember;
	}
	return NULL;
}

void ScDPResultDimension::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev, 
                                    size_t nPos, ScDPInitState& rInitState,  sal_Bool bInitChild /*= sal_True */ )
{
    if (nPos >= ppDim.size() || nPos >= ppLev.size())
    {
        bInitialized = true;
        return;
    }

	ScDPDimension* pThisDim = ppDim[nPos];
	ScDPLevel* pThisLevel = ppLev[nPos];

    if (!pThisDim || !pThisLevel)
    {
        bInitialized = true;
        return;
    }

    bIsDataLayout = pThisDim->getIsDataLayoutDimension();   // member
    aDimensionName = pThisDim->getName();                   // member 

    // Check the autoshow setting.  If it's enabled, store the settings.
    const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
    if ( rAutoInfo.IsEnabled )
    {
        bAutoShow     = sal_True;
        bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
        nAutoMeasure  = pThisLevel->GetAutoMeasure();
        nAutoCount    = rAutoInfo.ItemCount;
    }

    // Check the sort info, and store the settings if appropriate.
    const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
    if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
    {
        bSortByData = sal_True;
        bSortAscending = rSortInfo.IsAscending;
        nSortMeasure = pThisLevel->GetSortMeasure();
    }

    // global order is used to initialize aMembers, so it doesn't have to be looked at later
    const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();

    long nDimSource = pThisDim->GetDimension();     //! check GetSourceDim?
    ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );

    // Now, go through all members and initialize them.
    ScDPMembers* pMembers = pThisLevel->GetMembersObject();
    long nMembCount = pMembers->getCount();
    for ( long i=0; i<nMembCount; i++ )
    {
        long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];

        ScDPMember* pMember = pMembers->getByIndex(nSorted);
        if ( aCompare.IsIncluded( *pMember ) )
        {
        	ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember);
    		ScDPResultMember* pNew = AddMember( aData );

            rInitState.AddMember( nDimSource, /*aMemberData*/pNew->GetDataId() );
            pNew->InitFrom( ppDim, ppLev, nPos+1, rInitState, bInitChild  );
            rInitState.RemoveMember();
        }
    }
	bInitialized = sal_True;
}

void ScDPResultDimension::LateInitFrom( LateInitParams& rParams/* const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev*/,
                                        const vector<SCROW>& pItemData, size_t nPos,
                                        ScDPInitState& rInitState )
// End Comments
{
    if ( rParams.IsEnd( nPos ) )
        return;
#ifdef DBG_UTIL
    DBG_ASSERT( nPos <= pItemData.size(), ByteString::CreateFromInt32( pItemData.size()).GetBuffer() );
#endif 
	ScDPDimension* pThisDim = rParams.GetDim( nPos );
	ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
	SCROW rThisData = pItemData[nPos];

    if (!pThisDim || !pThisLevel)
        return;

    long nDimSource = pThisDim->GetDimension();     //! check GetSourceDim?

    sal_Bool bShowEmpty = pThisLevel->getShowEmpty();

    if ( !bInitialized )
    { // init some values
        //	create all members at the first call (preserve order)
        bIsDataLayout = pThisDim->getIsDataLayoutDimension();
        aDimensionName = pThisDim->getName();

        const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
        if ( rAutoInfo.IsEnabled )
        {
            bAutoShow     = sal_True;
            bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
            nAutoMeasure  = pThisLevel->GetAutoMeasure();
            nAutoCount    = rAutoInfo.ItemCount;
        }

        const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
        if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
        {
            bSortByData = sal_True;
            bSortAscending = rSortInfo.IsAscending;
            nSortMeasure = pThisLevel->GetSortMeasure();
        }
    }

    bool bLateInitAllMembers=  bIsDataLayout || rParams.GetInitAllChild() || bShowEmpty;

   if ( !bLateInitAllMembers )
    {
        ResultMembers* pMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
        bLateInitAllMembers = pMembers->IsHasHideDetailsMembers();
#ifdef DBG_UTIL
	DBG_TRACESTR( aDimensionName )
	if ( pMembers->IsHasHideDetailsMembers() )
		DBG_TRACE ( "HasHideDetailsMembers" );
#endif
	 pMembers->SetHasHideDetailsMembers( sal_False );
    }
 
    bool bNewAllMembers =(!rParams.IsRow()) ||  nPos == 0 || bLateInitAllMembers ;
    	
    if (bNewAllMembers )
    { 
      // global order is used to initialize aMembers, so it doesn't have to be looked at later
           if ( !bInitialized )
        { //init all members 
            const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();

            ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
            ScDPMembers* pMembers = pThisLevel->GetMembersObject();
            long nMembCount = pMembers->getCount();
            for ( long i=0; i<nMembCount; i++ )
            {
                long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];

                ScDPMember* pMember = pMembers->getByIndex(nSorted);
                if ( aCompare.IsIncluded( *pMember ) )
                { // add all members
                    ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember );
                    AddMember( aData );
                }
            }
            bInitialized = sal_True;    // don't call again, even if no members were included
        }
        //	initialize only specific member (or all if "show empty" flag is set)
        if ( bLateInitAllMembers  )
        {
            long nCount = maMemberArray.size();
            for (long i=0; i<nCount; i++)
            {
                ScDPResultMember* pResultMember = maMemberArray[i];
                
                // check show empty 
                sal_Bool bAllChildren = sal_False;
                if( bShowEmpty )
                {
                    if (  pResultMember->IsNamedItem( rThisData ) )
                        bAllChildren = sal_False;
                    else 
                        bAllChildren = sal_True;
                }
                rParams.SetInitAllChildren( bAllChildren );
                rInitState.AddMember( nDimSource,  pResultMember->GetDataId() );
                pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
                rInitState.RemoveMember();
            }
        }
        else
        {
            ScDPResultMember* pResultMember = FindMember( rThisData );
            if( NULL != pResultMember )
            {
            	 //DBG_TRACE( "ScDPResultDimension::LateInitFrom");
            	 // DBG_TRACESTR( pResultMember->GetDPMember()->GetNameStr());
				  
                rInitState.AddMember( nDimSource,  pResultMember->GetDataId() );
                pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
                rInitState.RemoveMember();
            }
        }
    }
    else 
        InitWithMembers( rParams, pItemData, nPos, rInitState );
}

long ScDPResultDimension::GetSize(long nMeasure) const
{
	long nTotal = 0;
	long nMemberCount = maMemberArray.size();
	if (bIsDataLayout)
	{
		DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
					"DataLayout dimension twice?");
		//	repeat first member...
		nTotal = nMemberCount * maMemberArray[0]->GetSize(0);	// all measures have equal size
	}
	else
	{
		//	add all members
		for (long nMem=0; nMem<nMemberCount; nMem++)
			nTotal += maMemberArray[nMem]->GetSize(nMeasure);
	}
	return nTotal;
}

bool ScDPResultDimension::IsValidEntry( const vector< SCROW >& aMembers ) const
{
    if (aMembers.empty())
        return false;

    const ScDPResultMember* pMember = FindMember( aMembers[0] );
    if ( NULL != pMember )
        return pMember->IsValidEntry( aMembers );
#ifdef DBG_UTIL
    ByteString strTemp ("IsValidEntry: Member not found, DimName = " );
    strTemp += ByteString( GetName(), RTL_TEXTENCODING_UTF8 );
    DBG_TRACE( strTemp.GetBuffer() );
    //    DBG_ERROR("IsValidEntry: Member not found");
#endif
    return false;
}

void ScDPResultDimension::ProcessData( const vector< SCROW >& aMembers,
                                       const ScDPResultDimension* pDataDim, 
                                       const vector< SCROW >& aDataMembers,
                                       const vector<ScDPValueData>& aValues ) const
{
    if (aMembers.empty())
        return;

	ScDPResultMember* pMember = FindMember( aMembers[0] );
	if ( NULL != pMember )
	{
        vector</*ScDPItemData*/SCROW > aChildMembers;
        if (aMembers.size() > 1)
        {
            vector</*ScDPItemData*/SCROW >::const_iterator itr = aMembers.begin();
            aChildMembers.insert(aChildMembers.begin(), ++itr, aMembers.end());
        }
        pMember->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
        return;
    }

	DBG_ERROR("ProcessData: Member not found");
}

void ScDPResultDimension::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
												long nStart, long nMeasure )
{
	long nPos = nStart;
	long nCount = maMemberArray.size();

	for (long i=0; i<nCount; i++)
	{
	    long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];

		ScDPResultMember* pMember = maMemberArray[nSorted];
		//	in data layout dimension, use first member with different measures/names
		if ( bIsDataLayout )
		{
            bool bTotalResult = false;
			String aMbrName = pResultData->GetMeasureDimensionName( nSorted );
			String aMbrCapt = pResultData->GetMeasureString( nSorted, sal_False, SUBTOTAL_FUNC_NONE, bTotalResult );
			maMemberArray[0]->FillMemberResults( pSequences, nPos, nSorted, sal_False, &aMbrName, &aMbrCapt );
		}
		else if ( pMember->IsVisible() )
			pMember->FillMemberResults( pSequences, nPos, nMeasure, sal_False, NULL, NULL );
		// nPos is modified
	}
}

void ScDPResultDimension::FillDataResults( const ScDPResultMember* pRefMember,
							uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence,
							long nRow, long nMeasure ) const
{
	long nMemberRow = nRow;
	long nMemberMeasure = nMeasure;
	long nCount = maMemberArray.size();
	for (long i=0; i<nCount; i++)
	{
	    long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];

		const ScDPResultMember* pMember;
		if (bIsDataLayout)
		{
			DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
						"DataLayout dimension twice?");
			pMember = maMemberArray[0];
			nMemberMeasure = nSorted;
		}
		else
			pMember = maMemberArray[nSorted];

		if ( pMember->IsVisible() )
			pMember->FillDataResults( pRefMember, rSequence, nMemberRow, nMemberMeasure );
			// nMemberRow is modified
	}
}

void ScDPResultDimension::UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const
{
    long nMemberMeasure = nMeasure;
    long nCount = maMemberArray.size();
    for (long i=0; i<nCount; i++)
    {
        const ScDPResultMember* pMember;
        if (bIsDataLayout)
        {
            DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
                        "DataLayout dimension twice?");
			pMember = maMemberArray[0];
            nMemberMeasure = i;
        }
        else
			pMember = maMemberArray[i];

        if ( pMember->IsVisible() )
            pMember->UpdateDataResults( pRefMember, nMemberMeasure );
    }
}

void ScDPResultDimension::SortMembers( ScDPResultMember* pRefMember )
{
    long nCount = maMemberArray.size();

    if ( bSortByData )
    {
        // sort members

        DBG_ASSERT( aMemberOrder.empty(), "sort twice?" );
        aMemberOrder.resize( nCount );
        for (long nPos=0; nPos<nCount; nPos++)
            aMemberOrder[nPos] = nPos;

        ScDPRowMembersOrder aComp( *this, nSortMeasure, bSortAscending );
        ::std::sort( aMemberOrder.begin(), aMemberOrder.end(), aComp );
    }

    // handle children

    // for data layout, call only once - sorting measure is always taken from settings
    long nLoopCount = bIsDataLayout ? 1 : nCount;
    for (long i=0; i<nLoopCount; i++)
    {
        ScDPResultMember* pMember = maMemberArray[i];
        if ( pMember->IsVisible() )
            pMember->SortMembers( pRefMember );
    }
}

void ScDPResultDimension::DoAutoShow( ScDPResultMember* pRefMember )
{
    long nCount = maMemberArray.size();

    // handle children first, before changing the visible state

    // for data layout, call only once - sorting measure is always taken from settings
    long nLoopCount = bIsDataLayout ? 1 : nCount;
    for (long i=0; i<nLoopCount; i++)
    {
        ScDPResultMember* pMember = maMemberArray[i];
        if ( pMember->IsVisible() )
            pMember->DoAutoShow( pRefMember );
    }

    if ( bAutoShow && nAutoCount > 0 && nAutoCount < nCount )
    {
        // establish temporary order, hide remaining members

        ScMemberSortOrder aAutoOrder;
        aAutoOrder.resize( nCount );
        long nPos;
        for (nPos=0; nPos<nCount; nPos++)
            aAutoOrder[nPos] = nPos;

        ScDPRowMembersOrder aComp( *this, nAutoMeasure, !bAutoTopItems );
        ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );

        // look for equal values to the last included one

        long nIncluded = nAutoCount;
        const ScDPResultMember* pMember1 = maMemberArray[aAutoOrder[nIncluded - 1]];
        const ScDPDataMember* pDataMember1 = pMember1->IsVisible() ? pMember1->GetDataRoot() : NULL;
        sal_Bool bContinue = sal_True;
        while ( bContinue )
        {
            bContinue = sal_False;
            if ( nIncluded < nCount )
            {
                const ScDPResultMember* pMember2 = maMemberArray[aAutoOrder[nIncluded]];
                const ScDPDataMember* pDataMember2 = pMember2->IsVisible() ? pMember2->GetDataRoot() : NULL;

                if ( lcl_IsEqual( pDataMember1, pDataMember2, nAutoMeasure ) )
                {
                    ++nIncluded;                // include more members if values are equal
                    bContinue = sal_True;
                }
            }
        }

        // hide the remaining members

        for (nPos = nIncluded; nPos < nCount; nPos++)
        {
            ScDPResultMember* pMember = maMemberArray[aAutoOrder[nPos]];
            pMember->SetAutoHidden();
        }
    }
}

void ScDPResultDimension::ResetResults()
{
    long nCount = maMemberArray.size();
    for (long i=0; i<nCount; i++)
    {
        // sort order doesn't matter
        ScDPResultMember* pMember = maMemberArray[bIsDataLayout ? 0 : i];
        pMember->ResetResults( sal_False );
    }
}

long ScDPResultDimension::GetSortedIndex( long nUnsorted ) const
{
    return aMemberOrder.empty() ? nUnsorted : aMemberOrder[nUnsorted];
}

void ScDPResultDimension::UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
                                                ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
{
	const ScDPResultMember* pMember;
    long nMemberMeasure = nMeasure;
    long nCount = maMemberArray.size();
    for (long i=0; i<nCount; i++)
    {
	    long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];

        if (bIsDataLayout)
        {
            DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
                        "DataLayout dimension twice?");
            pMember = maMemberArray[0];
            nMemberMeasure = nSorted;
        }
        else
            pMember = maMemberArray[nSorted];

        if ( pMember->IsVisible() )
        {
            if ( bIsDataLayout )
                rRunning.AddRowIndex( 0, 0 );
            else
                rRunning.AddRowIndex( i, nSorted );
            pMember->UpdateRunningTotals( pRefMember, nMemberMeasure, rRunning, rTotals );
            rRunning.RemoveRowIndex();
        }
    }
}

ScDPDataMember* ScDPResultDimension::GetRowReferenceMember( const ScDPRelativePos* pRelativePos, const String* pName,
                                    const long* pRowIndexes, const long* pColIndexes ) const
{
    // get named, previous/next, or first member of this dimension (first existing if pRelativePos and pName are NULL)

    DBG_ASSERT( pRelativePos == NULL || pName == NULL, "can't use position and name" );

    ScDPDataMember* pColMember = NULL;

    sal_Bool bFirstExisting = ( pRelativePos == NULL && pName == NULL );
    long nMemberCount = maMemberArray.size();
    long nMemberIndex = 0;      // unsorted
    long nDirection = 1;        // forward if no relative position is used
    if ( pRelativePos )
    {
        nDirection = pRelativePos->nDirection;
        nMemberIndex = pRelativePos->nBasePos + nDirection;     // bounds are handled below

        DBG_ASSERT( nDirection == 1 || nDirection == -1, "Direction must be 1 or -1" );
    }
    else if ( pName )
    {
        // search for named member

        const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];

        //! use ScDPItemData, as in ScDPDimension::IsValidPage?
        while ( pRowMember && pRowMember->GetName() != *pName )
        {
            ++nMemberIndex;
            if ( nMemberIndex < nMemberCount )
                pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
            else
                pRowMember = NULL;
        }
    }

    sal_Bool bContinue = sal_True;
    while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nMemberCount )
    {
        const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];

        // get child members by given indexes

        const long* pNextRowIndex = pRowIndexes;
        while ( *pNextRowIndex >= 0 && pRowMember )
        {
            const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
            if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
                pRowMember = pRowChild->GetMember( *pNextRowIndex );
            else
                pRowMember = NULL;
            ++pNextRowIndex;
        }

        if ( pRowMember && pRelativePos )
        {
            //  Skip the member if it has hidden details
            //  (because when looking for the details, it is skipped, too).
            //  Also skip if the member is invisible because it has no data,
            //  for consistent ordering.
            if ( pRowMember->HasHiddenDetails() || !pRowMember->IsVisible() )
                pRowMember = NULL;
        }

        if ( pRowMember )
        {
            pColMember = pRowMember->GetDataRoot();

            const long* pNextColIndex = pColIndexes;
            while ( *pNextColIndex >= 0 && pColMember )
            {
                const ScDPDataDimension* pColChild = pColMember->GetChildDimension();
                if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
                    pColMember = pColChild->GetMember( *pNextColIndex );
                else
                    pColMember = NULL;
                ++pNextColIndex;
            }
        }

        // continue searching only if looking for first existing or relative position
        bContinue = ( pColMember == NULL && ( bFirstExisting || pRelativePos ) );
        nMemberIndex += nDirection;
    }

    return pColMember;
}

// static
ScDPDataMember* ScDPResultDimension::GetColReferenceMember( const ScDPRelativePos* pRelativePos, const String* pName,
                            long nRefDimPos, const ScDPRunningTotalState& rRunning )
{
    DBG_ASSERT( pRelativePos == NULL || pName == NULL, "can't use position and name" );

    const long* pColIndexes = rRunning.GetColIndexes();
    const long* pRowIndexes = rRunning.GetRowIndexes();

    // get own row member using all indexes

    const ScDPResultMember* pRowMember = rRunning.GetRowResRoot();
    ScDPDataMember* pColMember = NULL;

    const long* pNextRowIndex = pRowIndexes;
    while ( *pNextRowIndex >= 0 && pRowMember )
    {
        const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
        if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
            pRowMember = pRowChild->GetMember( *pNextRowIndex );
        else
            pRowMember = NULL;
        ++pNextRowIndex;
    }

    // get column (data) members before the reference field
    //! pass rRowParent from ScDPDataMember::UpdateRunningTotals instead

    if ( pRowMember )
    {
        pColMember = pRowMember->GetDataRoot();

        const long* pNextColIndex = pColIndexes;
        long nColSkipped = 0;
        while ( *pNextColIndex >= 0 && pColMember && nColSkipped < nRefDimPos )
        {
            const ScDPDataDimension* pColChild = pColMember->GetChildDimension();
            if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
                pColMember = pColChild->GetMember( *pNextColIndex );
            else
                pColMember = NULL;
            ++pNextColIndex;
            ++nColSkipped;
        }
    }

    // get column member for the reference field

    if ( pColMember )
    {
        const ScDPDataDimension* pReferenceDim = pColMember->GetChildDimension();
        if ( pReferenceDim )
        {
            long nReferenceCount = pReferenceDim->GetMemberCount();

            sal_Bool bFirstExisting = ( pRelativePos == NULL && pName == NULL );
            long nMemberIndex = 0;      // unsorted
            long nDirection = 1;        // forward if no relative position is used
            pColMember = NULL;          // don't use parent dimension's member if none found
            if ( pRelativePos )
            {
                nDirection = pRelativePos->nDirection;
                nMemberIndex = pRelativePos->nBasePos + nDirection;     // bounds are handled below
            }
            else if ( pName )
            {
                // search for named member

                pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );

                //! use ScDPItemData, as in ScDPDimension::IsValidPage?
                while ( pColMember && pColMember->GetName() != *pName )
                {
                    ++nMemberIndex;
                    if ( nMemberIndex < nReferenceCount )
                        pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
                    else
                        pColMember = NULL;
                }
            }

            sal_Bool bContinue = sal_True;
            while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nReferenceCount )
            {
                pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );

                // get column members below the reference field

                const long* pNextColIndex = pColIndexes + nRefDimPos + 1;
                while ( *pNextColIndex >= 0 && pColMember )
                {
                    const ScDPDataDimension* pColChild = pColMember->GetChildDimension();
                    if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
                        pColMember = pColChild->GetMember( *pNextColIndex );
                    else
                        pColMember = NULL;
                    ++pNextColIndex;
                }

                if ( pColMember && pRelativePos )
                {
                    //  Skip the member if it has hidden details
                    //  (because when looking for the details, it is skipped, too).
                    //  Also skip if the member is invisible because it has no data,
                    //  for consistent ordering.
                    if ( pColMember->HasHiddenDetails() || !pColMember->IsVisible() )
                        pColMember = NULL;
                }

                // continue searching only if looking for first existing or relative position
                bContinue = ( pColMember == NULL && ( bFirstExisting || pRelativePos ) );
                nMemberIndex += nDirection;
            }
        }
        else
            pColMember = NULL;
    }

    return pColMember;
}

void ScDPResultDimension::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
{
    String aDimName = bIsDataLayout ? String::CreateFromAscii("(data layout)") : GetName();
    lcl_DumpRow( String::CreateFromAscii("ScDPResultDimension"), aDimName, NULL, pDoc, rPos );

    SCROW nStartRow = rPos.Row();

    long nCount = bIsDataLayout ? 1 : maMemberArray.size();
    for (long i=0; i<nCount; i++)
    {
        const ScDPResultMember* pMember = maMemberArray[i];
        pMember->DumpState( pRefMember, pDoc, rPos );
    }

    lcl_Indent( pDoc, nStartRow, rPos );
}

long ScDPResultDimension::GetMemberCount() const
{
	return maMemberArray.size();
}

const ScDPResultMember* ScDPResultDimension::GetMember(long n) const
{
	return maMemberArray[n];
}
ScDPResultMember* ScDPResultDimension::GetMember(long n)
{
	return maMemberArray[n];
}

ScDPResultDimension* ScDPResultDimension::GetFirstChildDimension() const
{
	if ( maMemberArray.size() > 0 )
		return maMemberArray[0]->GetChildDimension();
	else
		return NULL;
}

void ScDPResultDimension::FillVisibilityData(ScDPResultVisibilityData& rData) const
{
    if (IsDataLayout())
        return;

    MemberArray::const_iterator itr = maMemberArray.begin(), itrEnd = maMemberArray.end();

    for (;itr != itrEnd; ++itr)
    {
        ScDPResultMember* pMember = *itr;
        if (pMember->IsValid())
        {
            ScDPItemData aItem;
            pMember->FillItemData(aItem);
            rData.addVisibleMember(GetName(), aItem);
            pMember->FillVisibilityData(rData);
        }
    }
}

// -----------------------------------------------------------------------

ScDPDataDimension::ScDPDataDimension( const ScDPResultData* pData ) :
	pResultData( pData ),
	pResultDimension( NULL ),
	bIsDataLayout( sal_False )
{
}

ScDPDataDimension::~ScDPDataDimension()
{
}

void ScDPDataDimension::InitFrom( const ScDPResultDimension* pDim )
{
	if (!pDim)
		return;

    pResultDimension = pDim;
	bIsDataLayout = pDim->IsDataLayout();

    // Go through all result members under the given result dimension, and
    // create a new data member instance for each result member.
	long nCount = pDim->GetMemberCount();
	for (long i=0; i<nCount; i++)
	{
		const ScDPResultMember* pResMem = pDim->GetMember(i);

		ScDPDataMember* pNew = new ScDPDataMember( pResultData, pResMem );
		aMembers.Insert( pNew, aMembers.Count() );

		if ( !pResultData->IsLateInit() )
		{
			//	with LateInit, pResMem hasn't necessarily been initialized yet,
			//	so InitFrom for the new result member is called from its ProcessData method

			const ScDPResultDimension* pChildDim = pResMem->GetChildDimension();
			if ( pChildDim )
				pNew->InitFrom( pChildDim );
		}
	}
}

void ScDPDataDimension::ProcessData( const vector< SCROW >& aDataMembers, const vector<ScDPValueData>& aValues,
                                     const ScDPSubTotalState& rSubState )
{
    // the ScDPItemData array must contain enough entries for all dimensions - this isn't checked

    long nCount = aMembers.Count();
    for (long i=0; i<nCount; i++)
    {
        ScDPDataMember* pMember = aMembers[(sal_uInt16)i];

        // always first member for data layout dim
        if ( bIsDataLayout || ( !aDataMembers.empty() && pMember->IsNamedItem(aDataMembers[0]) ) )
        {
            vector</*ScDPItemData*/SCROW> aChildDataMembers;
            if (aDataMembers.size() > 1)
            {
                vector</*ScDPItemData*/SCROW >::const_iterator itr = aDataMembers.begin();
                aChildDataMembers.insert(aChildDataMembers.begin(), ++itr, aDataMembers.end());
            }
            pMember->ProcessData( aChildDataMembers, aValues, rSubState );
            return;
        }
    }

    DBG_ERROR("ProcessData: Member not found");
}

void ScDPDataDimension::FillDataRow( const ScDPResultDimension* pRefDim,
									uno::Sequence<sheet::DataResult>& rSequence,
									long nCol, long nMeasure, sal_Bool bIsSubTotalRow,
									const ScDPSubTotalState& rSubState ) const
{
	DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
    DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );

    const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();

	long nMemberMeasure = nMeasure;
	long nMemberCol = nCol;
	long nCount = aMembers.Count();
	for (long i=0; i<nCount; i++)
	{
	    long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];

		long nMemberPos = nSorted;
		if (bIsDataLayout)
		{
			DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
						"DataLayout dimension twice?");
			nMemberPos = 0;
			nMemberMeasure = nSorted;
		}

		const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
		if ( pRefMember->IsVisible() )	//! here or in ScDPDataMember::FillDataRow ???
		{
			const ScDPDataMember* pDataMember = aMembers[(sal_uInt16)nMemberPos];
			pDataMember->FillDataRow( pRefMember, rSequence, nMemberCol, nMemberMeasure, bIsSubTotalRow, rSubState );
			// nMemberCol is modified
		}
	}
}

void ScDPDataDimension::UpdateDataRow( const ScDPResultDimension* pRefDim,
                                    long nMeasure, sal_Bool bIsSubTotalRow,
                                    const ScDPSubTotalState& rSubState ) const
{
    DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
    DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );

    long nMemberMeasure = nMeasure;
    long nCount = aMembers.Count();
    for (long i=0; i<nCount; i++)
    {
        long nMemberPos = i;
        if (bIsDataLayout)
        {
            DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
                        "DataLayout dimension twice?");
            nMemberPos = 0;
            nMemberMeasure = i;
        }

        // Calculate must be called even if the member is not visible (for use as reference value)
        const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
        ScDPDataMember* pDataMember = aMembers[(sal_uInt16)nMemberPos];
        pDataMember->UpdateDataRow( pRefMember, nMemberMeasure, bIsSubTotalRow, rSubState );
    }
}

void ScDPDataDimension::SortMembers( ScDPResultDimension* pRefDim )
{
    long nCount = aMembers.Count();

    if ( pRefDim->IsSortByData() )
    {
        // sort members

        ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
        DBG_ASSERT( rMemberOrder.empty(), "sort twice?" );
        rMemberOrder.resize( nCount );
        for (long nPos=0; nPos<nCount; nPos++)
            rMemberOrder[nPos] = nPos;

        ScDPColMembersOrder aComp( *this, pRefDim->GetSortMeasure(), pRefDim->IsSortAscending() );
        ::std::sort( rMemberOrder.begin(), rMemberOrder.end(), aComp );
    }

    // handle children

    DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
    DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );

    // for data layout, call only once - sorting measure is always taken from settings
    long nLoopCount = bIsDataLayout ? 1 : nCount;
    for (long i=0; i<nLoopCount; i++)
    {
        ScDPResultMember* pRefMember = pRefDim->GetMember(i);
        if ( pRefMember->IsVisible() )  //! here or in ScDPDataMember ???
        {
            ScDPDataMember* pDataMember = aMembers[(sal_uInt16)i];
            pDataMember->SortMembers( pRefMember );
        }
    }
}

void ScDPDataDimension::DoAutoShow( ScDPResultDimension* pRefDim )
{
    long nCount = aMembers.Count();

    // handle children first, before changing the visible state

    DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
    DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );

    // for data layout, call only once - sorting measure is always taken from settings
    long nLoopCount = bIsDataLayout ? 1 : nCount;
    for (long i=0; i<nLoopCount; i++)
    {
        ScDPResultMember* pRefMember = pRefDim->GetMember(i);
        if ( pRefMember->IsVisible() )  //! here or in ScDPDataMember ???
        {
            ScDPDataMember* pDataMember = aMembers[(sal_uInt16)i];
            pDataMember->DoAutoShow( pRefMember );
        }
    }

    if ( pRefDim->IsAutoShow() && pRefDim->GetAutoCount() > 0 && pRefDim->GetAutoCount() < nCount )
    {
        // establish temporary order, hide remaining members

        ScMemberSortOrder aAutoOrder;
        aAutoOrder.resize( nCount );
        long nPos;
        for (nPos=0; nPos<nCount; nPos++)
            aAutoOrder[nPos] = nPos;

        ScDPColMembersOrder aComp( *this, pRefDim->GetAutoMeasure(), !pRefDim->IsAutoTopItems() );
        ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );

        // look for equal values to the last included one

        long nIncluded = pRefDim->GetAutoCount();
        ScDPDataMember* pDataMember1 = aMembers[(sal_uInt16)aAutoOrder[nIncluded - 1]];
        if ( !pDataMember1->IsVisible() )
            pDataMember1 = NULL;
        sal_Bool bContinue = sal_True;
        while ( bContinue )
        {
            bContinue = sal_False;
            if ( nIncluded < nCount )
            {
                ScDPDataMember* pDataMember2 = aMembers[(sal_uInt16)aAutoOrder[nIncluded]];
                if ( !pDataMember2->IsVisible() )
                    pDataMember2 = NULL;

                if ( lcl_IsEqual( pDataMember1, pDataMember2, pRefDim->GetAutoMeasure() ) )
                {
                    ++nIncluded;                // include more members if values are equal
                    bContinue = sal_True;
                }
            }
        }

        // hide the remaining members

        for (nPos = nIncluded; nPos < nCount; nPos++)
        {
            ScDPResultMember* pMember = pRefDim->GetMember(aAutoOrder[nPos]);
            pMember->SetAutoHidden();
        }
    }
}

void ScDPDataDimension::ResetResults()
{
    long nCount = aMembers.Count();
    for (long i=0; i<nCount; i++)
    {
        //  sort order doesn't matter

        long nMemberPos = bIsDataLayout ? 0 : i;
        ScDPDataMember* pDataMember = aMembers[(sal_uInt16)nMemberPos];
        pDataMember->ResetResults();
    }
}

long ScDPDataDimension::GetSortedIndex( long nUnsorted ) const
{
    if (!pResultDimension)
       return nUnsorted;

    const ScMemberSortOrder& rMemberOrder = pResultDimension->GetMemberOrder();
    return rMemberOrder.empty() ? nUnsorted : rMemberOrder[nUnsorted];
}

void ScDPDataDimension::UpdateRunningTotals( const ScDPResultDimension* pRefDim,
                                    long nMeasure, sal_Bool bIsSubTotalRow,
                                    const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
                                    ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent ) const
{
    DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
    DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );

    long nMemberMeasure = nMeasure;
    long nCount = aMembers.Count();
    for (long i=0; i<nCount; i++)
    {
        const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
	    long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];

        long nMemberPos = nSorted;
        if (bIsDataLayout)
        {
            DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
                        "DataLayout dimension twice?");
            nMemberPos = 0;
            nMemberMeasure = nSorted;
        }

        const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
        if ( pRefMember->IsVisible() )  //! here or in ScDPDataMember::UpdateRunningTotals ???
        {
            if ( bIsDataLayout )
                rRunning.AddColIndex( 0, 0 );
            else
                rRunning.AddColIndex( i, nSorted );

            ScDPDataMember* pDataMember = aMembers[(sal_uInt16)nMemberPos];
            pDataMember->UpdateRunningTotals( pRefMember, nMemberMeasure,
                                            bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent );

            rRunning.RemoveColIndex();
        }
    }
}

void ScDPDataDimension::DumpState( const ScDPResultDimension* pRefDim, ScDocument* pDoc, ScAddress& rPos ) const
{
    String aDimName = String::CreateFromAscii( bIsDataLayout ? "(data layout)" : "(unknown)" );
    lcl_DumpRow( String::CreateFromAscii("ScDPDataDimension"), aDimName, NULL, pDoc, rPos );

    SCROW nStartRow = rPos.Row();

    long nCount = bIsDataLayout ? 1 : aMembers.Count();
    for (long i=0; i<nCount; i++)
    {
        const ScDPResultMember* pRefMember = pRefDim->GetMember(i);
        const ScDPDataMember* pDataMember = aMembers[(sal_uInt16)i];
        pDataMember->DumpState( pRefMember, pDoc, rPos );
    }

    lcl_Indent( pDoc, nStartRow, rPos );
}

long ScDPDataDimension::GetMemberCount() const
{
    return aMembers.Count();
}

ScDPDataMember* ScDPDataDimension::GetMember(long n) const
{
    return aMembers[(sal_uInt16)n];
}

// ----------------------------------------------------------------------------

ScDPResultVisibilityData::ScDPResultVisibilityData(
 ScDPSource* pSource) :
    mpSource(pSource)
{
}

ScDPResultVisibilityData::~ScDPResultVisibilityData()
{
}

void ScDPResultVisibilityData::addVisibleMember(const String& rDimName, const ScDPItemData& rMemberItem)
{
    DimMemberType::iterator itr = maDimensions.find(rDimName);
    if (itr == maDimensions.end())
    {
        pair<DimMemberType::iterator, bool> r = maDimensions.insert(
            DimMemberType::value_type(rDimName, VisibleMemberType()));

        if (!r.second)
            // insertion failed.
            return;

        itr = r.first;
    }
    VisibleMemberType& rMem = itr->second;
    VisibleMemberType::iterator itrMem = rMem.find(rMemberItem);
    if (itrMem == rMem.end())
        rMem.insert(rMemberItem);
}

void ScDPResultVisibilityData::fillFieldFilters(vector<ScDPCacheTable::Criterion>& rFilters) const
{
    typedef hash_map<String, long, ScStringHashCode> FieldNameMapType;
    FieldNameMapType aFieldNames;
    ScDPTableData* pData = mpSource->GetData();
    long nColumnCount = pData->GetColumnCount();
    for (long i = 0; i < nColumnCount; ++i)
    {
        aFieldNames.insert(
            FieldNameMapType::value_type(pData->getDimensionName(i), i));
    }

    const ScDPDimensions* pDims = mpSource->GetDimensionsObject();
    for (DimMemberType::const_iterator itr = maDimensions.begin(), itrEnd = maDimensions.end();
          itr != itrEnd; ++itr)
    {
        const String& rDimName = itr->first;
        ScDPCacheTable::Criterion aCri;
        FieldNameMapType::const_iterator itrField = aFieldNames.find(rDimName);
        if (itrField == aFieldNames.end())
            // This should never happen!
            continue;

        long nDimIndex = itrField->second;
        aCri.mnFieldIndex = static_cast<sal_Int32>(nDimIndex);	
        aCri.mpFilter.reset(new ScDPCacheTable::GroupFilter(/*mrSharedString*/));
     
        ScDPCacheTable::GroupFilter* pGrpFilter = 
            static_cast<ScDPCacheTable::GroupFilter*>(aCri.mpFilter.get());

        const VisibleMemberType& rMem = itr->second;
        for (VisibleMemberType::const_iterator itrMem = rMem.begin(), itrMemEnd = rMem.end();
              itrMem != itrMemEnd; ++itrMem)
        {
            const ScDPItemData& rMemItem = *itrMem;
            pGrpFilter->addMatchItem(rMemItem.GetString(), rMemItem.GetValue(), rMemItem.IsValue());
        }

        ScDPDimension* pDim = pDims->getByIndex(nDimIndex);
        ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
            GetLevelsObject()->getByIndex(0)->GetMembersObject();
        if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(pMembers->getCount()))
            rFilters.push_back(aCri);
    }
}

size_t ScDPResultVisibilityData::MemberHash::operator() (const ScDPItemData& r) const
{
    if (r.IsValue())
        return static_cast<size_t>(::rtl::math::approxFloor(r.GetValue()));
    else
        return rtl_ustr_hashCode_WithLength(r.GetString().GetBuffer(), r.GetString().Len());
}
// Wang Xu Ming -- 2009-6-10
// DataPilot Migration
SCROW ScDPResultMember::GetDataId( ) const 
{
 const ScDPMember*   pMemberDesc = GetDPMember();
  if (pMemberDesc)
        return  pMemberDesc->GetItemDataId();
    return -1;
}

ScDPResultMember* ScDPResultDimension::AddMember(const ScDPParentDimData &aData )
{
	ScDPResultMember* pMember = new ScDPResultMember( pResultData, aData, sal_False );
	SCROW	nDataIndex = pMember->GetDataId();
	maMemberArray.push_back( pMember );
	
	if ( maMemberHash.end() == maMemberHash.find( nDataIndex ) )
		maMemberHash.insert( std::pair< SCROW, ScDPResultMember *>( nDataIndex, pMember ) );
	return pMember;
}

ResultMembers* ScDPResultDimension::GetResultMember( ScDPDimension* pThisDim, ScDPLevel* pThisLevel )
{
	 ResultMembers* pResultMembers = new ResultMembers();
	 // global order is used to initialize aMembers, so it doesn't have to be looked at later
	 const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
	 	 
	 ScDPMembers* pMembers = pThisLevel->GetMembersObject();
	 long nMembCount = pMembers->getCount();
	 for ( long i=0; i<nMembCount; i++ )
	 {
		 long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
		 ScDPMember* pMember = pMembers->getByIndex(nSorted);
		 if ( NULL == pResultMembers->FindMember( pMember->GetItemDataId() ) )
		 {
			ScDPParentDimData* pNew = new ScDPParentDimData( i, pThisDim, pThisLevel, pMember );
			pResultMembers->InsertMember(  pNew );
		 }
	 }
	 return pResultMembers;
}

ScDPResultMember* ScDPResultDimension::InsertMember(ScDPParentDimData *pMemberData)
{
    SCROW  nInsert = 0;
    if ( !lcl_SearchMember( maMemberArray, pMemberData->mnOrder , nInsert ) )
    { //Member not exist
        ScDPResultMember* pNew = new ScDPResultMember( pResultData, *pMemberData, sal_False );
        maMemberArray.insert( maMemberArray.begin()+nInsert, pNew );

        SCROW	nDataIndex = pMemberData->mpMemberDesc->GetItemDataId();
        if ( maMemberHash.end() == maMemberHash.find( nDataIndex ) )
            maMemberHash.insert( std::pair< SCROW, ScDPResultMember *>( nDataIndex, pNew ) );
        return pNew;
    }
    return maMemberArray[ nInsert ];
}

void ScDPResultDimension::  InitWithMembers(  LateInitParams& rParams, 
        const ::std::vector< SCROW >&     pItemData, 
        size_t  nPos,
        ScDPInitState& rInitState  )
{
    if ( rParams.IsEnd( nPos ) )
        return;
    ScDPDimension* pThisDim        = rParams.GetDim( nPos );
    ScDPLevel*        pThisLevel      = rParams.GetLevel( nPos );
    SCROW             nDataID         = pItemData[nPos];

    if (pThisDim && pThisLevel)
    {
        long nDimSource = pThisDim->GetDimension();     //! check GetSourceDim?

        //	create all members at the first call (preserve order)
        ResultMembers* pMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
        ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
        //	initialize only specific member (or all if "show empty" flag is set)
        ScDPResultMember* pResultMember = NULL;
        if ( bInitialized  ) 
            pResultMember = FindMember( nDataID );
        else 
            bInitialized = sal_True;

        if ( pResultMember == NULL )
        { //only insert found item
            ScDPParentDimData* pMemberData = pMembers->FindMember( nDataID );
            if ( pMemberData && aCompare.IsIncluded( *( pMemberData->mpMemberDesc ) ) )
                pResultMember = InsertMember( pMemberData );
        }
        if ( pResultMember )
        {
 //           DBG_TRACE( "ScDPResultDimension::InitWithMembers");
 //           DBG_TRACESTR( pResultMember->GetDPMember()->GetNameStr());
            rInitState.AddMember( nDimSource, pResultMember->GetDataId()  );
            pResultMember->LateInitFrom( rParams /*ppDim, ppLev*/, pItemData, nPos+1 , rInitState );
            rInitState.RemoveMember();
        }
    }
}

ScDPParentDimData* ResultMembers::FindMember( const SCROW& nIndex ) const
{
	DimMemberHash::const_iterator aRes = maMemberHash.find( nIndex );
	if( aRes != maMemberHash.end()) {
	   	if (  aRes->second->mpMemberDesc && aRes->second->mpMemberDesc->GetItemDataId()==nIndex )
			return aRes->second;
	}
	return NULL;
}
void  ResultMembers::InsertMember(  ScDPParentDimData* pNew )
{
    if ( !pNew->mpMemberDesc->getShowDetails() )
		mbHasHideDetailsMember = sal_True;
    maMemberHash.insert( std::pair< const SCROW, ScDPParentDimData *>( pNew->mpMemberDesc->GetItemDataId(), pNew ) );
}

ResultMembers::ResultMembers():
	mbHasHideDetailsMember( sal_False )
{
}
ResultMembers::~ResultMembers()
{
	for ( DimMemberHash::const_iterator iter = maMemberHash.begin(); iter != maMemberHash.end(); iter++ )
		delete iter->second;
}
// -----------------------------------------------------------------------
LateInitParams::LateInitParams( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev, sal_Bool bRow, sal_Bool bInitChild, sal_Bool bAllChildren ):
    mppDim( ppDim ),
    mppLev( ppLev ),
    mbRow( bRow ),
    mbInitChild( bInitChild ),
    mbAllChildren( bAllChildren )
{
}

LateInitParams::~LateInitParams()
{
}

sal_Bool LateInitParams::IsEnd( size_t nPos ) const
{
    return nPos >= mppDim.size();
}

// End Comments
// Wang Xu Ming -- 2009-8-4
// DataPilot Migration - old defects merge
void ScDPResultDimension::CheckShowEmpty( sal_Bool bShow )
{
        long nCount = maMemberArray.size();

            ScDPResultMember* pMember = NULL;
                for (long i=0; i<nCount; i++)
                {
                            pMember = maMemberArray.at(i);
                                    pMember->CheckShowEmpty( bShow );    
                }

}

void ScDPResultMember::CheckShowEmpty( sal_Bool bShow )
{
        if ( bHasElements )
        {
                    ScDPResultDimension* pChildDim = GetChildDimension();
                            if (pChildDim )
                                            pChildDim->CheckShowEmpty();
        }
        else if ( IsValid() && bInitialized )
        {
                    bShow = bShow ||  (  GetParentLevel() && GetParentLevel()->getShowEmpty() );
                            if ( bShow )
                            {
                                            SetHasElements();
                                                        ScDPResultDimension* pChildDim = GetChildDimension();
                                                                    if (pChildDim )
                                                                                        pChildDim->CheckShowEmpty( sal_True );
                            }   
        }
}// End Comments
