/**
 * @file
 * $Revision: 1.19 $
 * $Date: 2010/03/22 19:44:53 $
 *
 *   Unless noted otherwise, the portions of Isis written by the USGS are
 *   public domain. See individual third-party library and package descriptions
 *   for intellectual property information, user agreements, and related
 *   information.
 *
 *   Although Isis has been used by the USGS, no warranty, expressed or
 *   implied, is made by the USGS as to the accuracy and functioning of such
 *   software and related material nor shall the fact of distribution
 *   constitute any such warranty, and no responsibility is assumed by the
 *   USGS in connection therewith.
 *
 *   For additional information, launch
 *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
 *   in a browser or see the Privacy &amp; Disclaimers page on the Isis website,
 *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
 *   http://www.usgs.gov/privacy.html.
 */
#include "JigsawWorkOrder.h"

#include <QtDebug>

#include <QDialog>
#include <QDockWidget>
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>

#include "BundleSolutionInfo.h"
#include "Control.h"
#include "Directory.h"
#include "JigsawDialog.h"
#include "JigsawSetupDialog.h"
#include "Project.h"

namespace Isis {

  /**
   * @brief Constructs a JigsawWorkOrder.
   *
   * This creates a work order to run bundle adjustments. Note that right now,
   * the design implemented means that this work order finishes after a JigsawDialog
   * is shown. This work order is synchronous and not undoable. Note is is synchronous
   * in that it simply displays a dialog. The actual bundle adjust is threaded.
   *
   * @see JigsawDialog
   *
   * @param project The Project that we are going to Bundle Adjust
   *
   */
  JigsawWorkOrder::JigsawWorkOrder(Project *project) :
      WorkOrder(project) {
    // This work order is synchronous and not undoable
    m_isUndoable = false;
    QAction::setText(tr("&Bundle Adjustment..."));
    QUndoCommand::setText("&Bundle Adjustment...");
    QString hoverText = "Runs a bundle adjustment. ";
    hoverText += "You must import a control net and images before you can run a bundle adjustment.";
    QAction::setToolTip(hoverText);
  }


  /**
   * @brief Copy constructor.
   *
   * Copies the state of another JigsawWorkOrder.
   */
  JigsawWorkOrder::JigsawWorkOrder(const JigsawWorkOrder &other) :
      WorkOrder(other) {
    m_bundleSettings = other.m_bundleSettings;
  }


  /**
   * Destructor
   */
  JigsawWorkOrder::~JigsawWorkOrder() {
  }


  /**
   * This method clones the JigsawViewWorkOrder
   *
   * @return JigsawWorkOrder* Returns a clone of the JigsawWorkOrder
   */
  JigsawWorkOrder *JigsawWorkOrder::clone() const {
    return new JigsawWorkOrder(*this);
  }


  /**
   * This check is used by Directory::supportedActions(DataType data).
   *
   * @return bool True if the number of project controls and the number of project images
   *         is greater than 0.
   */
  bool JigsawWorkOrder::isExecutable() {
    return (project()->controls().size() > 0 && project()->images().size() > 0);
  }


  /**
   * If WorkOrder:setupExecution() returns true, this creates a setup dialog.
   *
   * When the setup is successful (i.e. the user does not cancel the dialog), this work order
   * will be read to execute.
   *
   * @return bool Returns True if setup dialog for the bundle adjustment is successful.
   */
  bool JigsawWorkOrder::setupExecution() {
    bool success = WorkOrder::setupExecution();

    if (success) {

      QStringList internalData;

      // Create a blocking setup dialog initially and check to make sure we get valid info
      JigsawSetupDialog setup(project());
      if (setup.exec() == QDialog::Accepted) {
        m_bundleSettings = setup.bundleSettings();
        if (setup.selectedControl()) {
          internalData.append(QStringList(setup.selectedControl()->id()));
        }
        // This else should not happen, the work order should be disabled if there are no controls.
        else {
          QString msg = "Cannot run a bundle adjustment without a selected control network.";
          QMessageBox::critical(qobject_cast<QWidget *>(parent()), "Error", msg);
          success = false;
        }
        // set output control network file name
        if (!setup.outputControlName().isEmpty()) {
          internalData.append(setup.outputControlName());
        }
        else {
          QString msg = "You must set an output control network filename.";
          QMessageBox::critical(qobject_cast<QWidget *>(parent()), "Error", msg);
          success = false;
        }
      }
      else {
        success = false;
      }
      setInternalData(internalData);
    }

    return success;
  }


 /**
  * This method returns true if other depends on a JigsawWorkOrder
  *
  * @param order the WorkOrder we want to check for dependancies
  *
  * @return bool True if WorkOrder depends on a JigsawWorkOrder
  *
  */
  bool JigsawWorkOrder::dependsOn(WorkOrder *other) const {
    // depend on types of ourselves.
    return dynamic_cast<JigsawWorkOrder *>(other);
  }


  /**
   * Executes the work order by creating a jigsaw dialog that allows the user to run or re-setup
   * the settings for a bundle adjustment.
   *
   * @see WorkOrder::execute()
   */
  void JigsawWorkOrder::execute() {

    Project *proj = project();

    // Get the selected control and bundle settings and give them to the JigsawDialog for now.
    Control *selectedControl = proj->control(internalData().first());

    QString outputControlFileName = internalData().at(1);

    JigsawDialog *runDialog = new JigsawDialog(project(), m_bundleSettings, selectedControl,
                                               outputControlFileName);
    runDialog->setAttribute(Qt::WA_DeleteOnClose);
    runDialog->show();
  }
}
