/*************************************************************************
 *
 * 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 ---------------------------------------------------------------

#include <tools/multisel.hxx>

#include "pfuncache.hxx"
#include "printfun.hxx"
#include "docsh.hxx"
#include "markdata.hxx"
#include "prevloc.hxx"

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

ScPrintFuncCache::ScPrintFuncCache( ScDocShell* pD, const ScMarkData& rMark,
									const ScPrintSelectionStatus& rStatus ) :
	aSelection( rStatus ),
	pDocSh( pD ),
	nTotalPages( 0 ),
	bLocInitialized( false )
{
	//	page count uses the stored cell widths for the printer anyway,
	//	so ScPrintFunc with the document's printer can be used to count

	SfxPrinter* pPrinter = pDocSh->GetPrinter();

	ScRange aRange;
	const ScRange* pSelRange = NULL;
	if ( rMark.IsMarked() )
	{
		rMark.GetMarkArea( aRange );
		pSelRange = &aRange;
	}

	ScDocument* pDoc = pDocSh->GetDocument();
	SCTAB nTabCount = pDoc->GetTableCount();

    // avoid repeated progress bars if row heights for all sheets are needed
    if ( nTabCount > 1 && rMark.GetSelectCount() == nTabCount )
        pDocSh->UpdatePendingRowHeights( nTabCount-1, true );

	SCTAB nTab;
	for ( nTab=0; nTab<nTabCount; nTab++ )
	{
		long nAttrPage = nTab > 0 ? nFirstAttr[nTab-1] : 1;

		long nThisTab = 0;
		if ( rMark.GetTableSelect( nTab ) )
		{
			ScPrintFunc aFunc( pDocSh, pPrinter, nTab, nAttrPage, 0, pSelRange, &aSelection.GetOptions() );
			nThisTab = aFunc.GetTotalPages();
			nFirstAttr[nTab] = aFunc.GetFirstPageNo();			// from page style or previous sheet
		}
		else
			nFirstAttr[nTab] = nAttrPage;

		nPages[nTab] = nThisTab;
		nTotalPages += nThisTab;
	}
}

ScPrintFuncCache::~ScPrintFuncCache()
{
}

void ScPrintFuncCache::InitLocations( const ScMarkData& rMark, OutputDevice* pDev )
{
    if ( bLocInitialized )
        return;                 // initialize only once

    ScRange aRange;
    const ScRange* pSelRange = NULL;
    if ( rMark.IsMarked() )
    {
        rMark.GetMarkArea( aRange );
        pSelRange = &aRange;
    }

    long nRenderer = 0;     // 0-based physical page number across sheets
    long nTabStart = 0;

    ScDocument* pDoc = pDocSh->GetDocument();
    SCTAB nTabCount = pDoc->GetTableCount();
    for ( SCTAB nTab=0; nTab<nTabCount; nTab++ )
    {
        if ( rMark.GetTableSelect( nTab ) )
        {
            ScPrintFunc aFunc( pDev, pDocSh, nTab, nFirstAttr[nTab], nTotalPages, pSelRange, &aSelection.GetOptions() );
            aFunc.SetRenderFlag( sal_True );

            long nDisplayStart = GetDisplayStart( nTab );

            for ( long nPage=0; nPage<nPages[nTab]; nPage++ )
            {
                Range aPageRange( nRenderer+1, nRenderer+1 );
                MultiSelection aPage( aPageRange );
                aPage.SetTotalRange( Range(0,RANGE_MAX) );
                aPage.Select( aPageRange );

                ScPreviewLocationData aLocData( pDoc, pDev );
                aFunc.DoPrint( aPage, nTabStart, nDisplayStart, sal_False, &aLocData );

                ScRange aCellRange;
                Rectangle aPixRect;
                if ( aLocData.GetMainCellRange( aCellRange, aPixRect ) )
                    aLocations.push_back( ScPrintPageLocation( nRenderer, aCellRange, aPixRect ) );

                ++nRenderer;
            }

            nTabStart += nPages[nTab];
        }
    }

    bLocInitialized = true;
}

bool ScPrintFuncCache::FindLocation( const ScAddress& rCell, ScPrintPageLocation& rLocation ) const
{
    for ( std::vector<ScPrintPageLocation>::const_iterator aIter(aLocations.begin());
          aIter != aLocations.end(); aIter++ )
    {
        if ( aIter->aCellRange.In( rCell ) )
        {
            rLocation = *aIter;
            return true;
        }
    }
    return false;   // not found    
}

sal_Bool ScPrintFuncCache::IsSameSelection( const ScPrintSelectionStatus& rStatus ) const
{
	return aSelection == rStatus;
}

SCTAB ScPrintFuncCache::GetTabForPage( long nPage ) const
{
	ScDocument* pDoc = pDocSh->GetDocument();
	SCTAB nTabCount = pDoc->GetTableCount();
	SCTAB nTab = 0;
	while ( nTab < nTabCount && nPage >= nPages[nTab] )
		nPage -= nPages[nTab++];
	return nTab;
}

long ScPrintFuncCache::GetTabStart( SCTAB nTab ) const
{
	long nRet = 0;
	for ( SCTAB i=0; i<nTab; i++ )
		nRet += nPages[i];
	return nRet;
}

long ScPrintFuncCache::GetDisplayStart( SCTAB nTab ) const
{
	//!	merge with lcl_GetDisplayStart in preview?

	long nDisplayStart = 0;
	ScDocument* pDoc = pDocSh->GetDocument();
	for (SCTAB i=0; i<nTab; i++)
	{
		if ( pDoc->NeedPageResetAfterTab(i) )
			nDisplayStart = 0;
		else
			nDisplayStart += nPages[i];
	}
	return nDisplayStart;
}