
/*  FSLView - 2D/3D Interactive Image Viewer

    Authors:    David Flitney 

    FMRIB Image Analysis Group

    Copyright (C) 2011 University of Oxford  */

/*  CCOPYRIGHT */

#include <QtGui>

#include "imagewindow.h"

#include "sliceview.h"
#include "slicewidget.h"
#include "briconwidget.h"
#include "cursorwidget.h"
#include "overlaywidget.h"
#include "talairachwidget.h"

#include "overlayinfodialog.h"
#include "viewoptionsdialog.h"

//#define DEBUGGING
#include "tracker.h"

struct ImageWindow::Implementation
{
  ImageWindow *iw;

  CursorWidget    *cursordock;
  TalairachWidget *talairachdock;
  OverlayWidget   *overlaydock;

  BriConWidget    *briconWidget;

  OverlayInfoDialog *overlayDialog;

  ImageGroup::Handle imageGroup;
  Cursor::Handle cursor, globalCursor;

  OverlayList::Handle      overlayList;
  DrawSettings::Handle     drawSettings;
  std::list<Shape::Handle> undoList;
  std::list<Shape::Handle> redoList;
  ViewOptions              opts;

  QTimer			*movieTimer;
  QActionGroup		*modeGroup;
  QActionGroup		*drawGroup;
  QSpinBox 			*penSize;
  QSpinBox			*penColor;

  Implementation(ImageGroup::Handle i,
		 OverlayList::Handle ol, 
		 Cursor::Handle c,
		 ImageWindow *p=0)
    : imageGroup(i),
      overlayList(ol),
      cursor(c->clone()),
      globalCursor(c),
      iw(p)
  {
	movieTimer = new QTimer(p);
	modeGroup = new QActionGroup(p);
	drawGroup = new QActionGroup(p);
    penColor = new QSpinBox(p);
    penSize = new QSpinBox(p);

	connect(movieTimer, SIGNAL(timeout()), p, SLOT(nextFrame()));
    drawSettings = DrawSettings::create();
    
    cursor->attach(iw);
    globalCursor->attach(iw);
    overlayList->attach(iw);

    overlayDialog = new OverlayInfoDialog(p, overlayList, imageGroup);
    connect(overlayDialog, SIGNAL(message(const QString&, int)), p, SIGNAL(message(const QString&, int)));

    penSize->setMaximum(100);
    penSize->setMinimum(1);
    penSize->setValue(1);
    connect(penSize, SIGNAL( valueChanged(int) ), p, SLOT( setPenSize(int) ));
    penColor->setMaximum(100);
    penColor->setMinimum(0);
    penColor->setValue(1);
    connect(penColor, SIGNAL( valueChanged(int) ), p, SLOT( setPenColor(int) ));
  }

  ~Implementation()
  {
	overlayList->detach(iw);
	globalCursor->detach(iw);
	cursor->detach(iw);

	if(overlayDialog) delete overlayDialog;
  }

  void setMovieFrameRate(int ms)
  {
	  if(movieTimer->isActive())
		  movieTimer->changeInterval(ms);
  }

  void setCurrentVolume(int n)
  {
    //m_cursor->setCursor(m_cursor->inqX(), m_cursor->inqY(), m_cursor->inqZ(), n);

    MetaImage::Handle mi = overlayList->getActiveMetaImage();
    mi->getDs()->setCurrentVolume(n);
    cursor->setCursor(cursor->inqX(), cursor->inqY(), cursor->inqZ(), n);
  }

  bool maskEditModeAllowed()
  {
	  MetaImage::Handle mi = overlayList->getActiveMetaImage();
	  return (mi->inqVisibility() && !mi->inqReadOnly());
  }

  void createDockWidgets(QWidget *p, OverlayList::Handle ol, Cursor::Handle c)
  {
	cursordock = new CursorWidget(iw, c, ol);
	iw->addDockWidget(Qt::BottomDockWidgetArea, cursordock);
    talairachdock = new TalairachWidget(iw, c, ol);
    iw->addDockWidget(Qt::BottomDockWidgetArea, talairachdock);
    talairachdock->hide();
    overlaydock = new OverlayWidget(iw, ol);
    iw->addDockWidget(Qt::BottomDockWidgetArea, overlaydock);
    connect(overlaydock,SIGNAL(infoButtonAction()), p, SLOT(openOverlayDialog()));


//    talairachdock->hide();
//    overlaydock->hide();
  }

};

