/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
#include "dpgroup.hxx"
#include "dpsave.hxx"
#include "xestream.hxx"
#include "xistream.hxx"
#include "xestring.hxx"
#include "xlpivot.hxx"
#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>

using ::com::sun::star::sheet::GeneralFunction;
using ::com::sun::star::sheet::DataPilotFieldOrientation;

namespace ScDPSortMode = ::com::sun::star::sheet::DataPilotFieldSortMode;
namespace ScDPShowItemsMode = ::com::sun::star::sheet::DataPilotFieldShowItemsMode;
namespace ScDPLayoutMode = ::com::sun::star::sheet::DataPilotFieldLayoutMode;
namespace ScDPRefItemType = ::com::sun::star::sheet::DataPilotFieldReferenceItemType;
namespace ScDPGroupBy = ::com::sun::star::sheet::DataPilotFieldGroupBy;

// ============================================================================
// Pivot cache
// ============================================================================

XclPCItem::XclPCItem() :
    meType( EXC_PCITEM_INVALID )
{
}

XclPCItem::~XclPCItem()
{
}

void XclPCItem::SetEmpty()
{
    meType = EXC_PCITEM_EMPTY;
    maText.Erase();
}

void XclPCItem::SetText( const String& rText )
{
    meType = EXC_PCITEM_TEXT;
    maText = rText;
}

void XclPCItem::SetDouble( double fValue )
{
    meType = EXC_PCITEM_DOUBLE;
    //! TODO convert double to string
    maText.Erase();
    mfValue = fValue;
}

void XclPCItem::SetDateTime( const DateTime& rDateTime )
{
    meType = EXC_PCITEM_DATETIME;
    //! TODO convert date to string
    maText.Erase();
    maDateTime = rDateTime;
}

void XclPCItem::SetInteger( sal_Int16 nValue )
{
    meType = EXC_PCITEM_INTEGER;
    maText = String::CreateFromInt32( nValue );
    mnValue = nValue;
}

void XclPCItem::SetError( sal_uInt16 nError )
{
    meType = EXC_PCITEM_ERROR;
    //! TODO convert error to string
    maText.Erase();
    mnError = nError;
}

void XclPCItem::SetBool( bool bValue )
{
    meType = EXC_PCITEM_BOOL;
    //! TODO convert boolean to string
    maText.Erase();
    mbValue = bValue;
}

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

bool XclPCItem::IsEqual( const XclPCItem& rItem ) const
{
    if( meType == rItem.meType ) switch( meType )
    {
        case EXC_PCITEM_INVALID:    return true;
        case EXC_PCITEM_EMPTY:      return true;
        case EXC_PCITEM_TEXT:       return maText     == rItem.maText;
        case EXC_PCITEM_DOUBLE:     return mfValue    == rItem.mfValue;
        case EXC_PCITEM_DATETIME:   return maDateTime == rItem.maDateTime;
        case EXC_PCITEM_INTEGER:    return mnValue    == rItem.mnValue;
        case EXC_PCITEM_BOOL:       return mbValue    == rItem.mbValue;
        case EXC_PCITEM_ERROR:      return mnError    == rItem.mnError;
        default:    DBG_ERRORFILE( "XclPCItem::IsEqual - unknown pivot cache item type" );
    }
    return false;
}

bool XclPCItem::IsEmpty() const
{
    return meType == EXC_PCITEM_EMPTY;
}

const String* XclPCItem::GetText() const
{
    return (meType == EXC_PCITEM_TEXT) ? &maText : 0;
}

const double* XclPCItem::GetDouble() const
{
    return (meType == EXC_PCITEM_DOUBLE) ? &mfValue : 0;
}

const DateTime* XclPCItem::GetDateTime() const
{
    return (meType == EXC_PCITEM_DATETIME) ? &maDateTime : 0;
}

const sal_Int16* XclPCItem::GetInteger() const
{
    return (meType == EXC_PCITEM_INTEGER) ? &mnValue : 0;
}

const sal_uInt16* XclPCItem::GetError() const
{
    return (meType == EXC_PCITEM_ERROR) ? &mnError : 0;
}

const bool* XclPCItem::GetBool() const
{
    return (meType == EXC_PCITEM_BOOL) ? &mbValue : 0;
}

// Field settings =============================================================

XclPCFieldInfo::XclPCFieldInfo() :
    mnFlags( 0 ),
    mnGroupChild( 0 ),
    mnGroupBase( 0 ),
    mnVisItems( 0 ),
    mnGroupItems( 0 ),
    mnBaseItems( 0 ),
    mnOrigItems( 0 )
{
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPCFieldInfo& rInfo )
{
    rStrm   >> rInfo.mnFlags
            >> rInfo.mnGroupChild
            >> rInfo.mnGroupBase
            >> rInfo.mnVisItems
            >> rInfo.mnGroupItems
            >> rInfo.mnBaseItems
            >> rInfo.mnOrigItems;
    if( rStrm.GetRecLeft() >= 3 )
        rInfo.maName = rStrm.ReadUniString();
    else
        rInfo.maName.Erase();
    return rStrm;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPCFieldInfo& rInfo )
{
    return rStrm
        << rInfo.mnFlags
        << rInfo.mnGroupChild
        << rInfo.mnGroupBase
        << rInfo.mnVisItems
        << rInfo.mnGroupItems
        << rInfo.mnBaseItems
        << rInfo.mnOrigItems
        << XclExpString( rInfo.maName );
}

