/**************************************************************
 *
 * 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 <svl/itemset.hxx>
#include <vcl/virdev.hxx>

#include "undostyl.hxx"
#include "docsh.hxx"
#include "docpool.hxx"
#include "stlpool.hxx"
#include "printfun.hxx"
#include "scmod.hxx"
#include "inputhdl.hxx"
#include "globstr.hrc"

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

TYPEINIT1(ScUndoModifyStyle, ScSimpleUndo);
TYPEINIT1(ScUndoApplyPageStyle, ScSimpleUndo);

// -----------------------------------------------------------------------
//
//		modify style (cell or page style)
//

ScStyleSaveData::ScStyleSaveData() :
	pItems( NULL )
{
}

ScStyleSaveData::ScStyleSaveData( const ScStyleSaveData& rOther ) :
	aName( rOther.aName ),
	aParent( rOther.aParent )
{
	if (rOther.pItems)
		pItems = new SfxItemSet( *rOther.pItems );
	else
		pItems = NULL;
}

ScStyleSaveData::~ScStyleSaveData()
{
	delete pItems;
}

ScStyleSaveData& ScStyleSaveData::operator=( const ScStyleSaveData& rOther )
{
	aName   = rOther.aName;
	aParent = rOther.aParent;

	delete pItems;
	if (rOther.pItems)
		pItems = new SfxItemSet( *rOther.pItems );
	else
		pItems = NULL;

	return *this;
}

void ScStyleSaveData::InitFromStyle( const SfxStyleSheetBase* pSource )
{
	if ( pSource )
	{
		aName   = pSource->GetName();
		aParent = pSource->GetParent();
		delete pItems;
		pItems = new SfxItemSet( ((SfxStyleSheetBase*)pSource)->GetItemSet() );
	}
	else
		*this = ScStyleSaveData();		// empty
}

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

ScUndoModifyStyle::ScUndoModifyStyle( ScDocShell* pDocSh, SfxStyleFamily eFam,
					const ScStyleSaveData& rOld, const ScStyleSaveData& rNew ) :
	ScSimpleUndo( pDocSh ),
	eFamily( eFam ),
	aOldData( rOld ),
	aNewData( rNew )
{
}

ScUndoModifyStyle::~ScUndoModifyStyle()
{
}

String ScUndoModifyStyle::GetComment() const
{
	sal_uInt16 nId = (eFamily == SFX_STYLE_FAMILY_PARA) ?
								STR_UNDO_EDITCELLSTYLE :
								STR_UNDO_EDITPAGESTYLE;
	return ScGlobal::GetRscString( nId );
}

void lcl_DocStyleChanged( ScDocument* pDoc, SfxStyleSheetBase* pStyle, sal_Bool bRemoved )
{
	//!	move to document or docshell

	VirtualDevice aVDev;
	Point aLogic = aVDev.LogicToPixel( Point(1000,1000), MAP_TWIP );
	double nPPTX = aLogic.X() / 1000.0;
	double nPPTY = aLogic.Y() / 1000.0;
	Fraction aZoom(1,1);
	pDoc->StyleSheetChanged( pStyle, bRemoved, &aVDev, nPPTX, nPPTY, aZoom, aZoom );

	ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
	if (pHdl)
		pHdl->ForgetLastPattern();
}

// static
void ScUndoModifyStyle::DoChange( ScDocShell* pDocSh, const String& rName,
									SfxStyleFamily eStyleFamily, const ScStyleSaveData& rData )
{
	ScDocument* pDoc = pDocSh->GetDocument();
	ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
	String aNewName = rData.GetName();
	sal_Bool bDelete = ( aNewName.Len() == 0 );			// no new name -> delete style
	sal_Bool bNew = ( rName.Len() == 0 && !bDelete );	// creating new style

	SfxStyleSheetBase* pStyle = NULL;
	if ( rName.Len() )
	{
		// find old style to modify
		pStyle = pStlPool->Find( rName, eStyleFamily );
		DBG_ASSERT( pStyle, "style not found" );

		if ( pStyle && !bDelete )
		{
			// set new name
			pStyle->SetName( aNewName );
		}
	}
	else if ( !bDelete )
	{
		// create style (with new name)
		pStyle = &pStlPool->Make( aNewName, eStyleFamily, SFXSTYLEBIT_USERDEF );

        if ( eStyleFamily == SFX_STYLE_FAMILY_PARA )
            pDoc->GetPool()->CellStyleCreated( aNewName );
	}

	if ( pStyle )
	{
		if ( bDelete )
		{
			if ( eStyleFamily == SFX_STYLE_FAMILY_PARA )
				lcl_DocStyleChanged( pDoc, pStyle, sal_True );		// TRUE: remove usage of style
			else
				pDoc->RemovePageStyleInUse( rName );

			// delete style
			pStlPool->Remove( pStyle );
		}
		else
		{
			// modify style

			String aNewParent = rData.GetParent();
			if ( aNewParent != pStyle->GetParent() )
				pStyle->SetParent( aNewParent );

			SfxItemSet& rStyleSet = pStyle->GetItemSet();
			const SfxItemSet* pNewSet = rData.GetItems();
			DBG_ASSERT( pNewSet, "no ItemSet for style" );
			if (pNewSet)
				rStyleSet.Set( *pNewSet, sal_False );

			if ( eStyleFamily == SFX_STYLE_FAMILY_PARA )
			{
				lcl_DocStyleChanged( pDoc, pStyle, sal_False );		// cell styles: row heights
			}
			else
			{
				// page styles

				if ( bNew && aNewName != rName )
					pDoc->RenamePageStyleInUse( rName, aNewName );

				if (pNewSet)
					pDoc->ModifyStyleSheet( *pStyle, *pNewSet );

				pDocSh->PageStyleModified( aNewName, sal_True );
			}
		}
	}

	pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );

	//!	undo/redo document modifications for deleted styles
	//!	undo/redo modifications of number formatter
}

void ScUndoModifyStyle::Undo()
{
	BeginUndo();
	DoChange( pDocShell, aNewData.GetName(), eFamily, aOldData );
	EndUndo();
}

void ScUndoModifyStyle::Redo()
{
	BeginRedo();
	DoChange( pDocShell, aOldData.GetName(), eFamily, aNewData );
	EndRedo();
}

void ScUndoModifyStyle::Repeat(SfxRepeatTarget& /* rTarget */)
{
}

