/**************************************************************
 * 
 * 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 <sfx2/opengrf.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdomedia.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdview.hxx>
#include <svtools/filter.hxx>
#include <svl/stritem.hxx>
#include <vcl/msgbox.hxx>
#include <tools/urlobj.hxx>
#include <avmedia/mediawindow.hxx>
#include <vcl/svapp.hxx>

#include "fuinsert.hxx"
#include "tabvwsh.hxx"
#include "drwlayer.hxx"
#include "drawview.hxx"
#include "document.hxx"
#include "scresid.hxx"
#include "progress.hxx"
#include "sc.hrc"
#include "globstr.hrc"



////========================================================================
////	class ImportProgress
////
////  Bemerkung:
////	Diese Klasse stellt lediglich den Handler fuer den ImportProgress des
////	Grafikfilters bereit.
////========================================================================
//
//class ImportProgress
//{
//public:
//		ImportProgress( GraphicFilter& rFilter );
//		~ImportProgress();
//
//	DECL_LINK( Update, GraphicFilter* );
//
//private:
//	ScProgress aProgress;
//};
//
////------------------------------------------------------------------------
//
//ImportProgress::ImportProgress( GraphicFilter& rFilter )
//	: aProgress( NULL, // SfxViewFrame*, NULL == alle Docs locken
//				 String( ScResId(STR_INSERTGRAPHIC) ),
//				 100 )
//{
//	rFilter.SetUpdatePercentHdl( LINK( this, ImportProgress, Update) );
//}
//
////------------------------------------------------------------------------
//
//__EXPORT ImportProgress::~ImportProgress()
//{
//	aProgress.SetState( 100 );
//}
//
////------------------------------------------------------------------------
//
//IMPL_LINK( ImportProgress, Update, GraphicFilter*, pGraphicFilter )
//{
//	aProgress.SetState( pGraphicFilter->GetPercent() );
//	return 0;
//}


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

void SC_DLLPUBLIC ScLimitSizeOnDrawPage( Size& rSize, Point& rPos, const Size& rPage )
{
	if ( !rPage.Width() || !rPage.Height() )
		return;

	Size aPageSize = rPage;
	sal_Bool bNegative = aPageSize.Width() < 0;
	if ( bNegative )
	{
		//	make everything positive temporarily
		aPageSize.Width() = -aPageSize.Width();
		rPos.X() = -rPos.X() - rSize.Width();
	}

	if ( rSize.Width() > aPageSize.Width() || rSize.Height() > aPageSize.Height() )
	{
		double fX = aPageSize.Width()  / (double) rSize.Width();
		double fY = aPageSize.Height() / (double) rSize.Height();

		if ( fX < fY )
		{
			rSize.Width()  = aPageSize.Width();
			rSize.Height() = (long) ( rSize.Height() * fX );
		}
		else
		{
			rSize.Height() = aPageSize.Height();
			rSize.Width()  = (long) ( rSize.Width() * fY );
		}

		if (!rSize.Width())
			rSize.Width() = 1;
		if (!rSize.Height())
			rSize.Height() = 1;
	}

	if ( rPos.X() + rSize.Width() > aPageSize.Width() )
		rPos.X() = aPageSize.Width() - rSize.Width();
	if ( rPos.Y() + rSize.Height() > aPageSize.Height() )
		rPos.Y() = aPageSize.Height() - rSize.Height();

	if ( bNegative )
		rPos.X() = -rPos.X() - rSize.Width();		// back to real position
}

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

void lcl_InsertGraphic( const Graphic& rGraphic,
						const String& rFileName, const String& rFilterName, sal_Bool bAsLink, sal_Bool bApi,
						ScTabViewShell*	pViewSh, Window* pWindow, SdrView* pView )
{
	ScDrawView* pDrawView = pViewSh->GetScDrawView();

    // #123922# check if an existing object is selected; if yes, evtl. replace
    // the graphic for a SdrGraphObj (including link state updates) or adapt the fill 
    // style for other objects
    if(pDrawView && 1 == pDrawView->GetMarkedObjectCount())
    {
        SdrObject* pPickObj = pDrawView->GetMarkedObjectByIndex(0);

        if(pPickObj)
        {
            //sal_Int8 nAction(DND_ACTION_MOVE);
            //Point aPos;
            const String aBeginUndo(ScGlobal::GetRscString(STR_UNDO_DRAGDROP));
            const String aEmpty;

            SdrObject* pResult = pDrawView->ApplyGraphicToObject(
                *pPickObj, 
                rGraphic, 
                aBeginUndo, 
                bAsLink ? rFileName : aEmpty, 
                bAsLink ? rFilterName : aEmpty);

            if(pResult)
            {
                // we are done; mark the modified/new object
                pDrawView->MarkObj(pResult, pDrawView->GetSdrPageView());
                return;
            }
        }
    }

	//	#74778# set the size so the graphic has its original pixel size
	//	at 100% view scale (as in SetMarkedOriginalSize),
	//	instead of respecting the current view scale
    MapMode aSourceMap = rGraphic.GetPrefMapMode();
	MapMode aDestMap( MAP_100TH_MM );
	if ( aSourceMap.GetMapUnit() == MAP_PIXEL && pDrawView )
	{
		Fraction aScaleX, aScaleY;
		pDrawView->CalcNormScale( aScaleX, aScaleY );
		aDestMap.SetScaleX(aScaleX);
		aDestMap.SetScaleY(aScaleY);
	}
	Size aLogicSize = pWindow->LogicToLogic(
							rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );

	//	Limit size

	SdrPageView* pPV  = pView->GetSdrPageView();
	SdrPage* pPage = pPV->GetPage();
	Point aInsertPos = pViewSh->GetInsertPos();

	ScViewData* pData = pViewSh->GetViewData();
	if ( pData->GetDocument()->IsNegativePage( pData->GetTabNo() ) )
		aInsertPos.X() -= aLogicSize.Width();		// move position to left edge

	ScLimitSizeOnDrawPage( aLogicSize, aInsertPos, pPage->GetSize() );

	Rectangle aRect ( aInsertPos, aLogicSize );

	SdrGrafObj* pObj = new SdrGrafObj( rGraphic, aRect );

    // #118522# calling SetGraphicLink here doesn't work

	//	#49961# Path is no longer used as name for the graphics object

	ScDrawLayer* pLayer = (ScDrawLayer*) pView->GetModel();
	String aName = pLayer->GetNewGraphicName();					// "Grafik x"
	pObj->SetName(aName);

	//	don't select if from (dispatch) API, to allow subsequent cell operations
	sal_uLong nInsOptions = bApi ? SDRINSERT_DONTMARK : 0;
	pView->InsertObjectAtView( pObj, *pPV, nInsOptions );

    // #118522# SetGraphicLink has to be used after inserting the object,
    // otherwise an empty graphic is swapped in and the contact stuff crashes.
    // See #i37444#.
	if ( bAsLink )
		pObj->SetGraphicLink( rFileName, rFilterName );
}

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

void lcl_InsertMedia( const ::rtl::OUString& rMediaURL, bool bApi,
					  ScTabViewShell* pViewSh, Window* pWindow, SdrView* pView,
					  const Size& rPrefSize )
{
	SdrPageView* 	pPV  = pView->GetSdrPageView();
	SdrPage* 		pPage = pPV->GetPage();
	ScViewData* 	pData = pViewSh->GetViewData();
	Point 			aInsertPos( pViewSh->GetInsertPos() );
	Size 			aSize;
	
	if( rPrefSize.Width() && rPrefSize.Height() )
	{
		if( pWindow )
			aSize = pWindow->PixelToLogic( rPrefSize, MAP_100TH_MM );
		else
			aSize = Application::GetDefaultDevice()->PixelToLogic( rPrefSize, MAP_100TH_MM );
	}
	else
		aSize = Size( 5000, 5000 );

	ScLimitSizeOnDrawPage( aSize, aInsertPos, pPage->GetSize() );
	
	if( pData->GetDocument()->IsNegativePage( pData->GetTabNo() ) )
		aInsertPos.X() -= aSize.Width();

	SdrMediaObj* pObj = new SdrMediaObj( Rectangle( aInsertPos, aSize ) );
	
	pObj->setURL( rMediaURL ); 
	pView->InsertObjectAtView( pObj, *pPV, bApi ? SDRINSERT_DONTMARK : 0 );
}

/*************************************************************************
|*
|* FuInsertGraphic::Konstruktor
|*
\************************************************************************/