// Numeric grouping field settings ============================================

XclPCNumGroupInfo::XclPCNumGroupInfo() :
    mnFlags( EXC_SXNUMGROUP_AUTOMIN | EXC_SXNUMGROUP_AUTOMAX )
{
    SetNumType();
}

void XclPCNumGroupInfo::SetNumType()
{
    SetXclDataType( EXC_SXNUMGROUP_TYPE_NUM );
}

sal_Int32 XclPCNumGroupInfo::GetScDateType() const
{
    sal_Int32 nScType = 0;
    switch( GetXclDataType() )
    {
        case EXC_SXNUMGROUP_TYPE_SEC:   nScType = ScDPGroupBy::SECONDS;   break;
        case EXC_SXNUMGROUP_TYPE_MIN:   nScType = ScDPGroupBy::MINUTES;   break;
        case EXC_SXNUMGROUP_TYPE_HOUR:  nScType = ScDPGroupBy::HOURS;     break;
        case EXC_SXNUMGROUP_TYPE_DAY:   nScType = ScDPGroupBy::DAYS;      break;
        case EXC_SXNUMGROUP_TYPE_MONTH: nScType = ScDPGroupBy::MONTHS;    break;
        case EXC_SXNUMGROUP_TYPE_QUART: nScType = ScDPGroupBy::QUARTERS;  break;
        case EXC_SXNUMGROUP_TYPE_YEAR:  nScType = ScDPGroupBy::YEARS;     break;
        default:    OSL_TRACE( "XclPCNumGroupInfo::GetScDateType - unexpected date type %d", GetXclDataType() );
    }
    return nScType;
}

void XclPCNumGroupInfo::SetScDateType( sal_Int32 nScType )
{
    sal_uInt16 nXclType = EXC_SXNUMGROUP_TYPE_NUM;
    switch( nScType )
    {
        case ScDPGroupBy::SECONDS:    nXclType = EXC_SXNUMGROUP_TYPE_SEC;     break;
        case ScDPGroupBy::MINUTES:    nXclType = EXC_SXNUMGROUP_TYPE_MIN;     break;
        case ScDPGroupBy::HOURS:      nXclType = EXC_SXNUMGROUP_TYPE_HOUR;    break;
        case ScDPGroupBy::DAYS:       nXclType = EXC_SXNUMGROUP_TYPE_DAY;     break;
        case ScDPGroupBy::MONTHS:     nXclType = EXC_SXNUMGROUP_TYPE_MONTH;   break;
        case ScDPGroupBy::QUARTERS:   nXclType = EXC_SXNUMGROUP_TYPE_QUART;   break;
        case ScDPGroupBy::YEARS:      nXclType = EXC_SXNUMGROUP_TYPE_YEAR;    break;
        default:    OSL_TRACE( "XclPCNumGroupInfo::SetScDateType - unexpected date type %d", nScType );
    }
    SetXclDataType( nXclType );
}

sal_uInt16 XclPCNumGroupInfo::GetXclDataType() const
{
    return ::extract_value< sal_uInt16 >( mnFlags, 2, 4 );
}

void XclPCNumGroupInfo::SetXclDataType( sal_uInt16 nXclType )
{
    ::insert_value( mnFlags, nXclType, 2, 4 );
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPCNumGroupInfo& rInfo )
{
    return rStrm >> rInfo.mnFlags;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPCNumGroupInfo& rInfo )
{
    return rStrm << rInfo.mnFlags;
}

// Base class for pivot cache fields ==========================================

XclPCField::XclPCField( XclPCFieldType eFieldType, sal_uInt16 nFieldIdx ) :
    meFieldType( eFieldType ),
    mnFieldIdx( nFieldIdx )
{
}

XclPCField::~XclPCField()
{
}

bool XclPCField::IsSupportedField() const
{
    return (meFieldType != EXC_PCFIELD_CALCED) && (meFieldType != EXC_PCFIELD_UNKNOWN);
}

bool XclPCField::IsStandardField() const
{
    return meFieldType == EXC_PCFIELD_STANDARD;
}

bool XclPCField::IsStdGroupField() const
{
    return meFieldType == EXC_PCFIELD_STDGROUP;
}

bool XclPCField::IsNumGroupField() const
{
    return meFieldType == EXC_PCFIELD_NUMGROUP;
}

bool XclPCField::IsDateGroupField() const
{
    return (meFieldType == EXC_PCFIELD_DATEGROUP) || (meFieldType == EXC_PCFIELD_DATECHILD);
}

bool XclPCField::IsGroupField() const
{
    return IsStdGroupField() || IsNumGroupField() || IsDateGroupField();
}

bool XclPCField::IsGroupBaseField() const
{
    return ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
}

bool XclPCField::IsGroupChildField() const
{
    return (meFieldType == EXC_PCFIELD_STDGROUP) || (meFieldType == EXC_PCFIELD_DATECHILD);
}

sal_uInt16 XclPCField::GetBaseFieldIndex() const
{
    return IsGroupChildField() ? maFieldInfo.mnGroupBase : mnFieldIdx;
}

bool XclPCField::HasOrigItems() const
{
    return IsSupportedField() && ((maFieldInfo.mnOrigItems > 0) || HasPostponedItems());
}