sal_Bool ScUndoModifyStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
{
	return sal_False;		// no repeat possible
}

// -----------------------------------------------------------------------
//
//		apply page style
//
ScUndoApplyPageStyle::ApplyStyleEntry::ApplyStyleEntry( SCTAB nTab, const String& rOldStyle ) :
    mnTab( nTab ),
    maOldStyle( rOldStyle )
{
}

ScUndoApplyPageStyle::ScUndoApplyPageStyle( ScDocShell* pDocSh, const String& rNewStyle ) :
    ScSimpleUndo( pDocSh ),
    maNewStyle( rNewStyle )
{
}

ScUndoApplyPageStyle::~ScUndoApplyPageStyle()
{
}

void ScUndoApplyPageStyle::AddSheetAction( SCTAB nTab, const String& rOldStyle )
{
    maEntries.push_back( ApplyStyleEntry( nTab, rOldStyle ) );
}

String ScUndoApplyPageStyle::GetComment() const
{
	return ScGlobal::GetRscString( STR_UNDO_APPLYPAGESTYLE );
}

void ScUndoApplyPageStyle::Undo()
{
	BeginUndo();
    for( ApplyStyleVec::const_iterator aIt = maEntries.begin(), aEnd = maEntries.end(); aIt != aEnd; ++aIt )
    {
        pDocShell->GetDocument()->SetPageStyle( aIt->mnTab, aIt->maOldStyle );
        ScPrintFunc( pDocShell, pDocShell->GetPrinter(), aIt->mnTab ).UpdatePages();
    }
	EndUndo();
}

void ScUndoApplyPageStyle::Redo()
{
	BeginRedo();
    for( ApplyStyleVec::const_iterator aIt = maEntries.begin(), aEnd = maEntries.end(); aIt != aEnd; ++aIt )
    {
        pDocShell->GetDocument()->SetPageStyle( aIt->mnTab, maNewStyle );
        ScPrintFunc( pDocShell, pDocShell->GetPrinter(), aIt->mnTab ).UpdatePages();
    }
	EndRedo();
}

void ScUndoApplyPageStyle::Repeat(SfxRepeatTarget& /* rTarget */)
{
	//!	set same page style to current tab
}

sal_Bool ScUndoApplyPageStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
{
	return sal_False;
}
