/**************************************************************
 * 
 * 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_framework.hxx"

#include <dispatch/startmoduledispatcher.hxx>

//_______________________________________________
// my own includes

#include <pattern/frame.hxx>
#include <threadhelp/readguard.hxx>
#include <threadhelp/writeguard.hxx>
#include <framework/framelistanalyzer.hxx>
#include <dispatchcommands.h>
#include <targets.h>
#include <services.h>
#include <general.h>

//_______________________________________________
// interface includes
#include <com/sun/star/frame/XDesktop.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/frame/CommandGroup.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include "com/sun/star/beans/XFastPropertySet.hpp"
#include <com/sun/star/frame/XModuleManager.hpp>

//_______________________________________________
// includes of other projects
#include <toolkit/helper/vclunohelper.hxx>
#include <vcl/window.hxx>
#include <vcl/svapp.hxx>
#include <vos/mutex.hxx>
#include <unotools/moduleoptions.hxx>

//_______________________________________________
// namespace

namespace framework{

#ifdef fpf
    #error "Who uses \"fpf\" as define. It will overwrite my namespace alias ..."
#endif
namespace fpf = ::framework::pattern::frame;

//_______________________________________________
// declarations

DEFINE_XINTERFACE_4(StartModuleDispatcher                                     ,
                    OWeakObject                                               ,
                    DIRECT_INTERFACE(css::lang::XTypeProvider                ),
                    DIRECT_INTERFACE(css::frame::XNotifyingDispatch          ),
                    DIRECT_INTERFACE(css::frame::XDispatch                   ),
                    DIRECT_INTERFACE(css::frame::XDispatchInformationProvider))

// Note: XStatusListener is an implementation detail. Hide it for scripting!
DEFINE_XTYPEPROVIDER_4(StartModuleDispatcher                   ,
                       css::lang::XTypeProvider                ,
                       css::frame::XDispatchInformationProvider,
                       css::frame::XNotifyingDispatch          ,
                       css::frame::XDispatch                   )

//-----------------------------------------------
StartModuleDispatcher::StartModuleDispatcher(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR  ,
                                             const css::uno::Reference< css::frame::XFrame >&              xFrame ,
                                             const ::rtl::OUString&                                        sTarget)
    : ThreadHelpBase     (&Application::GetSolarMutex() )
    , ::cppu::OWeakObject(                              )
    , m_xSMGR            (xSMGR                         )
    , m_xOwner           (xFrame                        )
    , m_sDispatchTarget  (sTarget                       )
    , m_lStatusListener  (m_aLock.getShareableOslMutex())
{
}

//-----------------------------------------------
StartModuleDispatcher::~StartModuleDispatcher()
{
}

//-----------------------------------------------
void SAL_CALL StartModuleDispatcher::dispatch(const css::util::URL&                                  aURL      ,
                                              const css::uno::Sequence< css::beans::PropertyValue >& lArguments)
    throw(css::uno::RuntimeException)
{
    dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >());
}

//-----------------------------------------------
void SAL_CALL StartModuleDispatcher::dispatchWithNotification(const css::util::URL&                                             aURL      ,
                                                              const css::uno::Sequence< css::beans::PropertyValue >&            /*lArguments*/,
                                                              const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
    throw(css::uno::RuntimeException)
{
    ::sal_Int16 nResult = css::frame::DispatchResultState::DONTKNOW;
    if (aURL.Complete.equals (CMD_UNO_SHOWSTARTMODULE))
    {
        nResult = css::frame::DispatchResultState::FAILURE;
        if (implts_isBackingModePossible ())
        {
            if (implts_establishBackingMode ())
                nResult = css::frame::DispatchResultState::SUCCESS;
        }
    }

    implts_notifyResultListener(xListener, nResult, css::uno::Any());
}

//-----------------------------------------------
css::uno::Sequence< ::sal_Int16 > SAL_CALL StartModuleDispatcher::getSupportedCommandGroups()
    throw(css::uno::RuntimeException)
{
    return css::uno::Sequence< ::sal_Int16 >();
}

//-----------------------------------------------
css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL StartModuleDispatcher::getConfigurableDispatchInformation(::sal_Int16 /*nCommandGroup*/)
    throw(css::uno::RuntimeException)
{
    return css::uno::Sequence< css::frame::DispatchInformation >();
}

//-----------------------------------------------
void SAL_CALL StartModuleDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/,
                                                       const css::util::URL&                                     /*aURL*/     )
    throw(css::uno::RuntimeException)
{
}

//-----------------------------------------------
void SAL_CALL StartModuleDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/,
                                                          const css::util::URL&                                     /*aURL*/     )
    throw(css::uno::RuntimeException)
{
}

//-----------------------------------------------
::sal_Bool StartModuleDispatcher::implts_isBackingModePossible ()
{
    if ( ! SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE))
        return sal_False;
    
    // SAFE -> ----------------------------------
    ReadGuard aReadLock(m_aLock);
    css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
    aReadLock.unlock();
    // <- SAFE ----------------------------------
    
    css::uno::Reference< css::frame::XFramesSupplier > xDesktop(
        xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY);
    
    FrameListAnalyzer aCheck(
        xDesktop,
        css::uno::Reference< css::frame::XFrame >(),
        FrameListAnalyzer::E_HELP | FrameListAnalyzer::E_BACKINGCOMPONENT);
    
    ::sal_Bool  bIsPossible    = sal_False;
    ::sal_Int32 nVisibleFrames = aCheck.m_lOtherVisibleFrames.getLength ();
    
    if (
		( ! aCheck.m_xBackingComponent.is ()) &&
		(   nVisibleFrames < 1              )
	   )
    {
        bIsPossible = sal_True;
    }
    
    return bIsPossible;
}

//-----------------------------------------------
::sal_Bool StartModuleDispatcher::implts_establishBackingMode()
{
    // SAFE -> ----------------------------------
    ReadGuard aReadLock(m_aLock);
    css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR  = m_xSMGR;
    aReadLock.unlock();
    // <- SAFE ----------------------------------

    css::uno::Reference< css::frame::XFrame > xDesktop         (xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY);
    css::uno::Reference< css::frame::XFrame > xFrame           = xDesktop->findFrame (SPECIALTARGET_BLANK, 0);
    css::uno::Reference< css::awt::XWindow  > xContainerWindow = xFrame->getContainerWindow ();

    css::uno::Sequence< css::uno::Any > lArgs(1);
    lArgs[0] <<= xContainerWindow;

    css::uno::Reference< css::frame::XController > xStartModule(
        xSMGR->createInstanceWithArguments(SERVICENAME_STARTMODULE, lArgs),
        css::uno::UNO_QUERY_THROW);

    css::uno::Reference< css::awt::XWindow > xComponentWindow(xStartModule, css::uno::UNO_QUERY);
    xFrame->setComponent(xComponentWindow, xStartModule);
    xStartModule->attachFrame(xFrame);
    xContainerWindow->setVisible(sal_True);

    return sal_True;
}

//-----------------------------------------------
void StartModuleDispatcher::implts_notifyResultListener(const css::uno::Reference< css::frame::XDispatchResultListener >& xListener,
                                                              ::sal_Int16                                                 nState   ,
                                                        const css::uno::Any&                                              aResult  )
{
    if ( ! xListener.is())
        return;

    css::frame::DispatchResultEvent aEvent(
        css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY),
        nState,
        aResult);

    xListener->dispatchFinished(aEvent);
}

} // namespace framework