bool XclPCField::HasInlineItems() const
{
    return (IsStandardField() || IsGroupField()) && ((maFieldInfo.mnGroupItems > 0) || (maFieldInfo.mnOrigItems > 0));
}

bool XclPCField::HasPostponedItems() const
{
    return IsStandardField() && ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_POSTPONE );
}

bool XclPCField::Has16BitIndexes() const
{
    return IsStandardField() && ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_16BIT );
}

// Pivot cache settings =======================================================

/** Contains data for a pivot cache (SXDB record). */
XclPCInfo::XclPCInfo() :
    mnSrcRecs( 0 ),
    mnStrmId( 0xFFFF ),
    mnFlags( EXC_SXDB_DEFAULTFLAGS ),
    mnBlockRecs( EXC_SXDB_BLOCKRECS ),
    mnStdFields( 0 ),
    mnTotalFields( 0 ),
    mnSrcType( EXC_SXDB_SRC_SHEET )
{
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPCInfo& rInfo )
{
    rStrm   >> rInfo.mnSrcRecs
            >> rInfo.mnStrmId
            >> rInfo.mnFlags
            >> rInfo.mnBlockRecs
            >> rInfo.mnStdFields
            >> rInfo.mnTotalFields;
    rStrm.Ignore( 2 );
    rStrm   >> rInfo.mnSrcType;
    rInfo.maUserName = rStrm.ReadUniString();
    return rStrm;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPCInfo& rInfo )
{
    return rStrm
        << rInfo.mnSrcRecs
        << rInfo.mnStrmId
        << rInfo.mnFlags
        << rInfo.mnBlockRecs
        << rInfo.mnStdFields
        << rInfo.mnTotalFields
        << sal_uInt16( 0 )
        << rInfo.mnSrcType
        << XclExpString( rInfo.maUserName );
}

// ============================================================================
// Pivot table
// ============================================================================

// cached name ================================================================

XclImpStream& operator>>( XclImpStream& rStrm, XclPTCachedName& rCachedName )
{
    sal_uInt16 nStrLen;
    rStrm >> nStrLen;
    rCachedName.mbUseCache = nStrLen == EXC_PT_NOSTRING;
    if( rCachedName.mbUseCache )
        rCachedName.maName.Erase();
    else
        rCachedName.maName = rStrm.ReadUniString( nStrLen );
    return rStrm;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTCachedName& rCachedName )
{
    if( rCachedName.mbUseCache )
        rStrm << EXC_PT_NOSTRING;
    else
        rStrm << XclExpString( rCachedName.maName, EXC_STR_DEFAULT, EXC_PT_MAXSTRLEN );
    return rStrm;
}

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

const String* XclPTVisNameInfo::GetVisName() const
{
    return HasVisName() ? &maVisName.maName : 0;
}

void XclPTVisNameInfo::SetVisName( const String& rName )
{
    maVisName.maName = rName;
    maVisName.mbUseCache = rName.Len() == 0;
}

// Field item settings ========================================================

XclPTItemInfo::XclPTItemInfo() :
    mnType( EXC_SXVI_TYPE_DATA ),
    mnFlags( EXC_SXVI_DEFAULTFLAGS ),
    mnCacheIdx( EXC_SXVI_DEFAULT_CACHE )
{
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTItemInfo& rInfo )
{
    return rStrm
        >> rInfo.mnType
        >> rInfo.mnFlags
        >> rInfo.mnCacheIdx
        >> rInfo.maVisName;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTItemInfo& rInfo )
{
    return rStrm
        << rInfo.mnType
        << rInfo.mnFlags
        << rInfo.mnCacheIdx
        << rInfo.maVisName;
}

// General field settings =====================================================

XclPTFieldInfo::XclPTFieldInfo() :
    mnAxes( EXC_SXVD_AXIS_NONE ),
    mnSubtCount( 1 ),
    mnSubtotals( EXC_SXVD_SUBT_DEFAULT ),
    mnItemCount( 0 ),
    mnCacheIdx( EXC_SXVD_DEFAULT_CACHE )
{
}

DataPilotFieldOrientation XclPTFieldInfo::GetApiOrient( sal_uInt16 nMask ) const
{
    using namespace ::com::sun::star::sheet;
    DataPilotFieldOrientation eOrient = DataPilotFieldOrientation_HIDDEN;
    sal_uInt16 nUsedAxes = mnAxes & nMask;
    if( nUsedAxes & EXC_SXVD_AXIS_ROW )
        eOrient = DataPilotFieldOrientation_ROW;
    else if( nUsedAxes & EXC_SXVD_AXIS_COL )
        eOrient = DataPilotFieldOrientation_COLUMN;
    else if( nUsedAxes & EXC_SXVD_AXIS_PAGE )
        eOrient = DataPilotFieldOrientation_PAGE;
    else if( nUsedAxes & EXC_SXVD_AXIS_DATA )
        eOrient = DataPilotFieldOrientation_DATA;
    return eOrient;
}

