//==============================================
//  copyright            : (C) 2003-2005 by Will Stokes
//==============================================
//  This program is free software; you can redistribute it
//  and/or modify it under the terms of the GNU General
//  Public License as published by the Free Software
//  Foundation; either version 2 of the License, or
//  (at your option) any later version.
//==============================================

//Systemwide includes
#include <qlayout.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <qpushbutton.h>
#include <qframe.h>
#include <qslider.h>
#include <qtooltip.h>
#include <qsizegrip.h>

//Projectwide includes
#include "grainEditor.h"
#include "panningPreviewInterface.h"
#include "selectionPlacementInterface.h"
#include "../blurSharpenSlider.h"
#include "../clickableLabel.h"
#include "../../config.h"
#include "../../backend/manipulations/blur.h"
#include "../../backend/manipulations/sharpen.h"
#include "../../backend/manipulations/edgeDetect.h"
#include "../../backend/tools/imageTools.h"

#define SLIDER_RADIUS 50

//==============================================
GrainEditor::GrainEditor( QString fileName, QWidget *parent, const char* name ) : QDialog(parent,name,true)
{
  //record filename
  this->fileName = fileName;

  //record original image size
  getImageSize( fileName, origImageSize );
  
  //construct edges image
  //speed up edge finding by scaling image down to < 800x600
  scaleImage( fileName, edgesImage, 512, 384 );
  EdgeDetect detector( &edgesImage );
  clusterMap = detector.getClusterMap();
  numRegions = detector.getNumClusters();
  
  QFrame* visibleFrame = new QFrame( this, "visible widgets" );
  //--------------
  //Preview frame
  previewInterface = new PanningPreviewInterface( fileName, 
                                                  visibleFrame, "previewInterface" );
  previewSelection = new QComboBox( visibleFrame, "previewSelction" );
  previewSelection->insertItem( tr("Split View") );
  previewSelection->insertItem( tr("Original Image") );
  previewSelection->insertItem( tr("Adjusted Image") );
  connect( previewSelection, SIGNAL(activated(int)), this, SLOT(selectPreviewImageType(int)) );  
   //--------------  
  //Controls frame 
  QFrame* controlsFrame = new QFrame( visibleFrame, "controlsFrame" );

  QLabel* selectionLabel = new QLabel( tr("Region Shown in Detail:"), 
                                       controlsFrame, "selectionLabel" );
  
  selectionPlacementInterface = new SelectionPlacementInterface( fileName, 
                                                                 controlsFrame, 
                                                                 "selectionPlacementInterface" );
  //--
  connect( previewInterface, SIGNAL( selectionChanged() ),
           this, SLOT( previewResized() ) );
  connect( selectionPlacementInterface, SIGNAL(placementChanged(QRect)), 
           previewInterface, SLOT(setSelection(QRect)) );  
  //--
  boundariesSlider = new BlurSharpenSlider( Qt::Vertical, controlsFrame );
  boundariesSlider->setMinValue( -SLIDER_RADIUS );
  boundariesSlider->setMaxValue( SLIDER_RADIUS );
  connect( boundariesSlider, SIGNAL(valueChanged(int)),
           this, SLOT(generateAdjustedPreviewImage()) );
           
  boundariesIcon = new ClickableLabel( controlsFrame, "boundariesIcon" );
  connect( boundariesIcon, SIGNAL(clicked()), SLOT(resetBoundaries()) );    

//  boundariesIcon->setPixmap( QPixmap(QString(IMAGE_PATH)+"miscImages/boundaries.png") );
//  QToolTip::add( boundariesSlider, tr("Blur/sharpen boundaries") );  
//  QToolTip::add( boundariesIcon, tr("Reset boundaries") );
  boundariesIcon->setPixmap( QPixmap(QString(IMAGE_PATH)+"miscImages/blurSharpen.png") );
  QToolTip::add( boundariesSlider, tr("Blur/Sharpen Image") );  
  QToolTip::add( boundariesIcon, tr("Reset") );
  //--
  /*
 regionsSlider = new QSlider(Qt::Vertical, controlsFrame );
  regionsSlider->setMinValue( -SLIDER_RADIUS );
  regionsSlider->setMaxValue( SLIDER_RADIUS );
  connect( regionsSlider, SIGNAL(valueChanged(int)),
           this, SLOT(generateAdjustedPreviewImage()) );
  QToolTip::add( regionsSlider, tr("Blur/sharpen regions") );  
  
  regionsIcon = new ClickableLabel( controlsFrame, "regionsIcon" );
  regionsIcon->setPixmap( QPixmap(QString(IMAGE_PATH)+"miscImages/regions.png") );
  connect( regionsIcon, SIGNAL(clicked()), SLOT(resetRegions()) );    
  QToolTip::add( regionsIcon, tr("Reset regions") );
 */
  //--
  QGridLayout* controlsGrid = new QGridLayout( controlsFrame, 6, 4, 0 );
  controlsGrid->setRowStretch( 0, 1 );  

  controlsGrid->addMultiCellWidget( selectionLabel,              1,1, 0,3 );
  controlsGrid->addMultiCellWidget( selectionPlacementInterface, 2,2, 0,3 );

  controlsGrid->addWidget( boundariesSlider,  3, 1 );
  controlsGrid->addWidget( boundariesIcon,    4, 1 );

//  controlsGrid->addWidget( regionsSlider,  3, 2 );
//  controlsGrid->addWidget( regionsIcon,    4, 2 );

  //make sure sliders have enough space so all slider units are settable
  controlsGrid->setRowSpacing( 3, 2*SLIDER_RADIUS + 5) ;
 
  controlsGrid->setRowStretch( 5, 1 );  
  controlsGrid->setSpacing( WIDGET_SPACING ); 

  controlsGrid->setColStretch( 0, 1 );
  controlsGrid->setColStretch( 3, 1 );
  //--------------
  //Dialog buttons:  
  buttonsFrame =   new QFrame( visibleFrame, "dialogButtons" );

  QPushButton* applyButton = new QPushButton( tr("Apply"), buttonsFrame );
  applyButton->setDefault(true);
  applyButton->setFocus();
  connect( applyButton, SIGNAL(clicked()), SLOT(applyAction()) );
                                
  QPushButton* cancelButton = new QPushButton( tr("Cancel"), buttonsFrame );
  connect( cancelButton, SIGNAL(clicked()), SLOT(reject()) );

  QPushButton* resetButton = new QPushButton( tr("Reset"), buttonsFrame );
  connect( resetButton, SIGNAL(clicked()), SLOT(resetAction()) );

  QGridLayout* buttonsGrid = new QGridLayout( buttonsFrame, 1, 5, 0 );
  buttonsGrid->setColStretch( 0, 1 );
  buttonsGrid->addWidget( applyButton,  0, 1 );
  buttonsGrid->addWidget( cancelButton, 0, 2 );
  buttonsGrid->addWidget( resetButton, 0, 3 );
  buttonsGrid->setColStretch( 4, 1 );  
  buttonsGrid->setSpacing( WIDGET_SPACING );
  //--------------
  //Top level grid  
  QGridLayout* mainGrid = new QGridLayout( visibleFrame, 3, 2, 0 );
  
  mainGrid->addWidget( previewInterface, 0,0 );
  mainGrid->addWidget( previewSelection, 1,0, Qt::AlignHCenter );  

  mainGrid->addMultiCellWidget( controlsFrame, 0,1, 1,1 );
  
  mainGrid->addMultiCellWidget( buttonsFrame, 2,2, 0,1 );

  mainGrid->setRowStretch( 0, 1 );
  mainGrid->setColStretch( 0, 1 );

  mainGrid->setSpacing( WIDGET_SPACING );
  mainGrid->setMargin( WIDGET_SPACING );  


  QGridLayout* invisibleGrid = new QGridLayout( this, 2, 1, 0 );
  invisibleGrid->addWidget( visibleFrame, 0, 0 );
  invisibleGrid->setRowStretch( 0, 1 );

  //PLATFORM_SPECIFIC_CODE
  //windows users expect a grip, but qt doesn't put one in by default. we'll add
  //it for them too. :-)
#if defined(Q_OS_WIN)
  QSizeGrip* sizeGrip = new QSizeGrip( this );
  invisibleGrid->addWidget( sizeGrip, 1, 0, Qt::AlignRight | Qt::AlignBottom );
#endif
  
  
  
  
  //--------------
  //Window caption
  setCaption( tr("Grain Editor") );
  //-------------------------------
}
//==============================================
GrainEditor::~GrainEditor() { }
//==============================================
void GrainEditor::applyAction()
{
  //check if user has adjusted grain.
  //if any changes have taken place call "accept", else "reject" so image is not
  //updated and appear modified
  if( boundariesSlider->value() != 0 )
    //||
    //  regionsSlider->value() != 0 )
  { accept(); }
  else
  { reject(); }  
}
//==============================================
void GrainEditor::resetBoundaries()
{
  boundariesSlider->setValue( 0 );
}
//==============================================
void GrainEditor::resetRegions()
{
  //regionsSlider->setValue( 0 );
}
//==============================================
void GrainEditor::resetAction()
{
  boundariesSlider->setValue( 0 );
  //regionsSlider->setValue( 0 );
}
//==============================================
QImage* GrainEditor::getModifiedImage()
{ 
  QImage* adjustedImage = new QImage(fileName);  

  //convert to 32-bit depth if necessary
  if( adjustedImage->depth() < 32 )
  {
    QImage* tmp = adjustedImage;
    adjustedImage = new QImage( tmp->convertDepth( 32, Qt::AutoColor ) );
    delete tmp; tmp=NULL;
  }
  
  adjustImage( *adjustedImage, QPoint(0,0) );
  return adjustedImage;  
}
//==============================================
void GrainEditor::selectPreviewImageType( int selection )
{
  previewInterface->setPreviewMode( (PREVIEW_MODE)selection );
}
//==============================================
void GrainEditor::previewResized()
{
  //reset selected region in selection placement interface
  selectionPlacementInterface->setSelectedRegion( previewInterface->getSelection() );

  //regenerate adjusted image and repaint
  generateAdjustedPreviewImage();
}
//==============================================
void GrainEditor::generateAdjustedPreviewImage()
{
  //get original image
  QImage origImage = previewInterface->getOrigImage();

  //construct adjusted image
  QImage adjustedImage = origImage.copy();
  adjustImage( adjustedImage, previewInterface->getSelection().topLeft() );
  
  //set adjusted image
  previewInterface->setAdjustedImage( adjustedImage );
}
//==============================================
void GrainEditor::adjustImage( QImage& image, QPoint offset )
{
  //no adjustment - don't change the image at all
  if( boundariesSlider->value() == 0 )//&&
      //regionsSlider->value() == 0 )
  { return; }
  
  //compute sigma
  float boundariesSigma;
  if( boundariesSlider->value() < 0 )
    boundariesSigma = (80.0f * QABS(boundariesSlider->value()) ) / 255.0f;  
  else
    boundariesSigma = (25.5f * QABS(boundariesSlider->value()) ) / 255.0f;  
//  float regionsSigma = (20.0f * QABS(regionsSlider->value()) ) / 255.0f;  

  
  //sharpen
  if ( boundariesSlider->value() < 0 )
  {
    sharpenImage( image, boundariesSigma, 
                  offset, origImageSize,
                  &edgesImage, true ); 
  }
  //blur
  else if( boundariesSlider->value() > 0 )
  {
    blurImage( image, boundariesSigma );
  }

  /*
  //sharpen boundaries
  if ( boundariesSlider->value() < 0 )
  {
    sharpenImage( image, boundariesSigma, 
                  offset, origImageSize,
                  &edgesImage, true ); 
  }
  //blur boundaries
  else if( boundariesSlider->value() > 0 )
  {
    blurImage( image, boundariesSigma, 
               offset, origImageSize,
               &edgesImage, NULL, numRegions, true ); 
  }
  
  //sharpen regions
  if ( regionsSlider->value() < 0 )
  {
    sharpenImage( image, regionsSigma, 
                  offset, origImageSize,
                  &edgesImage, false ); 
  }
  //blur regions
  else if( regionsSlider->value() > 0 )
  { 
    blurImage( image, regionsSigma, 
               offset, origImageSize,
               &edgesImage, clusterMap, numRegions, false );
  }
  */

}
//==============================================
void GrainEditor::keyPressEvent(QKeyEvent *e)
{
  if(e->key() == Qt::Key_Control )
  {
    PREVIEW_MODE curMode = (PREVIEW_MODE) previewSelection->currentItem();
    if(curMode == ORIGINAL_IMAGE)
      previewInterface->setPreviewMode( ADJUSTED_IMAGE, true );
    else if(curMode == ADJUSTED_IMAGE)
      previewInterface->setPreviewMode( ORIGINAL_IMAGE, true );
    else
      previewInterface->setPreviewMode( INV_SPLIT_VIEW );
  }
  else { QDialog::keyPressEvent(e); }
}
//==============================================
void GrainEditor::keyReleaseEvent(QKeyEvent *e)
{
  if(e->key() == Qt::Key_Control )
  {
    previewInterface->setPreviewMode( (PREVIEW_MODE) previewSelection->currentItem(), 
                                      false );
  }
  else { QDialog::keyReleaseEvent(e); }
}
//==============================================