ImageWindow::ImageWindow(ImageGroup::Handle i,
                         OverlayList::Handle ol, 
                         Cursor::Handle c,
                         QWidget *parent):
   QMainWindow(parent),
   m_impl(new Implementation(i, ol, c, this))
{
	setupUi(this);

//  setFrameShadow(QFrame::Raised);

//  setBackgroundColor(Qt::black);

  m_impl->createDockWidgets(this, ol, getCursor());
  m_impl->briconWidget = new BriConWidget(this, ol);
  m_briconToolBar->insertWidget(actionBriconReset, m_impl->briconWidget);

  ImageInfo::Handle info(m_impl->imageGroup->getMainImage()->getInfo());
  actionMovieMode->setEnabled(info->inqNumVolumes() > 1);
  actionCursorMode->setChecked(true);

  m_vtkToolBar->hide();

  //  setLabels(ol);
  setStyleSheet("QMainWindow::separator { width: 5px; height: 5px; }");
  on_actionCursorMode_toggled(true);

  m_impl->modeGroup->addAction(actionCursorMode);
  m_impl->modeGroup->addAction(actionPanMode);
  m_impl->modeGroup->addAction(actionMaskEditMode);
  m_impl->modeGroup->addAction(actionZoomMode);

  m_impl->drawGroup->addAction(actionSelectPenTool);
  m_impl->drawGroup->addAction(actionSelectEraseTool);
  m_impl->drawGroup->addAction(actionSelectFillTool);

  connect(m_impl->penSize, SIGNAL( valueChanged(int) ), SLOT( setPenSize(int) ));
  connect(m_impl->penColor, SIGNAL( valueChanged(int) ), SLOT( setPenColor(int) ));
  m_drawToolBar->addWidget(m_impl->penSize);
  m_drawToolBar->addWidget(m_impl->penColor);

//  connect( m_impl->modeGroup, SIGNAL(triggered(QAction*)), SLOT(modeTriggered(QACtion*)) );
}

ImageWindow::~ImageWindow()
{
}

void ImageWindow::setPenSize(int size)
{
	m_impl->drawSettings->setPenSize(size);
}

void ImageWindow::setPenColor(int color)
{
	TRACKER("ImageWindow::setPenColor(int color)");
	m_impl->drawSettings->setPenValue(color);
}

//void ImageWindow::setPenPixmap()
//{
//
//}

Cursor::Handle ImageWindow::getCursor()
{
	return m_impl->cursor;
}

OverlayList::Handle ImageWindow::getOverlayList()
{
	return m_impl->overlayList;
}

ViewOptions& ImageWindow::getOpts()
{
	return m_impl->opts;
}

DrawSettings::Handle ImageWindow::getDrawSettings()
{
	return m_impl->drawSettings;
}

struct SetVolume
{
  SetVolume(int v): m_vol(v) {}

  void operator()(const MetaImage::Handle& mi)
  {
    mi->getDs()->setCurrentVolume(m_vol);
  }

  int m_vol;
};

void ImageWindow::nextFrame()
{
  ImageInfo::Handle info(m_impl->imageGroup->getMainImage()->getInfo());
  int n = m_impl->cursor->inqV();
  if(++n >= info->inqNumVolumes()) n = 0;
  m_impl->setCurrentVolume(n);
}

void ImageWindow::on_actionBriconReset_triggered()
{
	m_impl->briconWidget->reset();
}

void ImageWindow::on_actionResetZoom_triggered()
{
	emit resetZoom();
}

void ImageWindow::on_actionToggleCrossHairs_toggled(bool mode)
{
	emit crossHairModeChanged(mode);
}

void ImageWindow::on_actionZoomMode_toggled(bool mode)
{
	emit modeChanged(mode ? SliceWidget::Zoom : SliceWidget::None);
}

void ImageWindow::on_actionPanMode_toggled(bool mode)
{
	emit modeChanged(mode ? SliceWidget::Pan : SliceWidget::None);
}

void ImageWindow::on_actionMaskEditMode_toggled(bool mode)
{
	m_drawToolBar->setEnabled(mode);
	emit modeChanged(mode ? SliceWidget::Masking : SliceWidget::None);
}