void XclPTFieldInfo::AddApiOrient( DataPilotFieldOrientation eOrient )
{
    using namespace ::com::sun::star::sheet;
    switch( eOrient )
    {
        case DataPilotFieldOrientation_ROW:     mnAxes |= EXC_SXVD_AXIS_ROW;    break;
        case DataPilotFieldOrientation_COLUMN:  mnAxes |= EXC_SXVD_AXIS_COL;    break;
        case DataPilotFieldOrientation_PAGE:    mnAxes |= EXC_SXVD_AXIS_PAGE;   break;
        case DataPilotFieldOrientation_DATA:    mnAxes |= EXC_SXVD_AXIS_DATA;   break;
        default:;
    }
}

//! TODO: should be a Sequence<GeneralFunction> in ScDPSaveData
void XclPTFieldInfo::GetSubtotals( XclPTSubtotalVec& rSubtotals ) const
{
    rSubtotals.clear();
    rSubtotals.reserve( 16 );

    using namespace ::com::sun::star::sheet;
    if( mnSubtotals & EXC_SXVD_SUBT_DEFAULT )   rSubtotals.push_back( GeneralFunction_AUTO );
    if( mnSubtotals & EXC_SXVD_SUBT_SUM )       rSubtotals.push_back( GeneralFunction_SUM );
    if( mnSubtotals & EXC_SXVD_SUBT_COUNT )     rSubtotals.push_back( GeneralFunction_COUNT );
    if( mnSubtotals & EXC_SXVD_SUBT_AVERAGE )   rSubtotals.push_back( GeneralFunction_AVERAGE );
    if( mnSubtotals & EXC_SXVD_SUBT_MAX )       rSubtotals.push_back( GeneralFunction_MAX );
    if( mnSubtotals & EXC_SXVD_SUBT_MIN )       rSubtotals.push_back( GeneralFunction_MIN );
    if( mnSubtotals & EXC_SXVD_SUBT_PROD )      rSubtotals.push_back( GeneralFunction_PRODUCT );
    if( mnSubtotals & EXC_SXVD_SUBT_COUNTNUM )  rSubtotals.push_back( GeneralFunction_COUNTNUMS );
    if( mnSubtotals & EXC_SXVD_SUBT_STDDEV )    rSubtotals.push_back( GeneralFunction_STDEV );
    if( mnSubtotals & EXC_SXVD_SUBT_STDDEVP )   rSubtotals.push_back( GeneralFunction_STDEVP );
    if( mnSubtotals & EXC_SXVD_SUBT_VAR )       rSubtotals.push_back( GeneralFunction_VAR );
    if( mnSubtotals & EXC_SXVD_SUBT_VARP )      rSubtotals.push_back( GeneralFunction_VARP );
}

void XclPTFieldInfo::SetSubtotals( const XclPTSubtotalVec& rSubtotals )
{
    mnSubtotals = EXC_SXVD_SUBT_NONE;
    using namespace ::com::sun::star::sheet;
    for( XclPTSubtotalVec::const_iterator aIt = rSubtotals.begin(), aEnd = rSubtotals.end(); aIt != aEnd; ++aIt )
    {
        switch( *aIt )
        {
            case GeneralFunction_AUTO:      mnSubtotals |= EXC_SXVD_SUBT_DEFAULT;   break;
            case GeneralFunction_SUM:       mnSubtotals |= EXC_SXVD_SUBT_SUM;       break;
            case GeneralFunction_COUNT:     mnSubtotals |= EXC_SXVD_SUBT_COUNT;     break;
            case GeneralFunction_AVERAGE:   mnSubtotals |= EXC_SXVD_SUBT_AVERAGE;   break;
            case GeneralFunction_MAX:       mnSubtotals |= EXC_SXVD_SUBT_MAX;       break;
            case GeneralFunction_MIN:       mnSubtotals |= EXC_SXVD_SUBT_MIN;       break;
            case GeneralFunction_PRODUCT:   mnSubtotals |= EXC_SXVD_SUBT_PROD;      break;
            case GeneralFunction_COUNTNUMS: mnSubtotals |= EXC_SXVD_SUBT_COUNTNUM;  break;
            case GeneralFunction_STDEV:     mnSubtotals |= EXC_SXVD_SUBT_STDDEV;    break;
            case GeneralFunction_STDEVP:    mnSubtotals |= EXC_SXVD_SUBT_STDDEVP;   break;
            case GeneralFunction_VAR:       mnSubtotals |= EXC_SXVD_SUBT_VAR;       break;
            case GeneralFunction_VARP:      mnSubtotals |= EXC_SXVD_SUBT_VARP;      break;
        }
    }

    mnSubtCount = 0;
    for( sal_uInt16 nMask = 0x8000; nMask; nMask >>= 1 )
        if( mnSubtotals & nMask )
            ++mnSubtCount;
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTFieldInfo& rInfo )
{
    // rInfo.mnCacheIdx is not part of the SXVD record
    return rStrm
        >> rInfo.mnAxes
        >> rInfo.mnSubtCount
        >> rInfo.mnSubtotals
        >> rInfo.mnItemCount
        >> rInfo.maVisName;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldInfo& rInfo )
{
    // rInfo.mnCacheIdx is not part of the SXVD record
    return rStrm
        << rInfo.mnAxes
        << rInfo.mnSubtCount
        << rInfo.mnSubtotals
        << rInfo.mnItemCount
        << rInfo.maVisName;
}

// Extended field settings ====================================================

