/***************************************************************************
                          FITSViewer.cpp  -  A FITSViewer for KStars
                             -------------------
    begin                : Thu Jan 22 2004
    copyright            : (C) 2004 by Jasem Mutlaq
    email                : mutlaqja@ikarustech.com

 2006-03-03	Using CFITSIO, Porting to Qt4
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "fitsviewer.h"

#include <klocale.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kstandardaction.h>

#include <kdebug.h>
#include <ktoolbar.h>
#include <ktemporaryfile.h>
#include <kmenubar.h>
#include <kstatusbar.h>
#include <klineedit.h>
#include <kicon.h>

#include <KUndoStack>
#include <KTabWidget>
#include <KAction>

#include <QFile>
#include <QCursor>
#include <QRadioButton>
#include <QClipboard>
#include <QImage>
#include <QRegExp>
#include <QKeyEvent>
#include <QCloseEvent>
#include <QTreeWidget>
#include <QHeaderView>
#include <QApplication>
#include <QUndoStack>
#include <QUndoGroup>

#include <math.h>
#ifndef __MINGW32__
  #include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifndef __MINGW32__
  #include <netinet/in.h>
#endif

#include "fitstab.h"
#include "fitsimage.h"
#include "fitshistogram.h"
#include "ksutils.h"
#include "Options.h"

FITSViewer::FITSViewer (QWidget *parent)
        : KXmlGuiWindow (parent)
{
    fitsTab   = new KTabWidget(this);
    undoGroup = new QUndoGroup(this);

    fitsTab->setTabsClosable(true);

    setCentralWidget(fitsTab);

    connect(fitsTab, SIGNAL(currentChanged(int)), this, SLOT(tabFocusUpdated(int)));
    connect(fitsTab, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));

    statusBar()->insertItem(QString(), FITS_POSITION);
    statusBar()->setItemFixed(FITS_POSITION, 100);
    statusBar()->insertItem(QString(), FITS_VALUE);
    statusBar()->setItemFixed(FITS_VALUE, 100);
    statusBar()->insertItem(QString(), FITS_RESOLUTION);
    statusBar()->setItemFixed(FITS_RESOLUTION, 100);
    statusBar()->insertItem(QString(), FITS_ZOOM);
    statusBar()->setItemFixed(FITS_ZOOM, 50);
    statusBar()->insertPermanentItem(i18n("Welcome to KStars FITS Viewer"), FITS_MESSAGE, 1);
    statusBar()->setItemAlignment(FITS_MESSAGE , Qt::AlignLeft);

    KAction *action;
    QFile tempFile;
    if (KSUtils::openDataFile( tempFile, "histogram.png" ) )
    {
        action = actionCollection()->addAction("image_histogram");
        action->setIcon(KIcon(tempFile.fileName()));
        tempFile.close();
    }
    else
    {
        action = actionCollection()->addAction("image_histogram");
        action->setIcon(KIcon("tools-wizard"));
    }

    action->setText(i18n("Histogram"));
    connect(action, SIGNAL(triggered(bool)), SLOT (histoFITS()));
    action->setShortcuts(KShortcut( Qt::CTRL+Qt::Key_H ));

    KStandardAction::open(this,   SLOT(openFile()),   actionCollection());
    KStandardAction::save(this,   SLOT(saveFile()),   actionCollection());
    KStandardAction::saveAs(this, SLOT(saveFileAs()), actionCollection());
    KStandardAction::close(this,  SLOT(slotClose()),  actionCollection());
    KStandardAction::copy(this,   SLOT(copyFITS()),   actionCollection());

    KStandardAction::zoomIn(this,     SLOT(ZoomIn()),      actionCollection());
    KStandardAction::zoomOut(this,    SLOT(ZoomOut()),     actionCollection());
    KStandardAction::actualSize(this, SLOT(ZoomDefault()), actionCollection());

    KAction *kundo = KStandardAction::undo(undoGroup, SLOT(undo()), actionCollection());
    KAction *kredo = KStandardAction::redo(undoGroup, SLOT(redo()), actionCollection());

    connect(undoGroup, SIGNAL(canUndoChanged(bool)), kundo, SLOT(setEnabled(bool)));
    connect(undoGroup, SIGNAL(canRedoChanged(bool)), kredo, SLOT(setEnabled(bool)));

    action = actionCollection()->addAction("image_stats");
    action->setIcon(KIcon("view-statistics"));
    action->setText(i18n( "Statistics"));
    connect(action, SIGNAL(triggered(bool)), SLOT(statFITS()));
    
    action = actionCollection()->addAction("fits_editor");
    action->setIcon(KIcon("document-properties"));
    action->setText(i18n( "FITS Header"));
    connect(action, SIGNAL(triggered(bool) ), SLOT(headerFITS()));

    /* Create GUI */
    createGUI("fitsviewer.rc");

    setWindowTitle(i18n("KStars FITS Viewer"));

    /* initially resize in accord with KDE rules */
    resize(INITIAL_W, INITIAL_H);
}

FITSViewer::~FITSViewer()
{}

