/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed 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.
 */


#ifndef mvdI18nMainWindow_h
#define mvdI18nMainWindow_h

//
// Configuration include.
//// Included at first position before any other ones.
#include "ConfigureMonteverdi.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.
#include <QtWidgets>

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)
#include "OTBMonteverdiGUIExport.h"
//
// Monteverdi includes (sorted by alphabetic order)


/*****************************************************************************/
/* PRE-DECLARATION SECTION                                                   */

//
// External class pre-declaration.
namespace
{
}

namespace mvd
{
//
// Internal class pre-declaration.
class AbstractModel;
class AbstractModelController;
class AbstractWorker;
class DatasetModel;
class VectorImageModel;

/*****************************************************************************/
/* CLASS DEFINITION SECTION                                                  */

/**
 * \class I18nMainWindow
 *
 * \ingroup OTBMonteverdiGUI
*
 * \brief Main-window widget base for the i18n application.
 */
class OTBMonteverdiGUI_EXPORT I18nMainWindow
  : public QMainWindow
{

  /*-[ QOBJECT SECTION ]-----------------------------------------------------*/

  Q_OBJECT;

  /*-[ PUBLIC SECTION ]------------------------------------------------------*/

//
// Public types.
public:
  enum DockLayout
  {
    DOCK_LAYOUT_NONE = 0,
    DOCK_LAYOUT_FLOATING = 1,
    DOCK_LAYOUT_SCROLLABLE = 2,
  };

  typedef QFlags< DockLayout > DockLayoutFlags;

//
// Public methods.
public:
  /** \brief Destructor. */
  ~I18nMainWindow() override;

  /**
   */
  void Initialize();

  /*-[ SIGNALS SECTION ]-----------------------------------------------------*/

//
// SIGNALS.
signals:

  /*-[ PROTECTED SECTION ]---------------------------------------------------*/

//
// Protected methods.
protected:

  /** \brief Constructor. */
  I18nMainWindow( QWidget* Parent =0, Qt::WindowFlags flags =0 );

  /**
   */
  QDockWidget*
    AddWidgetToDock( QWidget* widget,
		     const QString& dockName,
		     const QString& dockTitle,
		     Qt::DockWidgetArea dockArea,
		     DockLayoutFlags flags = DOCK_LAYOUT_NONE );

  /**
   */
  template< typename TWidget, typename TDockWidget >
    inline
    TDockWidget*
    AddDockWidget( const QString& dockName,
		   const QString& dockTitle,
		   Qt::DockWidgetArea dockArea,
		   DockLayoutFlags flags = DOCK_LAYOUT_NONE );

  /**
   */
  template< typename TWidget, typename TController, typename TDockWidget >
    inline
    TDockWidget*
    AddDockWidget( const QString& dockName,
		   const QString& dockTitle,
		   Qt::DockWidgetArea dockArea,
		   DockLayoutFlags flags = DOCK_LAYOUT_NONE );
  /**
   */
  const AbstractModelController *
    GetController( const QDockWidget * ) const;
  /**
   */
  AbstractModelController *
    GetController( const QDockWidget * );

  /**
   * \brief Assign model to the controller which is child of given
   * dock-widget.
   *
   * \param dock The dock-widget which is parent of the controller to
   * assign model to.
   *
   * \param model The model to assign to the controller.
   */
  inline void SetControllerModel( QDockWidget* dock, AbstractModel* model );

  /**
   */
  VectorImageModel *
    ImportImage( const QString & filename,
                 int width,
                 int height );

  /**
   */
  bool BuildGDALOverviews( const QStringList & filenames );

  /**
   */
  void SaveLayout( int version ) const;

  /**
   */
  bool RestoreLayout( int version );

  //
  // QMainWindow methods.

  void closeEvent( QCloseEvent* event ) override;

//
// Protected attributes.
protected:

  /*-[ PROTECTED SLOTS SECTION ]---------------------------------------------*/

//
// Protected slots.
protected slots:

  /**
   */
  virtual void OnAboutToChangeModel( const AbstractModel* ) =0;

  /**
   */
  virtual void OnModelChanged( AbstractModel* ) =0;

  /*-[ PRIVATE SECTION ]-----------------------------------------------------*/

//
// Private nested classes.
private:


//
// Private methods.
private:
  /**
   */
  QObject * Import( AbstractWorker * );

  /**
   */
  virtual void virtual_SetupUI() =0;

  /**
   */
  virtual void virtual_ConnectUI() =0;

  /**
   */
  virtual void virtual_InitializeUI();

  /**
   */

//
// Private attributes.
private:

  /*-[ PRIVATE SLOTS SECTION ]-----------------------------------------------*/

//
// Private slots.
private slots:

  /**
   * \brief Qt auto-connected slot which is called when File/Quit menu
   * action is activated.
   */
  void on_action_Quit_triggered();

  /**
   * \brief Qt auto-connected slot which is called when Help/About
   * menu action is activated.
   */
  virtual void on_action_About_triggered();

};

} // end namespace 'mvd'

/*****************************************************************************/
/* INLINE SECTION                                                            */

//
// System includes (sorted by alphabetic order)
#include <cassert>

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "mvdAbstractModelController.h"

namespace mvd
{

/*****************************************************************************/
inline
const AbstractModelController *
I18nMainWindow
::GetController( const QDockWidget * dock ) const
{
  assert( dock!=NULL );

  return dock->findChild< const AbstractModelController * >();
}

/*****************************************************************************/
inline
AbstractModelController *
I18nMainWindow
::GetController( const QDockWidget * dock )
{
  assert( dock!=NULL );

  return dock->findChild< AbstractModelController * >();
}

/*****************************************************************************/
inline
void
I18nMainWindow
::SetControllerModel( QDockWidget* dock, AbstractModel* model )
{
  assert( dock );

  AbstractModelController* controller =
    dock->findChild< AbstractModelController* >();

  assert( controller!=NULL );

  controller->SetModel( model );
}

/*****************************************************************************/
template< typename TWidget, typename TDockWidget >
inline
TDockWidget*
I18nMainWindow
::AddDockWidget( const QString & dockName,
		 const QString & dockTitle,
		 Qt::DockWidgetArea dockArea,
		 DockLayoutFlags flags )
{
  TWidget * widget = new TWidget( this );

  TDockWidget * dockWidget =
    AddWidgetToDock(
      widget,
      dockName,
      dockTitle,
      dockArea,
      flags
    );

  return dockWidget;
}

/*****************************************************************************/
template< typename TWidget, typename TController, typename TDockWidget >
inline
TDockWidget*
I18nMainWindow
::AddDockWidget( const QString & dockName,
		 const QString & dockTitle,
		 Qt::DockWidgetArea dockArea,
		 DockLayoutFlags flags )
{
  TWidget * widget = new TWidget( this );

  QWidget * pannel = widget;

  if( flags.testFlag( DOCK_LAYOUT_SCROLLABLE ) )
    {
    QScrollArea * scrollArea = new QScrollArea( this );

    scrollArea->setWidgetResizable( true );

    scrollArea->setWidget( widget );

    pannel = scrollArea;
    }


  TDockWidget * dockWidget =
    AddWidgetToDock(
      pannel,
      dockName,
      dockTitle,
      dockArea,
      flags
    );

  new TController(
    // wraps:
    widget,
    // as chid of:
    dockWidget
  );

  return dockWidget;
}

} // end namespace 'mvd'

#endif // I18nMainWindow_h