XclPTFieldExtInfo::XclPTFieldExtInfo() :
    mnFlags( EXC_SXVDEX_DEFAULTFLAGS ),
    mnSortField( EXC_SXVDEX_SORT_OWN ),
    mnShowField( EXC_SXVDEX_SHOW_NONE ),
    mnNumFmt(0),
    mpFieldTotalName(NULL)
{
}

sal_Int32 XclPTFieldExtInfo::GetApiSortMode() const
{
    sal_Int32 nSortMode = ScDPSortMode::MANUAL;
    if( ::get_flag( mnFlags, EXC_SXVDEX_SORT ) )
        nSortMode = (mnSortField == EXC_SXVDEX_SORT_OWN) ? ScDPSortMode::NAME : ScDPSortMode::DATA;
    return nSortMode;
}

void XclPTFieldExtInfo::SetApiSortMode( sal_Int32 nSortMode )
{
    bool bSort = (nSortMode == ScDPSortMode::NAME) || (nSortMode == ScDPSortMode::DATA);
    ::set_flag( mnFlags, EXC_SXVDEX_SORT, bSort );
    if( nSortMode == ScDPSortMode::NAME )
        mnSortField = EXC_SXVDEX_SORT_OWN;  // otherwise sort field has to be set by caller
}

sal_Int32 XclPTFieldExtInfo::GetApiAutoShowMode() const
{
    return ::get_flagvalue( mnFlags, EXC_SXVDEX_AUTOSHOW_ASC,
        ScDPShowItemsMode::FROM_TOP, ScDPShowItemsMode::FROM_BOTTOM );
}

void XclPTFieldExtInfo::SetApiAutoShowMode( sal_Int32 nShowMode )
{
    ::set_flag( mnFlags, EXC_SXVDEX_AUTOSHOW_ASC, nShowMode == ScDPShowItemsMode::FROM_TOP );
}

sal_Int32 XclPTFieldExtInfo::GetApiAutoShowCount() const
{
    return ::extract_value< sal_Int32 >( mnFlags, 24, 8 );
}

void XclPTFieldExtInfo::SetApiAutoShowCount( sal_Int32 nShowCount )
{
    ::insert_value( mnFlags, limit_cast< sal_uInt8 >( nShowCount ), 24, 8 );
}

sal_Int32 XclPTFieldExtInfo::GetApiLayoutMode() const
{
    sal_Int32 nLayoutMode = ScDPLayoutMode::TABULAR_LAYOUT;
    if( ::get_flag( mnFlags, EXC_SXVDEX_LAYOUT_REPORT ) )
        nLayoutMode = ::get_flag( mnFlags, EXC_SXVDEX_LAYOUT_TOP ) ?
            ScDPLayoutMode::OUTLINE_SUBTOTALS_TOP : ScDPLayoutMode::OUTLINE_SUBTOTALS_BOTTOM;
    return nLayoutMode;
}

void XclPTFieldExtInfo::SetApiLayoutMode( sal_Int32 nLayoutMode )
{
    ::set_flag( mnFlags, EXC_SXVDEX_LAYOUT_REPORT, nLayoutMode != ScDPLayoutMode::TABULAR_LAYOUT );
    ::set_flag( mnFlags, EXC_SXVDEX_LAYOUT_TOP, nLayoutMode == ScDPLayoutMode::OUTLINE_SUBTOTALS_TOP );
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTFieldExtInfo& rInfo )
{
    sal_uInt8 nNameLen = 0;
    rStrm >> rInfo.mnFlags
          >> rInfo.mnSortField
          >> rInfo.mnShowField
          >> rInfo.mnNumFmt
          >> nNameLen;

    rStrm.Ignore(10);
    if (nNameLen != 0xFF)
        // Custom field total name is used.  Pick it up.
        rInfo.mpFieldTotalName.reset(new rtl::OUString(rStrm.ReadUniString(nNameLen, 0)));

    return rStrm;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldExtInfo& rInfo )
{
    rStrm   << rInfo.mnFlags
            << rInfo.mnSortField
            << rInfo.mnShowField
            << EXC_SXVDEX_FORMAT_NONE;

    if (rInfo.mpFieldTotalName.get() && rInfo.mpFieldTotalName->getLength() > 0)
    {
        rtl::OUString aFinalName = *rInfo.mpFieldTotalName;
        if (aFinalName.getLength() >= 254)
            aFinalName = aFinalName.copy(0, 254);
        sal_uInt8 nNameLen = static_cast<sal_uInt8>(aFinalName.getLength());
        rStrm << nNameLen;
        rStrm.WriteZeroBytes(10);
        rStrm << XclExpString(aFinalName, EXC_STR_NOHEADER);
    }
    else
    {
        rStrm << sal_uInt16(0xFFFF);
        rStrm.WriteZeroBytes(8);
    }
    return rStrm;
}

// Page field settings ========================================================

XclPTPageFieldInfo::XclPTPageFieldInfo() :
    mnField( 0 ),
    mnSelItem( EXC_SXPI_ALLITEMS ),
    mnObjId( 0xFFFF )
{
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTPageFieldInfo& rInfo )
{
    return rStrm
        >> rInfo.mnField
        >> rInfo.mnSelItem
        >> rInfo.mnObjId;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTPageFieldInfo& rInfo )
{
    return rStrm
        << rInfo.mnField
        << rInfo.mnSelItem
        << rInfo.mnObjId;
}

// Data field settings ========================================================