bool FITSViewer::addFITS(const KUrl *imageName, FITSMode mode)
{

    FITSTab *tab = new FITSTab();

    if (tab->loadFITS(imageName) == false)
        return false;

    switch (mode)
    {
      case FITS_NORMAL:
        fitsTab->addTab(tab, imageName->fileName());
        break;

      case FITS_FOCUS:
        fitsTab->addTab(tab, i18n("Focus"));
        break;

    }

    connect(tab, SIGNAL(newStatus(QString,FITSBar)), this, SLOT(updateStatusBar(QString,FITSBar)));
    connect(tab->getImage(), SIGNAL(actionUpdated(QString,bool)), this, SLOT(updateAction(QString,bool)));
    connect(tab, SIGNAL(changeStatus(bool)), this, SLOT(updateTabStatus(bool)));

    undoGroup->addStack(tab->getUndoStack());
    tab->tabPositionUpdated();

    fitsImages.push_back(tab);

    fitsTab->setCurrentWidget(tab);


    return true;
}

void FITSViewer::tabFocusUpdated(int currentIndex)
{
    if (currentIndex < 0 || fitsImages.empty())
        return;

    fitsImages[currentIndex]->tabPositionUpdated();
}

void FITSViewer::slotClose()
{
    if (undoGroup->isClean())
        close();
    else
        saveUnsaved();
}

void FITSViewer::closeEvent(QCloseEvent *ev)
{
    saveUnsaved();
    if( undoGroup->isClean() )
        ev->accept();
    else
        ev->ignore();
}

void FITSViewer::openFile()
{
    KUrl fileURL = KFileDialog::getOpenUrl( QDir::homePath(), "*.fits *.fit *.fts|Flexible Image Transport System");
    if (fileURL.isEmpty())
        return;

    QString fpath = fileURL.path();
    QString cpath;


    // Make sure we don't have it open already, if yes, switch to it
    foreach (FITSTab *tab, fitsImages)
    {
        cpath = tab->getCurrentURL()->path();
        if (fpath == cpath)
        {
            fitsTab->setCurrentWidget(tab);
            return;
        }
    }

    addFITS(&fileURL);
}

void FITSViewer::saveFile()
{
    fitsImages[fitsTab->currentIndex()]->saveFile();
}

void FITSViewer::saveFileAs()
{
    //currentURL.clear();

    if (fitsImages.empty())
        return;

    fitsImages[fitsTab->currentIndex()]->saveFileAs();

}

void FITSViewer::copyFITS()
{
    if (fitsImages.empty())
        return;

   fitsImages[fitsTab->currentIndex()]->copyFITS();
}

void FITSViewer::histoFITS()
{
    if (fitsImages.empty())
        return;

    fitsImages[fitsTab->currentIndex()]->histoFITS();
}

void FITSViewer::statFITS()
{
    if (fitsImages.empty())
        return;

  fitsImages[fitsTab->currentIndex()]->statFITS();
}

void FITSViewer::headerFITS()
{
    if (fitsImages.empty())
        return;

  fitsImages[fitsTab->currentIndex()]->headerFITS();
}

int FITSViewer::saveUnsaved(int index)
{
    QUndoStack *undoStack = NULL;
    FITSTab *targetTab = NULL;
    QString caption = i18n( "Save Changes to FITS?" );
    QString message = i18n( "The current FITS file has unsaved changes.  Would you like to save before closing it?" );

    if (undoGroup->isClean())
        return -1;

    if (index != -1)
        targetTab = fitsImages[index];
    else
    {
        foreach(FITSTab *tab, fitsImages)
        {
            undoStack = tab->getUndoStack();

            if (undoStack->isClean())
                continue;

            targetTab = tab;
            break;
        }
     }

    if (targetTab == NULL)
        return -1;

    int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStandardGuiItem::save(), KStandardGuiItem::discard() );
    if( ans == KMessageBox::Yes )
    {
            targetTab->saveFile();
            return 0;
    }
    else if( ans == KMessageBox::No )
    {
       fitsImages.removeOne(targetTab);
       delete targetTab;
       return 1;
    }

    return -1;
}

void FITSViewer::updateStatusBar(const QString &msg, FITSBar id)
{
   statusBar()->changeItem(msg, id);
}

void FITSViewer::ZoomIn()
{
    if (fitsImages.empty())
        return;

  fitsImages[fitsTab->currentIndex()]->ZoomIn();
}

void FITSViewer::ZoomOut()
{
    if (fitsImages.empty())
        return;

  fitsImages[fitsTab->currentIndex()]->ZoomOut();
}

void FITSViewer::ZoomDefault()
{
    if (fitsImages.empty())
        return;

  fitsImages[fitsTab->currentIndex()]->ZoomDefault();
}

void FITSViewer::updateAction(const QString &name, bool enable)
{
    QAction *toolAction = NULL;

    toolAction = actionCollection()->action(name);
    if (toolAction != NULL)
        toolAction->setEnabled (enable);
}

void FITSViewer::updateTabStatus(bool clean)
{
    if (fitsImages.empty())
        return;

  QString tabText = fitsImages[fitsTab->currentIndex()]->getCurrentURL()->fileName();

  fitsTab->setTabText(fitsTab->currentIndex(), clean ? tabText : tabText + "*");
}

void FITSViewer::closeTab(int index)
{
    if (fitsImages.empty())
        return;

    int status = saveUnsaved(index);

    FITSTab *tab = fitsImages[index];

    if (status != 1)
    {
        fitsImages.removeOne(tab);
        delete tab;
    }


}

#include "fitsviewer.moc"