#ifdef _MSC_VER
#pragma optimize("",off)
#endif

FuInsertGraphic::FuInsertGraphic( ScTabViewShell*	pViewSh,
								  Window*			pWin,
                                  ScDrawView*       pViewP,
								  SdrModel*			pDoc,
								  SfxRequest&		rReq )
       : FuPoor(pViewSh, pWin, pViewP, pDoc, rReq)
{
	const SfxItemSet* pReqArgs = rReq.GetArgs();
	const SfxPoolItem* pItem;
	if ( pReqArgs &&
		 pReqArgs->GetItemState( SID_INSERT_GRAPHIC, sal_True, &pItem ) == SFX_ITEM_SET )
	{
		String aFileName = ((const SfxStringItem*)pItem)->GetValue();

		String aFilterName;
		if ( pReqArgs->GetItemState( FN_PARAM_FILTER, sal_True, &pItem ) == SFX_ITEM_SET )
			aFilterName = ((const SfxStringItem*)pItem)->GetValue();

		sal_Bool bAsLink = sal_False;
		if ( pReqArgs->GetItemState( FN_PARAM_1, sal_True, &pItem ) == SFX_ITEM_SET )
			bAsLink = ((const SfxBoolItem*)pItem)->GetValue();

		Graphic aGraphic;
        int nError = GraphicFilter::LoadGraphic( aFileName, aFilterName, aGraphic, GraphicFilter::GetGraphicFilter() );
        if ( nError == GRFILTER_OK )
        {
			lcl_InsertGraphic( aGraphic, aFileName, aFilterName, bAsLink, sal_True, pViewSh, pWindow, pView );
        }
	}
	else
	{
		SvxOpenGraphicDialog aDlg(ScResId(STR_INSERTGRAPHIC));

		if( aDlg.Execute() == GRFILTER_OK )
		{
			Graphic aGraphic;
            int nError = aDlg.GetGraphic(aGraphic);
			if( nError == GRFILTER_OK )
			{
				String aFileName = aDlg.GetPath();
				String aFilterName = aDlg.GetCurrentFilter();
				sal_Bool bAsLink = aDlg.IsAsLink();

				lcl_InsertGraphic( aGraphic, aFileName, aFilterName, bAsLink, sal_False, pViewSh, pWindow, pView );

				//	append items for recording
				rReq.AppendItem( SfxStringItem( SID_INSERT_GRAPHIC, aFileName ) );
				rReq.AppendItem( SfxStringItem( FN_PARAM_FILTER, aFilterName ) );
				rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bAsLink ) );
				rReq.Done();
			}
			else
			{
				//	error is handled in SvxOpenGraphicDialog::GetGraphic

#if 0
				sal_uInt16 nRes = 0;
				switch ( nError )
				{
					case GRFILTER_OPENERROR:	nRes = SCSTR_GRFILTER_OPENERROR;	break;
					case GRFILTER_IOERROR:		nRes = SCSTR_GRFILTER_IOERROR;		break;
					case GRFILTER_FORMATERROR:	nRes = SCSTR_GRFILTER_FORMATERROR;	break;
					case GRFILTER_VERSIONERROR:	nRes = SCSTR_GRFILTER_VERSIONERROR;	break;
					case GRFILTER_FILTERERROR:	nRes = SCSTR_GRFILTER_FILTERERROR;	break;
					case GRFILTER_TOOBIG:		nRes = SCSTR_GRFILTER_TOOBIG;		break;
				}
				if ( nRes )
				{
					InfoBox aInfoBox( pWindow, String(ScResId(nRes)) );
					aInfoBox.Execute();
				}
				else
				{
					sal_uLong nStreamError = GetGrfFilter()->GetLastError().nStreamError;
					if( ERRCODE_NONE != nStreamError )
						ErrorHandler::HandleError( nStreamError );
				}
#endif
			}
		}
	}
}