XclPTDataFieldInfo::XclPTDataFieldInfo() :
    mnField( 0 ),
    mnAggFunc( EXC_SXDI_FUNC_SUM ),
    mnRefType( EXC_SXDI_REF_NORMAL ),
    mnRefField( 0 ),
    mnRefItem( 0 ),
    mnNumFmt( 0 )
{
}

GeneralFunction XclPTDataFieldInfo::GetApiAggFunc() const
{
    using namespace ::com::sun::star::sheet;
    GeneralFunction eAggFunc;
    switch( mnAggFunc )
    {
        case EXC_SXDI_FUNC_SUM:         eAggFunc = GeneralFunction_SUM;         break;
        case EXC_SXDI_FUNC_COUNT:       eAggFunc = GeneralFunction_COUNT;       break;
        case EXC_SXDI_FUNC_AVERAGE:     eAggFunc = GeneralFunction_AVERAGE;     break;
        case EXC_SXDI_FUNC_MAX:         eAggFunc = GeneralFunction_MAX;         break;
        case EXC_SXDI_FUNC_MIN:         eAggFunc = GeneralFunction_MIN;         break;
        case EXC_SXDI_FUNC_PRODUCT:     eAggFunc = GeneralFunction_PRODUCT;     break;
        case EXC_SXDI_FUNC_COUNTNUM:    eAggFunc = GeneralFunction_COUNTNUMS;   break;
        case EXC_SXDI_FUNC_STDDEV:      eAggFunc = GeneralFunction_STDEV;       break;
        case EXC_SXDI_FUNC_STDDEVP:     eAggFunc = GeneralFunction_STDEVP;      break;
        case EXC_SXDI_FUNC_VAR:         eAggFunc = GeneralFunction_VAR;         break;
        case EXC_SXDI_FUNC_VARP:        eAggFunc = GeneralFunction_VARP;        break;
        default:                        eAggFunc = GeneralFunction_SUM;
    }
    return eAggFunc;
}

void XclPTDataFieldInfo::SetApiAggFunc( GeneralFunction eAggFunc )
{
    using namespace ::com::sun::star::sheet;
    switch( eAggFunc )
    {
        case GeneralFunction_SUM:       mnAggFunc = EXC_SXDI_FUNC_SUM;      break;
        case GeneralFunction_COUNT:     mnAggFunc = EXC_SXDI_FUNC_COUNT;    break;
        case GeneralFunction_AVERAGE:   mnAggFunc = EXC_SXDI_FUNC_AVERAGE;  break;
        case GeneralFunction_MAX:       mnAggFunc = EXC_SXDI_FUNC_MAX;      break;
        case GeneralFunction_MIN:       mnAggFunc = EXC_SXDI_FUNC_MIN;      break;
        case GeneralFunction_PRODUCT:   mnAggFunc = EXC_SXDI_FUNC_PRODUCT;  break;
        case GeneralFunction_COUNTNUMS: mnAggFunc = EXC_SXDI_FUNC_COUNTNUM; break;
        case GeneralFunction_STDEV:     mnAggFunc = EXC_SXDI_FUNC_STDDEV;   break;
        case GeneralFunction_STDEVP:    mnAggFunc = EXC_SXDI_FUNC_STDDEVP;  break;
        case GeneralFunction_VAR:       mnAggFunc = EXC_SXDI_FUNC_VAR;      break;
        case GeneralFunction_VARP:      mnAggFunc = EXC_SXDI_FUNC_VARP;     break;
        default:                        mnAggFunc = EXC_SXDI_FUNC_SUM;
    }
}

sal_Int32 XclPTDataFieldInfo::GetApiRefType() const
{
    namespace ScDPRefType = ::com::sun::star::sheet::DataPilotFieldReferenceType;
    sal_Int32 nRefType;
    switch( mnRefType )
    {
        case EXC_SXDI_REF_DIFF:         nRefType = ScDPRefType::ITEM_DIFFERENCE;            break;
        case EXC_SXDI_REF_PERC:         nRefType = ScDPRefType::ITEM_PERCENTAGE;            break;
        case EXC_SXDI_REF_PERC_DIFF:    nRefType = ScDPRefType::ITEM_PERCENTAGE_DIFFERENCE; break;
        case EXC_SXDI_REF_RUN_TOTAL:    nRefType = ScDPRefType::RUNNING_TOTAL;              break;
        case EXC_SXDI_REF_PERC_ROW:     nRefType = ScDPRefType::ROW_PERCENTAGE;             break;
        case EXC_SXDI_REF_PERC_COL:     nRefType = ScDPRefType::COLUMN_PERCENTAGE;          break;
        case EXC_SXDI_REF_PERC_TOTAL:   nRefType = ScDPRefType::TOTAL_PERCENTAGE;           break;
        case EXC_SXDI_REF_INDEX:        nRefType = ScDPRefType::INDEX;                      break;
        default:                        nRefType = ScDPRefType::NONE;
    }
    return nRefType;
}