void ImageWindow::on_actionCursorMode_toggled(bool mode)
{
	emit modeChanged(mode ? SliceWidget::Cursing : SliceWidget::None);
}

void ImageWindow::on_actionMovieMode_toggled(bool mode)
{
	if(!m_impl->movieTimer->isActive())
		m_impl->movieTimer->start(m_impl->opts.inqMovieFrameRate(), false);
	else
		m_impl->movieTimer->stop();
}

void ImageWindow::on_actionOptions_triggered(bool mode)
{
	ViewOptionsDialog optionsDialog(this, m_impl->opts);

	optionsDialog.m_showLabels->setEnabled(true);

	if(optionsDialog.exec() == QDialog::Accepted)
	{
		m_impl->opts = optionsDialog.getOptions();
		setLabels(m_impl->overlayList.get());
		m_impl->setMovieFrameRate(m_impl->opts.inqMovieFrameRate());
		m_impl->cursor->repaint();	// Forces a redraw
	}
}

void ImageWindow::on_actionSliceRollMode_toggled(bool mode)
{
}

void ImageWindow::on_actionSelectPenTool_toggled(bool on)
{
	if(on)
		m_impl->drawSettings->setMode(DrawSettings::FreeHand);
	m_impl->penSize->setValue(m_impl->drawSettings->inqPenSize());
	m_impl->penColor->setValue(m_impl->drawSettings->inqPenValue());

}

void ImageWindow::on_actionSelectEraseTool_toggled(bool on)
{
	if(on)
		m_impl->drawSettings->setMode(DrawSettings::Erase);
	m_impl->penSize->setValue(m_impl->drawSettings->inqPenSize());
	m_impl->penColor->setValue(m_impl->drawSettings->inqPenValue());
}

void ImageWindow::on_actionSelectFillTool_toggled(bool on)
{
	if(on)
		m_impl->drawSettings->setMode(DrawSettings::Fill);
	m_impl->penSize->setValue(m_impl->drawSettings->inqPenSize());
	m_impl->penColor->setValue(m_impl->drawSettings->inqPenValue());
}

void ImageWindow::on_actionRedo_triggered()
{
  TRACKER("ImageWindow::redoGraphics()");
  if(!m_redoList.empty())
    {
      Shape::Handle s = m_redoList.back();
      m_redoList.pop_back();
      m_undoList.push_back(s->getBuffer());
      s->commit();
    }
  m_impl->cursor->repaint();
}

void ImageWindow::on_actionUndo_triggered()
{
  TRACKER("ImageWindow::undoGraphics()");
  if(!m_undoList.empty())
    {
      Shape::Handle s = m_undoList.back();
      m_undoList.pop_back();
      m_redoList.push_back(s->getBuffer());
      s->commit();
    }
  m_impl->cursor->repaint();
}

void ImageWindow::on_actionLinkCursor_toggled(bool on)
{
	m_impl->drawSettings->setLinkCursor(on);
}

void ImageWindow::on_actionSnapShot_triggered()
{
	QPixmap snap = QPixmap::grabWidget(centralWidget());

    QString format = "png";
    QString initialPath = QDir::currentPath() + tr("/snapshot.") + format;

    QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
                               initialPath,
                               tr("%1 Files (*.%2);;All Files (*)")
                               .arg(format.toUpper())
                               .arg(format));
    if (!fileName.isEmpty())
        snap.save(fileName, format.toAscii());

}