/*************************************************************************
|*
|* FuInsertGraphic::Destruktor
|*
\************************************************************************/

FuInsertGraphic::~FuInsertGraphic()
{
}

/*************************************************************************
|*
|* FuInsertGraphic::Function aktivieren
|*
\************************************************************************/

void FuInsertGraphic::Activate()
{
	FuPoor::Activate();
}

/*************************************************************************
|*
|* FuInsertGraphic::Function deaktivieren
|*
\************************************************************************/

void FuInsertGraphic::Deactivate()
{
	FuPoor::Deactivate();
}

/*************************************************************************
|*
|* FuInsertMedia::Konstruktor
|*
\************************************************************************/

FuInsertMedia::FuInsertMedia( ScTabViewShell*	pViewSh,
							  Window*			pWin,
                              ScDrawView*       pViewP,
							  SdrModel*			pDoc,
							  SfxRequest&		rReq ) :
    FuPoor(pViewSh, pWin, pViewP, pDoc, rReq)
{
	::rtl::OUString 	aURL;
	const SfxItemSet*	pReqArgs = rReq.GetArgs();
	bool				bAPI = false;

	if( pReqArgs )
	{
		const SfxStringItem* pStringItem = PTR_CAST( SfxStringItem, &pReqArgs->Get( rReq.GetSlot() ) );
		
		if( pStringItem )
		{
			aURL = pStringItem->GetValue();
			bAPI = aURL.getLength();
		}
	}

	if( bAPI || ::avmedia::MediaWindow::executeMediaURLDialog( pWindow, aURL ) )
	{
		Size aPrefSize;

		if( pWin )
			pWin->EnterWait();
			
		if( !::avmedia::MediaWindow::isMediaURL( aURL, true, &aPrefSize ) )
		{
			if( pWin )
				pWin->LeaveWait();
			
			if( !bAPI )
				::avmedia::MediaWindow::executeFormatErrorBox( pWindow );
		}
		else
		{
			lcl_InsertMedia( aURL, bAPI, pViewSh, pWindow, pView, aPrefSize );
		
			if( pWin )
				pWin->LeaveWait();
		}
	}
}

/*************************************************************************
|*
|* FuInsertMedia::Destruktor
|*
\************************************************************************/

FuInsertMedia::~FuInsertMedia()
{
}

/*************************************************************************
|*
|* FuInsertMedia::Function aktivieren
|*
\************************************************************************/

void FuInsertMedia::Activate()
{
	FuPoor::Activate();
}

/*************************************************************************
|*
|* FuInsertMedia::Function deaktivieren
|*
\************************************************************************/

void FuInsertMedia::Deactivate()
{
	FuPoor::Deactivate();
}