void XclPTDataFieldInfo::SetApiRefType( sal_Int32 nRefType )
{
    namespace ScDPRefType = ::com::sun::star::sheet::DataPilotFieldReferenceType;
    switch( nRefType )
    {
        case ScDPRefType::ITEM_DIFFERENCE:              mnRefType = EXC_SXDI_REF_DIFF;      break;
        case ScDPRefType::ITEM_PERCENTAGE:              mnRefType = EXC_SXDI_REF_PERC;      break;
        case ScDPRefType::ITEM_PERCENTAGE_DIFFERENCE:   mnRefType = EXC_SXDI_REF_PERC_DIFF; break;
        case ScDPRefType::RUNNING_TOTAL:                mnRefType = EXC_SXDI_REF_RUN_TOTAL; break;
        case ScDPRefType::ROW_PERCENTAGE:               mnRefType = EXC_SXDI_REF_PERC_ROW;  break;
        case ScDPRefType::COLUMN_PERCENTAGE:            mnRefType = EXC_SXDI_REF_PERC_COL;  break;
        case ScDPRefType::TOTAL_PERCENTAGE:             mnRefType = EXC_SXDI_REF_PERC_TOTAL;break;
        case ScDPRefType::INDEX:                        mnRefType = EXC_SXDI_REF_INDEX;     break;
        default:                                        mnRefType = EXC_SXDI_REF_NORMAL;
    }
}

sal_Int32 XclPTDataFieldInfo::GetApiRefItemType() const
{
    sal_Int32 nRefItemType;
    switch( mnRefItem )
    {
        case EXC_SXDI_PREVITEM: nRefItemType = ScDPRefItemType::PREVIOUS;   break;
        case EXC_SXDI_NEXTITEM: nRefItemType = ScDPRefItemType::NEXT;       break;
        default:                nRefItemType = ScDPRefItemType::NAMED;
    }
    return nRefItemType;
}

void XclPTDataFieldInfo::SetApiRefItemType( sal_Int32 nRefItemType )
{
    switch( nRefItemType )
    {
        case ScDPRefItemType::PREVIOUS: mnRefItem = EXC_SXDI_PREVITEM;  break;
        case ScDPRefItemType::NEXT:     mnRefItem = EXC_SXDI_NEXTITEM;  break;
        // nothing for named item reference
    }
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTDataFieldInfo& rInfo )
{
    return rStrm
        >> rInfo.mnField
        >> rInfo.mnAggFunc
        >> rInfo.mnRefType
        >> rInfo.mnRefField
        >> rInfo.mnRefItem
        >> rInfo.mnNumFmt
        >> rInfo.maVisName;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTDataFieldInfo& rInfo )
{
    return rStrm
        << rInfo.mnField
        << rInfo.mnAggFunc
        << rInfo.mnRefType
        << rInfo.mnRefField
        << rInfo.mnRefItem
        << rInfo.mnNumFmt
        << rInfo.maVisName;
}

// Pivot table settings =======================================================

XclPTInfo::XclPTInfo() :
    mnFirstHeadRow( 0 ),
    mnCacheIdx( 0xFFFF ),
    mnDataAxis( EXC_SXVD_AXIS_NONE ),
    mnDataPos( EXC_SXVIEW_DATALAST ),
    mnFields( 0 ),
    mnRowFields( 0 ),
    mnColFields( 0 ),
    mnPageFields( 0 ),
    mnDataFields( 0 ),
    mnDataRows( 0 ),
    mnDataCols( 0 ),
    mnFlags( EXC_SXVIEW_DEFAULTFLAGS ),
    mnAutoFmtIdx( EXC_SXVIEW_AUTOFMT )
{
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTInfo& rInfo )
{
    sal_uInt16 nTabLen, nDataLen;

    rStrm   >> rInfo.maOutXclRange
            >> rInfo.mnFirstHeadRow
            >> rInfo.maDataXclPos
            >> rInfo.mnCacheIdx;
    rStrm.Ignore( 2 );
    rStrm   >> rInfo.mnDataAxis >> rInfo.mnDataPos
            >> rInfo.mnFields
            >> rInfo.mnRowFields >> rInfo.mnColFields
            >> rInfo.mnPageFields >> rInfo.mnDataFields
            >> rInfo.mnDataRows >> rInfo.mnDataCols
            >> rInfo.mnFlags
            >> rInfo.mnAutoFmtIdx
            >> nTabLen >> nDataLen;
    rInfo.maTableName = rStrm.ReadUniString( nTabLen );
    rInfo.maDataName = rStrm.ReadUniString( nDataLen );
    return rStrm;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTInfo& rInfo )
{
    XclExpString aXclTableName( rInfo.maTableName );
    XclExpString aXclDataName( rInfo.maDataName );

    rStrm   << rInfo.maOutXclRange
            << rInfo.mnFirstHeadRow
            << rInfo.maDataXclPos
            << rInfo.mnCacheIdx
            << sal_uInt16( 0 )
            << rInfo.mnDataAxis << rInfo.mnDataPos
            << rInfo.mnFields
            << rInfo.mnRowFields << rInfo.mnColFields
            << rInfo.mnPageFields << rInfo.mnDataFields
            << rInfo.mnDataRows << rInfo.mnDataCols
            << rInfo.mnFlags
            << rInfo.mnAutoFmtIdx
            << aXclTableName.Len() << aXclDataName.Len();
    aXclTableName.WriteFlagField( rStrm );
    aXclTableName.WriteBuffer( rStrm );
    aXclDataName.WriteFlagField( rStrm );
    aXclDataName.WriteBuffer( rStrm );
    return rStrm;
}

// Extended pivot table settings ==============================================