void ImageWindow::update(const Cursor::Handle& c)
{
	//  TRACKER("ImageWindow::update(const Cursor::Handle& c)");

//	qDebug("ImageWindow::update(this=%p, c=%s)", this, (c == m_impl->cursor) ? "local" : "global");
//	qDebug("ImageWindow::update(...) v = %d", c->inqV());

	MetaImage::Handle mi = m_impl->overlayList->getActiveMetaImage();

	// See if we need to do any volume updates
	if(c == m_impl->cursor){
		mi->getDs()->setCurrentVolume(c->inqV());
		if(m_impl->opts.inqVolumeIndexingWithinView())
			for_each( m_impl->overlayList->begin(), m_impl->overlayList->end(), SetVolume(c->inqV()) );
	} else {
		if ( (m_impl->opts.inqUseSharedVolume()) && (c->inqV() <= mi->getInfo()->inqNumVolumes()) ) {
			mi->getDs()->setCurrentVolume(c->inqV());
			if(m_impl->opts.inqVolumeIndexingWithinView())
				for_each( m_impl->overlayList->begin(), m_impl->overlayList->end(), SetVolume(c->inqV()) );
			m_impl->cursordock->setVolumeValue(c->inqV());
		} else
			m_impl->cursordock->setVolumeValue(mi->getDs()->inqCurrentVolume());
	}

	// Propagate cursor changes to/from the global cursor
	Cursor::Handle dst((c == m_impl->cursor) ? m_impl->globalCursor : m_impl->cursor);
	dst->detach(this);
	if( m_impl->opts.inqUseSharedLocation() )
		dst->setCursor(c->inqX(), c->inqY(), c->inqZ());
	if( m_impl->opts.inqUseSharedVolume() )
		dst->setCursor(c->inqV());
	if(c->inqRepaint())
		dst->repaint(); // note the need to pass on repaint requests
	dst->attach(this);

	// Propagate cursor changes if necessary...
//	if(c == m_impl->globalCursor) {
//		m_impl->cursor->detach(this);
//		if( m_impl->opts.inqUseSharedLocation() )
//			if( m_impl->opts.inqUseSharedVolume() )
//				m_impl->cursor->setCursor(c);
//			else
//				m_impl->cursor->setCursor(c->inqX(), c->inqY(), c->inqZ());
//		if(c->inqRepaint())
//			m_impl->cursor->repaint(); // note the need to pass on repaint requests
//		m_impl->cursor->attach(this);
//	} else {
//		m_impl->globalCursor->detach(this);
//		if( m_impl->opts.inqUseSharedLocation() )
//			if( m_impl->opts.inqUseSharedVolume() )
//				m_impl->globalCursor->setCursor(c);
//			else
//				m_impl->globalCursor->setCursor(c->inqX(), c->inqY(), c->inqZ());
//		if(c->inqRepaint())
//			m_impl->globalCursor->repaint();
//		m_impl->globalCursor->attach(this);
//	}

}

void ImageWindow::openOverlayDialog()
{
//  TRACKER("ImageWindow::openOverlayDialog");

  m_impl->overlayDialog->show();
}

void ImageWindow::update(const OverlayList* i, OverlayListMsg msg)
{
  //  TRACKER("ImageWidget::update(const OverlayList* i, OverlayListMsg msg)");

//	if(OverlayListMsg(Select) == msg)
//	{
//		clearUndoList();
//	}
	MetaImage::Handle mi = i->getActiveMetaImage();

	Cursor::Handle c =  m_impl->cursor;
	c->setCursor(c->inqX(), c->inqY(), c->inqZ(), mi->getDs()->inqCurrentVolume());

	if(OverlayListMsg(DtiMode) == msg)
	{
		if(mi)
		{
			if(DtiDisplay(None) == mi->getDs()->inqDtiDisplay())
			{
				ImageInfo::Handle info(m_impl->imageGroup->getMainImage()->getInfo());
				actionMovieMode->setEnabled(info->inqNumVolumes() > 1);
			}
			else
			{
//				m_cursorWidget->setVolumeValue(0);
				actionMovieMode->setEnabled(false);
				m_impl->movieTimer->stop();
			}
		}
	}

	if(OverlayListMsg(Select) == msg || OverlayListMsg(DtiMode) == msg ||
		OverlayListMsg(Visibility) == msg || OverlayListMsg(Security) == msg)
	{

		bool state(m_impl->maskEditModeAllowed());
		actionMaskEditMode->setEnabled(state);
		if(!state)
		{
			m_drawToolBar->setEnabled(state);
		}
		else if(actionMaskEditMode->isChecked())
		{
			m_drawToolBar->setEnabled(true);
			m_impl->drawSettings->setMode(DrawSettings::FreeHand);
		}
		else
		{
			m_drawToolBar->setEnabled(false);
			on_actionCursorMode_toggled(true);
		}
	}

  //  emit overlayEvent();
}  

void ImageWindow::closeEvent(QCloseEvent *event)
{
//	if (maybeSave()) {
//		event->accept();
//	} else {
//		event->ignore();
//	}
	QString str("ImageWindow::closeEvent");
	emit message(str, -1);

	event->accept();

	emit windowClose(event);
}