XclPTExtInfo::XclPTExtInfo() :
    mnSxformulaRecs( 0 ),
    mnSxselectRecs( 0 ),
    mnPagePerRow( 0 ),
    mnPagePerCol( 0 ),
    mnFlags( EXC_SXEX_DEFAULTFLAGS )
{
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTExtInfo& rInfo )
{
    rStrm >> rInfo.mnSxformulaRecs;
    rStrm.Ignore( 6 );
    return rStrm
        >> rInfo.mnSxselectRecs
        >> rInfo.mnPagePerRow
        >> rInfo.mnPagePerCol
        >> rInfo.mnFlags;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTExtInfo& rInfo )
{
    return rStrm
        << rInfo.mnSxformulaRecs
        << EXC_PT_NOSTRING              // length of alt. error text
        << EXC_PT_NOSTRING              // length of alt. empty text
        << EXC_PT_NOSTRING              // length of tag
        << rInfo.mnSxselectRecs
        << rInfo.mnPagePerRow
        << rInfo.mnPagePerCol
        << rInfo.mnFlags
        << EXC_PT_NOSTRING              // length of page field style name
        << EXC_PT_NOSTRING              // length of table style name
        << EXC_PT_NOSTRING;             // length of vacate style name
}

// ============================================================================

// Pivot table autoformat settings ============================================

/**
classic     : 10 08 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00
default     : 10 08 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00
report01    : 10 08 02 00 00 00 00 00 20 00 00 00 00 10 00 00 00
report02    : 10 08 02 00 00 00 00 00 20 00 00 00 01 10 00 00 00
report03    : 10 08 02 00 00 00 00 00 20 00 00 00 02 10 00 00 00
report04    : 10 08 02 00 00 00 00 00 20 00 00 00 03 10 00 00 00
report05    : 10 08 02 00 00 00 00 00 20 00 00 00 04 10 00 00 00
report06    : 10 08 02 00 00 00 00 00 20 00 00 00 05 10 00 00 00
report07    : 10 08 02 00 00 00 00 00 20 00 00 00 06 10 00 00 00
report08    : 10 08 02 00 00 00 00 00 20 00 00 00 07 10 00 00 00
report09    : 10 08 02 00 00 00 00 00 20 00 00 00 08 10 00 00 00
report10    : 10 08 02 00 00 00 00 00 20 00 00 00 09 10 00 00 00
table01     : 10 08 00 00 00 00 00 00 20 00 00 00 0a 10 00 00 00
table02     : 10 08 00 00 00 00 00 00 20 00 00 00 0b 10 00 00 00
table03     : 10 08 00 00 00 00 00 00 20 00 00 00 0c 10 00 00 00
table04     : 10 08 00 00 00 00 00 00 20 00 00 00 0d 10 00 00 00
table05     : 10 08 00 00 00 00 00 00 20 00 00 00 0e 10 00 00 00
table06     : 10 08 00 00 00 00 00 00 20 00 00 00 0f 10 00 00 00
table07     : 10 08 00 00 00 00 00 00 20 00 00 00 10 10 00 00 00
table08     : 10 08 00 00 00 00 00 00 20 00 00 00 11 10 00 00 00
table09     : 10 08 00 00 00 00 00 00 20 00 00 00 12 10 00 00 00
table10     : 10 08 00 00 00 00 00 00 20 00 00 00 13 10 00 00 00
none        : 10 08 00 00 00 00 00 00 20 00 00 00 15 10 00 00 00
**/

XclPTViewEx9Info::XclPTViewEx9Info() :
    mbReport( 0 ),
    mnAutoFormat( 0 ),
    mnGridLayout( 0x10 )
{
}

void XclPTViewEx9Info::Init( const ScDPObject& rDPObj )
{
    if( rDPObj.GetHeaderLayout() )
    {
        mbReport     = 0;
        mnAutoFormat = 1;
        mnGridLayout = 0;
    }
    else
    {
        // Report1 for now
        // TODO : sync with autoformat indicies
        mbReport     = 2;
        mnAutoFormat = 1;
        mnGridLayout = 0x10;
    }

    const ScDPSaveData* pData = rDPObj.GetSaveData();
    if (pData)
    {
        const rtl::OUString* pGrandTotal = pData->GetGrandTotalName();
        if (pGrandTotal)
            maGrandTotalName = *pGrandTotal;
    }
}

XclImpStream& operator>>( XclImpStream& rStrm, XclPTViewEx9Info& rInfo )
{
    rStrm.Ignore( 2 );
    rStrm >> rInfo.mbReport;            /// 2 for report* fmts ?
    rStrm.Ignore( 6 );
    rStrm >> rInfo.mnAutoFormat >> rInfo.mnGridLayout;
    rInfo.maGrandTotalName = rStrm.ReadUniString();
    return rStrm;
}

XclExpStream& operator<<( XclExpStream& rStrm, const XclPTViewEx9Info& rInfo )
{
    return rStrm 
        << EXC_PT_AUTOFMT_HEADER
        << rInfo.mbReport
        << EXC_PT_AUTOFMT_ZERO
        << EXC_PT_AUTOFMT_FLAGS
        << rInfo.mnAutoFormat
        << rInfo.mnGridLayout
        << XclExpString(rInfo.maGrandTotalName, EXC_STR_DEFAULT, EXC_PT_MAXSTRLEN);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
