double MosaicControlNetTool::maxMovementColorResidualMagnitude() const {
    double result = Null;

    if (!IsSpecial(m_residualMagnitude))
      result = m_residualMagnitude;

    return result;
  }

#include "MosaicControlNetTool.h"

#include <iostream>

#include <QGraphicsScene>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLabel>
#include <QMenu>
#include <QPointF>
#include <QMessageBox>
#include <QPushButton>

#include "ChipViewportsWidget.h"
#include "Control.h"
#include "ControlList.h"
#include "ControlNet.h"
#include "ControlNetGraphicsItem.h"
#include "ControlPoint.h"
#include "ControlPointEditView.h"
#include "ControlPointEditWidget.h"
#include "Directory.h"
#include "FileDialog.h"
#include "FileName.h"
#include "IException.h"
#include "Image.h"
#include "ImageDisplayProperties.h"
#include "IString.h"
#include "Latitude.h"
#include "Longitude.h"
#include "MosaicControlNetToolMovementConfigDialog.h"
#include "MosaicSceneItem.h"
#include "MosaicSceneWidget.h"
#include "MosaicGraphicsView.h"
#include "Project.h"
#include "Projection.h"
#include "PvlObject.h"
#include "SpecialPixel.h"
#include "TProjection.h"

namespace Isis {

  /**
   * MosaicControlNetTool constructor
   *
   * @param parent
   */
  MosaicControlNetTool::MosaicControlNetTool(MosaicSceneWidget *scene) :
      MosaicTool(scene) {
    m_controlNet = NULL;
    m_controlNetGraphics = NULL;
    m_loadControlNetButton = NULL;
    m_displayControlNetButton = NULL;
    m_displayConnectivity = NULL;
    m_closeNetwork = NULL;
    m_controlNetFileLabel = NULL;
    m_randomizeColors = NULL;

    m_movementArrowColorSource = NoMovement;
    m_measureCount = 10;
    m_residualMagnitude = 5.0;

    // Create the action buttons

    m_displayControlNetButton = new QPushButton("Display");
    m_displayControlNetButton->setCheckable(true);
    m_displayControlNetButton->setEnabled(false);
    m_displayControlNetButton->setToolTip("Toggle the visibility of the "
        "control points and movement arrows in the network.");
    connect(m_displayControlNetButton, SIGNAL(clicked()), this, SLOT(displayControlNet()));
    connect(m_displayControlNetButton, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

    m_displayConnectivity = new QPushButton("Color Islands");
    m_displayConnectivity->setToolTip("Color cubes the same if the control "
        "network has a connection between them");
    connect(m_displayConnectivity, SIGNAL(clicked()), this, SLOT(displayConnectivity()));
    connect(m_displayConnectivity, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));
    m_displayConnectivity->setEnabled(false);

    m_randomizeColors = new QPushButton("Color Images");
    m_randomizeColors->setToolTip("Color all cubes differently");
    connect(m_randomizeColors, SIGNAL(clicked()), this, SLOT(randomizeColors()));
    connect(m_randomizeColors, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

    m_configMovement = new QPushButton(tr("Configure Movement Display"));
    m_configMovement->setToolTip(tr("Show arrow from the apriori surface point to "
        "the adjusted surface point for each control point with this "
        "information"));
    connect(m_configMovement, SIGNAL(clicked()), this, SLOT(configMovement()));
    connect(m_configMovement, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

    //  MosaicSceneWidget could be NULL because the MosaicSceneWidget::getControlNetHelp and
    //  MosaicSceneWidget::getGridHelp create tools passing in Null for the Widget.
    //  Why can't the getControlNetHelp and getGridHelp pass in the current MosaicSceneWidget?
    if (getWidget() && !getWidget()->directory()) {
      m_closeNetwork = new QPushButton("Close Network");
      m_closeNetwork->setEnabled(false);
      m_closeNetwork->setVisible(false);
      m_closeNetwork->setToolTip("Close the currently open control network");
      connect(m_closeNetwork, SIGNAL(clicked()), this, SLOT(closeNetwork()));
      connect(m_closeNetwork, SIGNAL(destroyed(QObject *)),
              this, SLOT(objectDestroyed(QObject *)));

      m_loadControlNetButton = new QPushButton("Open Network");
      m_loadControlNetButton->setToolTip("Open and load a control network");
      connect(m_loadControlNetButton, SIGNAL(clicked()),
              this, SLOT(openControlNet()));
      connect(m_loadControlNetButton, SIGNAL(destroyed(QObject *)),
              this, SLOT(objectDestroyed(QObject *)));

      connect(this, SIGNAL(controlPointSelected(ControlPoint *)),
              getWidget(), SIGNAL(controlPointSelected(ControlPoint *)));
    }

    m_controlNetFileLabel = new QLabel;
    m_controlNetFileLabel->setToolTip("The filename of the currently open "
        "control network");
    connect(m_controlNetFileLabel, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

  }

  MosaicControlNetTool::~MosaicControlNetTool() {
    m_controlNetGraphics = NULL; // the scene cleans/cleaned this up

    delete m_loadControlNetButton;
    delete m_displayControlNetButton;
    delete m_displayConnectivity;
    delete m_configMovement;
    delete m_closeNetwork;
    delete m_controlNetFileLabel;
    delete m_randomizeColors;

    closeNetwork();
  }

  Image *MosaicControlNetTool::takeImage(
      QString sn, ImageList &images) {
    if (m_controlNet && m_controlNetGraphics) {
      QString filename = m_controlNetGraphics->snToFileName(sn);

      for(int i = 0; i < images.size(); i++) {
        Image *image = images[i];

        if (image->fileName() == filename) {
          return images.takeAt(i);
        }
      }
    }

    return NULL;
  }

  PvlObject MosaicControlNetTool::toPvl() const {
    PvlObject obj(projectPvlObjectName());

    obj += PvlKeyword("FileName", m_controlNetFile);
    obj += PvlKeyword("Visible",
        Isis::toString((int)(m_controlNetGraphics && m_controlNetGraphics->isVisible())));
    obj += PvlKeyword("Movement", toString(m_movementArrowColorSource));

    if (maxMovementColorMeasureCount() != -1) {
      obj += PvlKeyword("MovementColorMaxMeasureCount", Isis::toString(m_measureCount));
    }

    if (maxMovementColorResidualMagnitude() != Null) {
      obj += PvlKeyword("MovementColorMaxResidualMagnitude",
                        Isis::toString(m_residualMagnitude));
    }

    return obj;
  }

  void MosaicControlNetTool::fromPvl(const PvlObject &obj) {
    m_controlNetFile = obj["FileName"][0];
    if (m_controlNetFile == "Null")
      m_controlNetFile = "";

    if (obj.hasKeyword("Movement")) {
      m_movementArrowColorSource = fromMovementColorSourceString(obj["Movement"]);
    }

    if (obj.hasKeyword("MovementColorMaxMeasureCount")) {
      m_measureCount = toInt(obj["MovementColorMaxMeasureCount"][0]);
    }

    if (obj.hasKeyword("MovementColorMaxResidualMagnitude")) {
      m_residualMagnitude = toDouble(obj["MovementColorMaxResidualMagnitude"][0]);
    }

    loadNetwork();

    if (m_controlNetGraphics && m_displayControlNetButton) {
      m_displayControlNetButton->setChecked( toBool(obj["Visible"][0]) );
      displayControlNet();
    }
  }

  QString MosaicControlNetTool::projectPvlObjectName() const {
    return "MosaicControlNetTool";
  }

  /**
   * Define how the movement arrows should be drawn. This includes if movement arrows should be
   *   drawn, what criteria should be used, and how to stretch (where to transition colors) the
   *   arrows.
   *
   * NOTE: This is just a quick implementation and is probably not designed correctly. This is
   *       subject to change.
   *
   * @param colorSource If and how to draw and color the arrows
   * @param maxMeasureCount The measure count to become fully colored
   * @param maxResidualMagnitude The max residual magnitude to become fully colored
   */
  void MosaicControlNetTool::setMovementArrowColorSource(MovementColorSource colorSource,
      int maxMeasureCount, double maxResidualMagnitude) {
    m_movementArrowColorSource = colorSource;
    m_measureCount = maxMeasureCount;
    m_residualMagnitude = maxResidualMagnitude;

    if (m_controlNetGraphics) {
      m_controlNetGraphics->setArrowsVisible(m_movementArrowColorSource != NoMovement,
          m_movementArrowColorSource == MeasureCount, m_measureCount,
          m_movementArrowColorSource == ResidualMagnitude, m_residualMagnitude);
    }
  }

  /**
   * Get the current setting for the movement arrows.
   */
  MosaicControlNetTool::MovementColorSource MosaicControlNetTool::movementArrowColorSource() const {
    return m_movementArrowColorSource;
  }

  /**
   * Get the current measure count to become fully colored. This will return -1 if it's undefined.
   */
  int MosaicControlNetTool::maxMovementColorMeasureCount() const {
    int result = -1;

    if (m_measureCount > 0)
      result = m_measureCount;

    return result;
  }

  /**
   * Get the current max. residual magnitude to become fully colored. This will return Null if it's
   *   undefined.
   */

/**
   * Convert a MovementColorSource to a string for serialization purposes.
   */
  QString MosaicControlNetTool::toString(MovementColorSource source) {
    QString result;

    switch (source) {
      case NoMovement:
        result = "No movement arrows";
        break;

      case NoColor:
        result = "Black movement arrows";
        break;

      case MeasureCount:
        result = "Movement arrows colored by measure count";
        break;

      case ResidualMagnitude:
        result = "Movement arrows colored by residual magnitude";
        break;
    }

    return result;
  }

  /**
   * Convert a string back to a MovementColorSource (for serialization purposes).
   */
  MosaicControlNetTool::MovementColorSource MosaicControlNetTool::fromMovementColorSourceString(
      QString string) {
    MovementColorSource result = NoMovement;

    for (int i = 0; i < NUM_MOVEMENT_COLOR_SOURCE_VALUES; i++) {
      if (string.toLower() == toString((MovementColorSource)i).toLower()) {
        result = (MovementColorSource)i;
      }
    }

    return result;
  }

  /**
   * Adds the action to the toolpad.
   *
   * @param toolpad
   *
   * @return QAction*
   */
  QAction *MosaicControlNetTool::getPrimaryAction() {
    QAction *action = new QAction(this);
    action->setIcon(getIcon("HILLBLU_molecola.png"));
    action->setToolTip("Control Net (c)");
    action->setShortcut(Qt::Key_C);
    QString text  =
      "Function:  Display and analyze a control network

"
      "This tool shows you all of the control points in your network for "
      "which a latitude/longitude can be calculated. The control points are "
      "shown as color-coded '+' marks. The control points have a right-click "
      "menu and information about them can be seen just by hovering over them."
      "
Shortcut:  c
 ";
    action->setWhatsThis(text);
    return action;
  }

  QWidget *MosaicControlNetTool::getToolBarWidget() {
    // Put the buttons in a horizontal orientation
    QHBoxLayout *actionLayout = new QHBoxLayout();

    if (m_displayControlNetButton)
      actionLayout->addWidget(m_displayControlNetButton);

    if (m_displayConnectivity)
      actionLayout->addWidget(m_displayConnectivity);

    if (m_randomizeColors)
      actionLayout->addWidget(m_randomizeColors);

    if (m_configMovement)
      actionLayout->addWidget(m_configMovement);

    if (m_closeNetwork)
      actionLayout->addWidget(m_closeNetwork);

    if (m_loadControlNetButton)
      actionLayout->addWidget(m_loadControlNetButton);

    if (m_controlNetFileLabel)
      actionLayout->addWidget(m_controlNetFileLabel);

    actionLayout->setMargin(0);

    QWidget *toolBarWidget = new QWidget;
    toolBarWidget->setLayout(actionLayout);

    return toolBarWidget;
  }

  /**
   * Bring up a movement arrow configuration dialog
   */
  void MosaicControlNetTool::configMovement() {
    MosaicControlNetToolMovementConfigDialog *configDialog =
        new MosaicControlNetToolMovementConfigDialog(this, qobject_cast<QWidget *>(parent()));
    configDialog->setAttribute(Qt::WA_DeleteOnClose);
    configDialog->show();
  }

  /**
   * This slot opens and reopens this tool properly
   */
  void MosaicControlNetTool::updateTool() {
    if (isActive()) {
      getWidget()->setCubesSelectable(true);
      getWidget()->getView()->setContextMenuPolicy(Qt::NoContextMenu);
      getWidget()->enableRubberBand(false);
    }
    else {
      getWidget()->setCubesSelectable(true);
      getWidget()->getView()->setContextMenuPolicy(Qt::DefaultContextMenu);
      getWidget()->enableRubberBand(false);
    }
    if (isActive() && m_controlNetFile == "") {
      openControlNet();
    }
  }

  /**
   * The user toggled the cnet visibility - re-sync the graphics item visibility
   *   with the action.
   */
  void MosaicControlNetTool::displayControlNet() {
    if (m_controlNetGraphics && m_displayControlNetButton)
      m_controlNetGraphics->setVisible( m_displayControlNetButton->isChecked() );
  }

  /**
   * Displays the connectivity of Control Points
   *
   */
  void MosaicControlNetTool::displayConnectivity() {
    if (m_controlNet) {
      ImageList images = getWidget()->images();

      QList<QColor> colorsUsed;

      QList< QList<QString> > serialConns =
          m_controlNet->GetSerialConnections();

      QList<QString> island;
      foreach(island, serialConns) {
        QColor color;

        QString cubeSn;
        foreach(cubeSn, island) {
          Image *image = takeImage(cubeSn, images);

          if (image) {
            while(!color.isValid()) {
              QColor displayColor = image->displayProperties()->getValue(
                  ImageDisplayProperties::Color).value<QColor>();

              if (colorsUsed.indexOf(displayColor) == -1) {
                colorsUsed.append(displayColor);
                color = displayColor;
              }
              else {
                QColor ranColor = ImageDisplayProperties::randomColor();

                if (colorsUsed.indexOf(ranColor) == -1) {
                  colorsUsed.append(ranColor);
                  color = ranColor;
                }
              }
            }

            image->displayProperties()->setColor(color);
          }
        }
      }
    }
  }

  /**
   * Slot used to re-create the graphics items that depict the control points
   *
   */
  void MosaicControlNetTool::rebuildPointGraphics() {
    if (m_controlNetGraphics) {
      m_controlNetGraphics->buildChildren();
    }
  }

  void MosaicControlNetTool::displayChangedControlPoint(QString changedControlPoint) {
    m_controlNetGraphics->clearControlPointGraphicsItem(changedControlPoint);
    m_controlNetGraphics->buildChildren();
  }

  void MosaicControlNetTool::displayNewControlPoint(QString newControlPoint) {
    m_controlNetGraphics->buildChildren();
  }

/*
 * remove deleted point from display
 * removeControlPointFromDisplay
 */
  void MosaicControlNetTool::displayUponControlPointDeletion() {
    m_controlNetGraphics->clearControlPointGraphicsItem( QString("Point ID") );
    m_controlNetGraphics->buildChildren();
  }

  /**
   * Close the open network, if one is open. m_controlNetFile is set to an
   *   empty string.
   */
  void MosaicControlNetTool::closeNetwork() {
    if (m_controlNetGraphics) {
      getWidget()->getScene()->removeItem(m_controlNetGraphics);
      delete m_controlNetGraphics;
    }

    // If qmos (not ipce) application
    if (m_controlNet && !getWidget()->directory()) {
      delete m_controlNet;
      m_controlNet = NULL;
    }

    if (m_displayControlNetButton)
      m_displayControlNetButton->setChecked(false);

    if (m_displayControlNetButton)
      m_displayControlNetButton->setEnabled(false);

    if (m_displayConnectivity)
      m_displayConnectivity->setEnabled(false);

    if (m_closeNetwork) {
      m_closeNetwork->setEnabled(false);
      m_closeNetwork->setVisible(false);
    }

    if (m_loadControlNetButton) {
      m_loadControlNetButton->setEnabled(true);
      m_loadControlNetButton->setVisible(true);
    }

    if (m_controlNetFileLabel)
      m_controlNetFileLabel->setText("");

    m_controlNetFile = "";
  }

  /**
   * An object was destroyed, NULL it out.
   */
  void MosaicControlNetTool::objectDestroyed(QObject *obj) {
    if (obj == m_loadControlNetButton)
      m_loadControlNetButton = NULL;
    else if (obj == m_displayControlNetButton)
      m_displayControlNetButton = NULL;
    else if (obj == m_displayConnectivity)
      m_displayConnectivity = NULL;
    else if (obj == m_closeNetwork)
      m_closeNetwork = NULL;
    else if (obj == m_controlNetGraphics)
      m_controlNetGraphics = NULL;
    else if (obj == m_configMovement)
      m_configMovement = NULL;
    else if (obj == m_controlNetFileLabel)
      m_controlNetFileLabel = NULL;
    else if (obj == m_randomizeColors)
      m_randomizeColors = NULL;
  }

  /**
   * Loads a control net from a file
   *
   */
  void MosaicControlNetTool::openControlNet() {

    // If qmos (not ipce) application
    if (!getWidget()->directory()) {
      // Bring up a file dialog for user to select their cnet file.
      QString netFile = FileDialog::getOpenFileName(getWidget(),
                        "Select Control Net. File",
                        QDir::current().dirName() + "/",
                        "Control Networks (*.net);;All Files (*.*)");

      // if the file is not empty attempt to load in the control points
      // for each mosaic item
      if (!netFile.isEmpty()) {
        FileName controlNetFile(netFile);
        m_controlNetFile = controlNetFile.expanded();
      }
    }
    else {
      //  If ipce application, there must be an active control net and active image list.
      if (!getWidget()->directory()->project()->activeControl()) {
        // Error and return to Select Tool
        QString message = "No active control network chosen.  Choose an active image list then an"
                          "active control network on the project tree.\n";
        QMessageBox::critical(getWidget(), "Error", message);
        return;
      }
      m_controlNetFile = getWidget()->directory()->project()->activeControl()->fileName();
    }

    if (!m_controlNetFile.isEmpty()) {
      loadNetwork();
      if (m_displayControlNetButton) m_displayControlNetButton->setChecked(true);
    }
  }

  /**
   * Load m_controlNetFile into memory - this will re-load the network if it's
   *   already open.
   */
  void MosaicControlNetTool::loadNetwork() {
    QString netFile = m_controlNetFile;
    closeNetwork();
    m_controlNetFile = netFile;

    if (m_controlNetFile.size() > 0) {
      try {
        //  If qmos application create new control net from chosen filename
        if (!getWidget()->directory()) {
          m_controlNetFileLabel->setText( QFileInfo(netFile).fileName() );
          m_controlNet = new ControlNet(m_controlNetFile);
        }
        //  If ipce application, get the active control net from the project.  This control has
        //  already been read into memory.
        else {
          m_controlNet = getWidget()->directory()->project()->activeControl()->controlNet();
          m_controlNetFileLabel->setText( QFileInfo(
              getWidget()->directory()->project()->activeControl()->fileName()).fileName() );
        }
        m_controlNetGraphics = new ControlNetGraphicsItem(m_controlNet,
            getWidget());

        setMovementArrowColorSource(m_movementArrowColorSource,
                                    m_measureCount, m_residualMagnitude);

        connect(m_controlNetGraphics, SIGNAL(destroyed(QObject *)),
                this, SLOT(objectDestroyed(QObject *)));

      }
      catch(IException &e) {
        QString message = "Invalid control network.\n";
        message += e.toString();
        QMessageBox::information(getWidget(), "Error", message);
        return;
      }

      if (m_displayControlNetButton)
        m_displayControlNetButton->setEnabled(true);

      if (m_displayConnectivity)
        m_displayConnectivity->setEnabled(true);

      if (m_closeNetwork) {
        m_closeNetwork->setEnabled(true);
        m_closeNetwork->setVisible(true);
      }

      if (m_loadControlNetButton) {
        m_loadControlNetButton->setEnabled(false);
        m_loadControlNetButton->setVisible(false);
      }
    }
  }

  void MosaicControlNetTool::randomizeColors() {
    foreach (Image *image, getWidget()->images()) {
      image->displayProperties()->setColor(ImageDisplayProperties::randomColor());
    }
  }

  // TODO: why did we remove the error checks?
  void MosaicControlNetTool::mouseButtonRelease(QPointF point, Qt::MouseButton mouseButton) {
    if (!isActive() || !m_controlNet) return;

    // If not IPCE, return, qmos does not use this code
    if (!getWidget()->directory()) return;

    ControlPoint *cp = NULL;

    //  Modify closest control point
    if (mouseButton == Qt::LeftButton) {

      //  Find closes point
      cp = m_controlNetGraphics->findClosestControlPoint(point);

      // TODO  move the emit into the if so that we do not need to do early return.
      // The user did not click close enough to a point for findClosestControlPoint to find a point.
      if (!cp) {
        return;
      }
      emit modifyControlPoint(cp);
    }
    else if (mouseButton == Qt::MidButton) {

      cp = m_controlNetGraphics->findClosestControlPoint(point);
      if (!cp) {
      // TODO Figure out how to get this error message in the right place
        QString message = "No points exist for deleting. Create points "
                          "using the right mouse button.";
        QMessageBox::warning(getWidget(), "Warning", message);
        return;
      }

      emit deleteControlPoint(cp);
      //       deletePoint(point); // what should happen here?
    }

    //   Create control point at cursor location
    else if (mouseButton == Qt::RightButton) {
      //  TODO  For now simply take the first image in the list
      // Find all Images under mouse position ... already doing this with the foreach loop?
      //  TODO  should this imagesUnderMousePosition be implemented in MosaicSceneWidget?
      //      Similar code is found in MosaicSceneWidget::contextMenuEvent.
      ImageList imagesAtMousePosition;
      QList<QGraphicsItem *> itemsAtMousePosition = getWidget()->getScene()->items(point);
      foreach (QGraphicsItem *graphicsItem, itemsAtMousePosition) {
        MosaicSceneItem *sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem);

        if (!sceneImageItem) {
          sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem->parentItem());
        }

        if (sceneImageItem && sceneImageItem->image()) {
          imagesAtMousePosition.append(sceneImageItem->image());
        }
      }

      if (imagesAtMousePosition.count()) {
        Projection *proj = getWidget()->getProjection();
        Projection::ProjectionType ptype = proj->projectionType();

        if (ptype == Projection::Triaxial) {
          TProjection *tproj = (TProjection *) proj;
          if (tproj && getWidget()->getView()->sceneRect().contains(point)) {
            if ( tproj->SetCoordinate( point.x(), -1 * point.y() ) ) {
              //  Create Latitude and Longitude objects so there is a signature different from
              Latitude lat(tproj->Latitude(), Angle::Degrees);
              Longitude lon(tproj->Longitude(), Angle::Degrees);
              emit createControlPoint(lat.degrees(), lon.degrees());
            }
          }
        }
      }
    }
  }
}


switch (source) {
      case NoMovement:
        result = "No movement arrows";
        break;

      case NoColor:
        result = "Black movement arrows";
        break;

      case MeasureCount:
        result = "Movement arrows colored by measure count";
        break;

      case ResidualMagnitude:
        result = "Movement arrows colored by residual magnitude";
        break;
    }

#include "MosaicControlNetTool.h"

#include <iostream>

#include <QGraphicsScene>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLabel>
#include <QMenu>
#include <QPointF>
#include <QMessageBox>
#include <QPushButton>

#include "ChipViewportsWidget.h"
#include "Control.h"
#include "ControlList.h"
#include "ControlNet.h"
#include "ControlNetGraphicsItem.h"
#include "ControlPoint.h"
#include "ControlPointEditView.h"
#include "ControlPointEditWidget.h"
#include "Directory.h"
#include "FileDialog.h"
#include "FileName.h"
#include "IException.h"
#include "Image.h"
#include "ImageDisplayProperties.h"
#include "IString.h"
#include "Latitude.h"
#include "Longitude.h"
#include "MosaicControlNetToolMovementConfigDialog.h"
#include "MosaicSceneItem.h"
#include "MosaicSceneWidget.h"
#include "MosaicGraphicsView.h"
#include "Project.h"
#include "Projection.h"
#include "PvlObject.h"
#include "SpecialPixel.h"
#include "TProjection.h"

namespace Isis {

  /**
   * MosaicControlNetTool constructor
   *
   * @param parent
   */
  MosaicControlNetTool::MosaicControlNetTool(MosaicSceneWidget *scene) :
      MosaicTool(scene) {
    m_controlNet = NULL;
    m_controlNetGraphics = NULL;
    m_loadControlNetButton = NULL;
    m_displayControlNetButton = NULL;
    m_displayConnectivity = NULL;
    m_closeNetwork = NULL;
    m_controlNetFileLabel = NULL;
    m_randomizeColors = NULL;

    m_movementArrowColorSource = NoMovement;
    m_measureCount = 10;
    m_residualMagnitude = 5.0;

    // Create the action buttons

    m_displayControlNetButton = new QPushButton("Display");
    m_displayControlNetButton->setCheckable(true);
    m_displayControlNetButton->setEnabled(false);
    m_displayControlNetButton->setToolTip("Toggle the visibility of the "
        "control points and movement arrows in the network.");
    connect(m_displayControlNetButton, SIGNAL(clicked()), this, SLOT(displayControlNet()));
    connect(m_displayControlNetButton, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

    m_displayConnectivity = new QPushButton("Color Islands");
    m_displayConnectivity->setToolTip("Color cubes the same if the control "
        "network has a connection between them");
    connect(m_displayConnectivity, SIGNAL(clicked()), this, SLOT(displayConnectivity()));
    connect(m_displayConnectivity, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));
    m_displayConnectivity->setEnabled(false);

    m_randomizeColors = new QPushButton("Color Images");
    m_randomizeColors->setToolTip("Color all cubes differently");
    connect(m_randomizeColors, SIGNAL(clicked()), this, SLOT(randomizeColors()));
    connect(m_randomizeColors, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

    m_configMovement = new QPushButton(tr("Configure Movement Display"));
    m_configMovement->setToolTip(tr("Show arrow from the apriori surface point to "
        "the adjusted surface point for each control point with this "
        "information"));
    connect(m_configMovement, SIGNAL(clicked()), this, SLOT(configMovement()));
    connect(m_configMovement, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

    //  MosaicSceneWidget could be NULL because the MosaicSceneWidget::getControlNetHelp and
    //  MosaicSceneWidget::getGridHelp create tools passing in Null for the Widget.
    //  Why can't the getControlNetHelp and getGridHelp pass in the current MosaicSceneWidget?
    if (getWidget() && !getWidget()->directory()) {
      m_closeNetwork = new QPushButton("Close Network");
      m_closeNetwork->setEnabled(false);
      m_closeNetwork->setVisible(false);
      m_closeNetwork->setToolTip("Close the currently open control network");
      connect(m_closeNetwork, SIGNAL(clicked()), this, SLOT(closeNetwork()));
      connect(m_closeNetwork, SIGNAL(destroyed(QObject *)),
              this, SLOT(objectDestroyed(QObject *)));

      m_loadControlNetButton = new QPushButton("Open Network");
      m_loadControlNetButton->setToolTip("Open and load a control network");
      connect(m_loadControlNetButton, SIGNAL(clicked()),
              this, SLOT(openControlNet()));
      connect(m_loadControlNetButton, SIGNAL(destroyed(QObject *)),
              this, SLOT(objectDestroyed(QObject *)));

      connect(this, SIGNAL(controlPointSelected(ControlPoint *)),
              getWidget(), SIGNAL(controlPointSelected(ControlPoint *)));
    }

    m_controlNetFileLabel = new QLabel;
    m_controlNetFileLabel->setToolTip("The filename of the currently open "
        "control network");
    connect(m_controlNetFileLabel, SIGNAL(destroyed(QObject *)),
            this, SLOT(objectDestroyed(QObject *)));

  }

  MosaicControlNetTool::~MosaicControlNetTool() {
    m_controlNetGraphics = NULL; // the scene cleans/cleaned this up

    delete m_loadControlNetButton;
    delete m_displayControlNetButton;
    delete m_displayConnectivity;
    delete m_configMovement;
    delete m_closeNetwork;
    delete m_controlNetFileLabel;
    delete m_randomizeColors;

    closeNetwork();
  }

  Image *MosaicControlNetTool::takeImage(
      QString sn, ImageList &images) {
    if (m_controlNet && m_controlNetGraphics) {
      QString filename = m_controlNetGraphics->snToFileName(sn);

      for(int i = 0; i < images.size(); i++) {
        Image *image = images[i];

        if (image->fileName() == filename) {
          return images.takeAt(i);
        }
      }
    }

    return NULL;
  }

  PvlObject MosaicControlNetTool::toPvl() const {
    PvlObject obj(projectPvlObjectName());

    obj += PvlKeyword("FileName", m_controlNetFile);
    obj += PvlKeyword("Visible",
        Isis::toString((int)(m_controlNetGraphics && m_controlNetGraphics->isVisible())));
    obj += PvlKeyword("Movement", toString(m_movementArrowColorSource));

    if (maxMovementColorMeasureCount() != -1) {
      obj += PvlKeyword("MovementColorMaxMeasureCount", Isis::toString(m_measureCount));
    }

    if (maxMovementColorResidualMagnitude() != Null) {
      obj += PvlKeyword("MovementColorMaxResidualMagnitude",
                        Isis::toString(m_residualMagnitude));
    }

    return obj;
  }

  void MosaicControlNetTool::fromPvl(const PvlObject &obj) {
    m_controlNetFile = obj["FileName"][0];
    if (m_controlNetFile == "Null")
      m_controlNetFile = "";

    if (obj.hasKeyword("Movement")) {
      m_movementArrowColorSource = fromMovementColorSourceString(obj["Movement"]);
    }

    if (obj.hasKeyword("MovementColorMaxMeasureCount")) {
      m_measureCount = toInt(obj["MovementColorMaxMeasureCount"][0]);
    }

    if (obj.hasKeyword("MovementColorMaxResidualMagnitude")) {
      m_residualMagnitude = toDouble(obj["MovementColorMaxResidualMagnitude"][0]);
    }

    loadNetwork();

    if (m_controlNetGraphics && m_displayControlNetButton) {
      m_displayControlNetButton->setChecked( toBool(obj["Visible"][0]) );
      displayControlNet();
    }
  }

  QString MosaicControlNetTool::projectPvlObjectName() const {
    return "MosaicControlNetTool";
  }

  /**
   * Define how the movement arrows should be drawn. This includes if movement arrows should be
   *   drawn, what criteria should be used, and how to stretch (where to transition colors) the
   *   arrows.
   *
   * NOTE: This is just a quick implementation and is probably not designed correctly. This is
   *       subject to change.
   *
   * @param colorSource If and how to draw and color the arrows
   * @param maxMeasureCount The measure count to become fully colored
   * @param maxResidualMagnitude The max residual magnitude to become fully colored
   */
  void MosaicControlNetTool::setMovementArrowColorSource(MovementColorSource colorSource,
      int maxMeasureCount, double maxResidualMagnitude) {
    m_movementArrowColorSource = colorSource;
    m_measureCount = maxMeasureCount;
    m_residualMagnitude = maxResidualMagnitude;

    if (m_controlNetGraphics) {
      m_controlNetGraphics->setArrowsVisible(m_movementArrowColorSource != NoMovement,
          m_movementArrowColorSource == MeasureCount, m_measureCount,
          m_movementArrowColorSource == ResidualMagnitude, m_residualMagnitude);
    }
  }

  /**
   * Get the current setting for the movement arrows.
   */
  MosaicControlNetTool::MovementColorSource MosaicControlNetTool::movementArrowColorSource() const {
    return m_movementArrowColorSource;
  }

  /**
   * Get the current measure count to become fully colored. This will return -1 if it's undefined.
   */
  int MosaicControlNetTool::maxMovementColorMeasureCount() const {
    int result = -1;

    if (m_measureCount > 0)
      result = m_measureCount;

    return result;
  }

  /**
   * Get the current max. residual magnitude to become fully colored. This will return Null if it's
   *   undefined.
   */
  double MosaicControlNetTool::maxMovementColorResidualMagnitude() const {
    double result = Null;

    if (!IsSpecial(m_residualMagnitude))
      result = m_residualMagnitude;

    return result;
  }

  /**
   * Convert a MovementColorSource to a string for serialization purposes.
   */
  QString MosaicControlNetTool::toString(MovementColorSource source) {
    QString result;

return result;
  }

  /**
   * Convert a string back to a MovementColorSource (for serialization purposes).
   */
  MosaicControlNetTool::MovementColorSource MosaicControlNetTool::fromMovementColorSourceString(
      QString string) {
    MovementColorSource result = NoMovement;

    for (int i = 0; i < NUM_MOVEMENT_COLOR_SOURCE_VALUES; i++) {
      if (string.toLower() == toString((MovementColorSource)i).toLower()) {
        result = (MovementColorSource)i;
      }
    }

    return result;
  }

  /**
   * Adds the action to the toolpad.
   *
   * @param toolpad
   *
   * @return QAction*
   */
  QAction *MosaicControlNetTool::getPrimaryAction() {
    QAction *action = new QAction(this);
    action->setIcon(getIcon("HILLBLU_molecola.png"));
    action->setToolTip("Control Net (c)");
    action->setShortcut(Qt::Key_C);
    QString text  =
      "Function:  Display and analyze a control network

"
      "This tool shows you all of the control points in your network for "
      "which a latitude/longitude can be calculated. The control points are "
      "shown as color-coded '+' marks. The control points have a right-click "
      "menu and information about them can be seen just by hovering over them."
      "
Shortcut:  c
 ";
    action->setWhatsThis(text);
    return action;
  }

  QWidget *MosaicControlNetTool::getToolBarWidget() {
    // Put the buttons in a horizontal orientation
    QHBoxLayout *actionLayout = new QHBoxLayout();

    if (m_displayControlNetButton)
      actionLayout->addWidget(m_displayControlNetButton);

    if (m_displayConnectivity)
      actionLayout->addWidget(m_displayConnectivity);

    if (m_randomizeColors)
      actionLayout->addWidget(m_randomizeColors);

    if (m_configMovement)
      actionLayout->addWidget(m_configMovement);

    if (m_closeNetwork)
      actionLayout->addWidget(m_closeNetwork);

    if (m_loadControlNetButton)
      actionLayout->addWidget(m_loadControlNetButton);

    if (m_controlNetFileLabel)
      actionLayout->addWidget(m_controlNetFileLabel);

    actionLayout->setMargin(0);

    QWidget *toolBarWidget = new QWidget;
    toolBarWidget->setLayout(actionLayout);

    return toolBarWidget;
  }

  /**
   * Bring up a movement arrow configuration dialog
   */
  void MosaicControlNetTool::configMovement() {
    MosaicControlNetToolMovementConfigDialog *configDialog =
        new MosaicControlNetToolMovementConfigDialog(this, qobject_cast<QWidget *>(parent()));
    configDialog->setAttribute(Qt::WA_DeleteOnClose);
    configDialog->show();
  }

  /**
   * This slot opens and reopens this tool properly
   */
  void MosaicControlNetTool::updateTool() {
    if (isActive()) {
      getWidget()->setCubesSelectable(true);
      getWidget()->getView()->setContextMenuPolicy(Qt::NoContextMenu);
      getWidget()->enableRubberBand(false);
    }
    else {
      getWidget()->setCubesSelectable(true);
      getWidget()->getView()->setContextMenuPolicy(Qt::DefaultContextMenu);
      getWidget()->enableRubberBand(false);
    }
    if (isActive() && m_controlNetFile == "") {
      openControlNet();
    }
  }

  /**
   * The user toggled the cnet visibility - re-sync the graphics item visibility
   *   with the action.
   */
  void MosaicControlNetTool::displayControlNet() {
    if (m_controlNetGraphics && m_displayControlNetButton)
      m_controlNetGraphics->setVisible( m_displayControlNetButton->isChecked() );
  }

  /**
   * Displays the connectivity of Control Points
   *
   */
  void MosaicControlNetTool::displayConnectivity() {
    if (m_controlNet) {
      ImageList images = getWidget()->images();

      QList<QColor> colorsUsed;

      QList< QList<QString> > serialConns =
          m_controlNet->GetSerialConnections();

      QList<QString> island;
      foreach(island, serialConns) {
        QColor color;

        QString cubeSn;
        foreach(cubeSn, island) {
          Image *image = takeImage(cubeSn, images);

          if (image) {
            while(!color.isValid()) {
              QColor displayColor = image->displayProperties()->getValue(
                  ImageDisplayProperties::Color).value<QColor>();

              if (colorsUsed.indexOf(displayColor) == -1) {
                colorsUsed.append(displayColor);
                color = displayColor;
              }
              else {
                QColor ranColor = ImageDisplayProperties::randomColor();

                if (colorsUsed.indexOf(ranColor) == -1) {
                  colorsUsed.append(ranColor);
                  color = ranColor;
                }
              }
            }

            image->displayProperties()->setColor(color);
          }
        }
      }
    }
  }

  /**
   * Slot used to re-create the graphics items that depict the control points
   *
   */
  void MosaicControlNetTool::rebuildPointGraphics() {
    if (m_controlNetGraphics) {
      m_controlNetGraphics->buildChildren();
    }
  }

  void MosaicControlNetTool::displayChangedControlPoint(QString changedControlPoint) {
    m_controlNetGraphics->clearControlPointGraphicsItem(changedControlPoint);
    m_controlNetGraphics->buildChildren();
  }

  void MosaicControlNetTool::displayNewControlPoint(QString newControlPoint) {
    m_controlNetGraphics->buildChildren();
  }

/*
 * remove deleted point from display
 * removeControlPointFromDisplay
 */
  void MosaicControlNetTool::displayUponControlPointDeletion() {
    m_controlNetGraphics->clearControlPointGraphicsItem( QString("Point ID") );
    m_controlNetGraphics->buildChildren();
  }

  /**
   * Close the open network, if one is open. m_controlNetFile is set to an
   *   empty string.
   */
  void MosaicControlNetTool::closeNetwork() {
    if (m_controlNetGraphics) {
      getWidget()->getScene()->removeItem(m_controlNetGraphics);
      delete m_controlNetGraphics;
    }

    // If qmos (not ipce) application
    if (m_controlNet && !getWidget()->directory()) {
      delete m_controlNet;
      m_controlNet = NULL;
    }

    if (m_displayControlNetButton)
      m_displayControlNetButton->setChecked(false);

    if (m_displayControlNetButton)
      m_displayControlNetButton->setEnabled(false);

    if (m_displayConnectivity)
      m_displayConnectivity->setEnabled(false);

    if (m_closeNetwork) {
      m_closeNetwork->setEnabled(false);
      m_closeNetwork->setVisible(false);
    }

    if (m_loadControlNetButton) {
      m_loadControlNetButton->setEnabled(true);
      m_loadControlNetButton->setVisible(true);
    }

    if (m_controlNetFileLabel)
      m_controlNetFileLabel->setText("");

    m_controlNetFile = "";
  }

  /**
   * An object was destroyed, NULL it out.
   */
  void MosaicControlNetTool::objectDestroyed(QObject *obj) {
    if (obj == m_loadControlNetButton)
      m_loadControlNetButton = NULL;
    else if (obj == m_displayControlNetButton)
      m_displayControlNetButton = NULL;
    else if (obj == m_displayConnectivity)
      m_displayConnectivity = NULL;
    else if (obj == m_closeNetwork)
      m_closeNetwork = NULL;
    else if (obj == m_controlNetGraphics)
      m_controlNetGraphics = NULL;
    else if (obj == m_configMovement)
      m_configMovement = NULL;
    else if (obj == m_controlNetFileLabel)
      m_controlNetFileLabel = NULL;
    else if (obj == m_randomizeColors)
      m_randomizeColors = NULL;
  }

  /**
   * Loads a control net from a file
   *
   */
  void MosaicControlNetTool::openControlNet() {

    // If qmos (not ipce) application
    if (!getWidget()->directory()) {
      // Bring up a file dialog for user to select their cnet file.
      QString netFile = FileDialog::getOpenFileName(getWidget(),
                        "Select Control Net. File",
                        QDir::current().dirName() + "/",
                        "Control Networks (*.net);;All Files (*.*)");

      // if the file is not empty attempt to load in the control points
      // for each mosaic item
      if (!netFile.isEmpty()) {
        FileName controlNetFile(netFile);
        m_controlNetFile = controlNetFile.expanded();
      }
    }
    else {
      //  If ipce application, there must be an active control net and active image list.
      if (!getWidget()->directory()->project()->activeControl()) {
        // Error and return to Select Tool
        QString message = "No active control network chosen.  Choose an active image list then an"
                          "active control network on the project tree.\n";
        QMessageBox::critical(getWidget(), "Error", message);
        return;
      }
      m_controlNetFile = getWidget()->directory()->project()->activeControl()->fileName();
    }

    if (!m_controlNetFile.isEmpty()) {
      loadNetwork();
      if (m_displayControlNetButton) m_displayControlNetButton->setChecked(true);
    }
  }

  /**
   * Load m_controlNetFile into memory - this will re-load the network if it's
   *   already open.
   */
  void MosaicControlNetTool::loadNetwork() {
    QString netFile = m_controlNetFile;
    closeNetwork();
    m_controlNetFile = netFile;

    if (m_controlNetFile.size() > 0) {
      try {
        //  If qmos application create new control net from chosen filename
        if (!getWidget()->directory()) {
          m_controlNetFileLabel->setText( QFileInfo(netFile).fileName() );
          m_controlNet = new ControlNet(m_controlNetFile);
        }
        //  If ipce application, get the active control net from the project.  This control has
        //  already been read into memory.
        else {
          m_controlNet = getWidget()->directory()->project()->activeControl()->controlNet();
          m_controlNetFileLabel->setText( QFileInfo(
              getWidget()->directory()->project()->activeControl()->fileName()).fileName() );
        }
        m_controlNetGraphics = new ControlNetGraphicsItem(m_controlNet,
            getWidget());

        setMovementArrowColorSource(m_movementArrowColorSource,
                                    m_measureCount, m_residualMagnitude);

        connect(m_controlNetGraphics, SIGNAL(destroyed(QObject *)),
                this, SLOT(objectDestroyed(QObject *)));

      }
      catch(IException &e) {
        QString message = "Invalid control network.\n";
        message += e.toString();
        QMessageBox::information(getWidget(), "Error", message);
        return;
      }

      if (m_displayControlNetButton)
        m_displayControlNetButton->setEnabled(true);

      if (m_displayConnectivity)
        m_displayConnectivity->setEnabled(true);

      if (m_closeNetwork) {
        m_closeNetwork->setEnabled(true);
        m_closeNetwork->setVisible(true);
      }

      if (m_loadControlNetButton) {
        m_loadControlNetButton->setEnabled(false);
        m_loadControlNetButton->setVisible(false);
      }
    }
  }

  void MosaicControlNetTool::randomizeColors() {
    foreach (Image *image, getWidget()->images()) {
      image->displayProperties()->setColor(ImageDisplayProperties::randomColor());
    }
  }

  // TODO: why did we remove the error checks?
  void MosaicControlNetTool::mouseButtonRelease(QPointF point, Qt::MouseButton mouseButton) {
    if (!isActive() || !m_controlNet) return;

    // If not IPCE, return, qmos does not use this code
    if (!getWidget()->directory()) return;

    ControlPoint *cp = NULL;

    //  Modify closest control point
    if (mouseButton == Qt::LeftButton) {

      //  Find closes point
      cp = m_controlNetGraphics->findClosestControlPoint(point);

      // TODO  move the emit into the if so that we do not need to do early return.
      // The user did not click close enough to a point for findClosestControlPoint to find a point.
      if (!cp) {
        return;
      }
      emit modifyControlPoint(cp);
    }
    else if (mouseButton == Qt::MidButton) {

      cp = m_controlNetGraphics->findClosestControlPoint(point);
      if (!cp) {
      // TODO Figure out how to get this error message in the right place
        QString message = "No points exist for deleting. Create points "
                          "using the right mouse button.";
        QMessageBox::warning(getWidget(), "Warning", message);
        return;
      }

      emit deleteControlPoint(cp);
      //       deletePoint(point); // what should happen here?
    }

    //   Create control point at cursor location
    else if (mouseButton == Qt::RightButton) {
      //  TODO  For now simply take the first image in the list
      // Find all Images under mouse position ... already doing this with the foreach loop?
      //  TODO  should this imagesUnderMousePosition be implemented in MosaicSceneWidget?
      //      Similar code is found in MosaicSceneWidget::contextMenuEvent.
      ImageList imagesAtMousePosition;
      QList<QGraphicsItem *> itemsAtMousePosition = getWidget()->getScene()->items(point);
      foreach (QGraphicsItem *graphicsItem, itemsAtMousePosition) {
        MosaicSceneItem *sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem);

        if (!sceneImageItem) {
          sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem->parentItem());
        }

        if (sceneImageItem && sceneImageItem->image()) {
          imagesAtMousePosition.append(sceneImageItem->image());
        }
      }

      if (imagesAtMousePosition.count()) {
        Projection *proj = getWidget()->getProjection();
        Projection::ProjectionType ptype = proj->projectionType();

        if (ptype == Projection::Triaxial) {
          TProjection *tproj = (TProjection *) proj;
          if (tproj && getWidget()->getView()->sceneRect().contains(point)) {
            if ( tproj->SetCoordinate( point.x(), -1 * point.y() ) ) {
              //  Create Latitude and Longitude objects so there is a signature different from
              Latitude lat(tproj->Latitude(), Angle::Degrees);
              Longitude lon(tproj->Longitude(), Angle::Degrees);
              emit createControlPoint(lat.degrees(), lon.degrees());
            }
          }
        }
      }
    }
  }
}


NavalTaskingManagerClass::NavalTaskingManagerClass(ushort type, Team t) : CampManagerClass(type, t)
{
    flags = 0;
    unitList = NULL;
    tod = 0;
    topPriority = 0;
    done = 0;
}

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include "CmpGlobl.h"
#include "ListADT.h"
#include "F4Vu.h"
#include "vutypes.h"
#include "Objectiv.h"
#include "Strategy.h"
#include "Unit.h"
#include "Find.h"
#include "Path.h"
#include "ASearch.h"
#include "Campaign.h"
#include "Update.h"
#include "f4vu.h"
#include "CampList.h"
#include "gtm.h"
#include "team.h"
#include "gndunit.h"
#include "gtmobj.h"
#include "Manager.h"
#include "MsgInc/NavalTaskingMsg.h"
#include "FalcSess.h"
#include "ClassTbl.h"

//sfr: buffer chks
#include "InvalidBufferException.h"

#include "Debuggr.h"

// NTM (Naval Tasking Manager) Build ground tasking orders for each team

// Class Functions

NavalTaskingManagerClass::NavalTaskingManagerClass(VU_BYTE **stream, long *rem) : CampManagerClass(stream, rem)
{
    memcpychk(&flags, stream, sizeof(short), rem);
    unitList = NULL;
    tod = 0;
    topPriority = 0;
    done = 0;
}

NavalTaskingManagerClass::NavalTaskingManagerClass(FILE *file) : CampManagerClass(file)
{
    fread(&flags, sizeof(short), 1, file);
    unitList = NULL;
    tod = 0;
    topPriority = 0;
    done = 0;
}

NavalTaskingManagerClass::~NavalTaskingManagerClass()
{
    if (unitList)
    {
        unitList->Unregister();
        delete unitList;
    }
}

int NavalTaskingManagerClass::SaveSize(void)
{
    return CampManagerClass::SaveSize()
           + sizeof(short);
}

int NavalTaskingManagerClass::Save(VU_BYTE **stream)
{
    CampManagerClass::Save(stream);
    memcpy(*stream, &flags, sizeof(short));
    *stream += sizeof(short);
    return NavalTaskingManagerClass::SaveSize();
}

int NavalTaskingManagerClass::Save(FILE *file)
{
    int retval = 0;

    if ( not file)
        return 0;

    retval += CampManagerClass::Save(file);
    retval += fwrite(&flags, sizeof(short), 1, file);
    return retval;
}

int NavalTaskingManagerClass::Task(void)
{
    return 0;
}

void NavalTaskingManagerClass::DoCalculations(void)
{
    MissionRequestClass mis;
    Unit unit;
    int j;
    Objective o;

    // Target all naval units
    VuListIterator mit(AllRealList);
    unit = (Unit) mit.GetFirst();

    while (unit)
    {
        if (unit->IsTaskForce() and GetRoE(owner, unit->GetTeam(), ROE_NAVAL_FIRE) == ROE_ALLOWED)
        {
            mis.requesterID = FalconNullId;
            unit->GetLocation(&mis.tx, &mis.ty);
            mis.vs = unit->GetTeam();
            mis.who = owner;
            j = 30 + (rand() + unit->GetCampID()) % 60;
            mis.tot = Camp_GetCurrentTime() + j * CampaignMinutes;
            mis.tot_type = TYPE_NE;
            mis.targetID = unit->Id();
            mis.target_num = 255;
            mis.mission = AMIS_ASHIP;
            mis.roe_check = ROE_NAVAL_FIRE;
            // Determine if they're active or static
            o = FindNearestObjective(mis.tx, mis.ty, NULL, 2);

            if (o and o->GetType() == TYPE_PORT)
            {
                if (unit->GetSType() == STYPE_UNIT_SEA_TANKER or unit->GetSType() == STYPE_UNIT_SEA_TRANSPORT)
                {
                    mis.context = enemyNavalForceUnloading;
                }
                else
                {
                    mis.context = enemyNavalForceStatic;
                }
            }
            else
            {
                mis.context = enemyNavalForceActive;
            }

            mis.RequestMission();
        }

        unit = (Unit) mit.GetNext();
    }
}

// Sends a message to the NTM
void NavalTaskingManagerClass::SendNTMMessage(VU_ID from, short message, short data1, short data2, VU_ID data3)
{
    VuTargetEntity *target = (VuTargetEntity*) vuDatabase->Find(OwnerId());
    FalconNavalTaskingMessage* tontm = new FalconNavalTaskingMessage(Id(), target);

    if (this)
    {
        tontm->dataBlock.from = from;
        tontm->dataBlock.team = owner;
        tontm->dataBlock.messageType = message;
        tontm->dataBlock.data1 = data1;
        tontm->dataBlock.data2 = data2;
        tontm->dataBlock.enemy = data3;
        FalconSendMessage(tontm, TRUE);
    }
}

int NavalTaskingManagerClass::Handle(VuFullUpdateEvent *event)
{
    NavalTaskingManagerClass* tmpGTM = (NavalTaskingManagerClass*)(event->expandedData_.get());

    // Copy in new data
    memcpy(&flags, &tmpGTM->flags, sizeof(short));
    return (VuEntity::Handle(event));
}

// Global functions


switch (Subtarget.getTargetABI()) {
  default:
    llvm_unreachable("Unrecognized ABI");
  case RISCVABI::ABI_ILP32:
  case RISCVABI::ABI_LP64:
    return CSR_ILP32_LP64_RegMask;
  case RISCVABI::ABI_ILP32F:
  case RISCVABI::ABI_LP64F:
    return CSR_ILP32F_LP64F_RegMask;
  case RISCVABI::ABI_ILP32D:
  case RISCVABI::ABI_LP64D:
    return CSR_ILP32D_LP64D_RegMask;
  }

//===-- RISCVRegisterInfo.cpp - RISCV Register Information ------*- C++ -*-===//
// This file contains the RISCV implementation of the TargetRegisterInfo class.

#include "RISCVRegisterInfo.h"
#include "RISCV.h"
#include "RISCVMachineFunctionInfo.h"
#include "RISCVSubtarget.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/Support/ErrorHandling.h"

#define GET_REGINFO_TARGET_DESC
#include "RISCVGenRegisterInfo.inc"

using namespace llvm;

static_assert(RISCV::X1 == RISCV::X0 + 1, "Register list not consecutive");
static_assert(RISCV::X31 == RISCV::X0 + 31, "Register list not consecutive");
static_assert(RISCV::F1_F == RISCV::F0_F + 1, "Register list not consecutive");
static_assert(RISCV::F31_F == RISCV::F0_F + 31,
              "Register list not consecutive");
static_assert(RISCV::F1_D == RISCV::F0_D + 1, "Register list not consecutive");
static_assert(RISCV::F31_D == RISCV::F0_D + 31,
              "Register list not consecutive");
static_assert(RISCV::V1 == RISCV::V0 + 1, "Register list not consecutive");
static_assert(RISCV::V31 == RISCV::V0 + 31, "Register list not consecutive");

RISCVRegisterInfo::RISCVRegisterInfo(unsigned HwMode)
    : RISCVGenRegisterInfo(RISCV::X1, /*DwarfFlavour*/0, /*EHFlavor*/0,
                           /*PC*/0, HwMode) {}

const MCPhysReg *
RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
  auto &Subtarget = MF->getSubtarget<RISCVSubtarget>();
  if (MF->getFunction().hasFnAttribute("interrupt")) {
    if (Subtarget.hasStdExtD())
      return CSR_XLEN_F64_Interrupt_SaveList;
    if (Subtarget.hasStdExtF())
      return CSR_XLEN_F32_Interrupt_SaveList;
    return CSR_Interrupt_SaveList;
  }

  switch (Subtarget.getTargetABI()) {
  default:
    llvm_unreachable("Unrecognized ABI");
  case RISCVABI::ABI_ILP32:
  case RISCVABI::ABI_LP64:
    return CSR_ILP32_LP64_SaveList;
  case RISCVABI::ABI_ILP32F:
  case RISCVABI::ABI_LP64F:
    return CSR_ILP32F_LP64F_SaveList;
  case RISCVABI::ABI_ILP32D:
  case RISCVABI::ABI_LP64D:
    return CSR_ILP32D_LP64D_SaveList;
  }
}

BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
  const RISCVFrameLowering *TFI = getFrameLowering(MF);
  BitVector Reserved(getNumRegs());

  // Mark any registers requested to be reserved as such
  for (size_t Reg = 0; Reg < getNumRegs(); Reg++) {
    if (MF.getSubtarget<RISCVSubtarget>().isRegisterReservedByUser(Reg))
      markSuperRegs(Reserved, Reg);
  }

  // Use markSuperRegs to ensure any register aliases are also reserved
  markSuperRegs(Reserved, RISCV::X0); // zero
  markSuperRegs(Reserved, RISCV::X2); // sp
  markSuperRegs(Reserved, RISCV::X3); // gp
  markSuperRegs(Reserved, RISCV::X4); // tp

  auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
  if (Subtarget.hasStdExtV() || TFI->hasFP(MF))
    markSuperRegs(Reserved, RISCV::X8); // fp
  // Reserve the base register if we need to realign the stack and allocate
  // variable-sized objects at runtime.
  if (TFI->hasBP(MF))
    markSuperRegs(Reserved, RISCVABI::getBPReg()); // bp
  assert(checkAllSuperRegsMarked(Reserved));
  return Reserved;
}

bool RISCVRegisterInfo::isAsmClobberable(const MachineFunction &MF,
                                         MCRegister PhysReg) const {
  return !MF.getSubtarget<RISCVSubtarget>().isRegisterReservedByUser(PhysReg);
}

bool RISCVRegisterInfo::isConstantPhysReg(MCRegister PhysReg) const {
  return PhysReg == RISCV::X0;
}

const uint32_t *RISCVRegisterInfo::getNoPreservedMask() const {
  return CSR_NoRegs_RegMask;
}

// Frame indexes representing locations of CSRs which are given a fixed location
// by save/restore libcalls.
static const std::map<unsigned, int> FixedCSRFIMap = {
  {/*ra*/  RISCV::X1,   -1},
  {/*s0*/  RISCV::X8,   -2},
  {/*s1*/  RISCV::X9,   -3},
  {/*s2*/  RISCV::X18,  -4},
  {/*s3*/  RISCV::X19,  -5},
  {/*s4*/  RISCV::X20,  -6},
  {/*s5*/  RISCV::X21,  -7},
  {/*s6*/  RISCV::X22,  -8},
  {/*s7*/  RISCV::X23,  -9},
  {/*s8*/  RISCV::X24,  -10},
  {/*s9*/  RISCV::X25,  -11},
  {/*s10*/ RISCV::X26,  -12},
  {/*s11*/ RISCV::X27,  -13}
};

bool RISCVRegisterInfo::hasReservedSpillSlot(const MachineFunction &MF,
                                             Register Reg,
                                             int &FrameIdx) const {
  const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
  if (!RVFI->useSaveRestoreLibCalls(MF))
    return false;

  auto FII = FixedCSRFIMap.find(Reg);
  if (FII == FixedCSRFIMap.end())
    return false;

  FrameIdx = FII->second;
  return true;
}

void RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                            int SPAdj, unsigned FIOperandNum,
                                            RegScavenger *RS) const {
  assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");

  MachineInstr &MI = *II;
  MachineFunction &MF = *MI.getParent()->getParent();
  MachineFrameInfo &MFI = MF.getFrameInfo();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const RISCVInstrInfo *TII = MF.getSubtarget<RISCVSubtarget>().getInstrInfo();
  DebugLoc DL = MI.getDebugLoc();

  int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
  Register FrameReg;
  int Offset =
      getFrameLowering(MF)->getFrameIndexReference(MF, FrameIndex, FrameReg);

  if (!isInt<32>(Offset)) {
    report_fatal_error(
        "Frame offsets outside of the signed 32-bit range not supported");
  }

  MachineBasicBlock &MBB = *MI.getParent();

  if (MFI.getStackID(FrameIndex) == TargetStackID::RISCVVector) {
    switch (MI.getOpcode()) {
    case RISCV::ADDI: {
      MachineOperand StackSlot = MI.getOperand(FIOperandNum);
      unsigned Opcode = getRegSizeInBits(RISCV::GPRRegClass) == 32 ? RISCV::LW :
                                                                   RISCV::LD;
      MachineInstr *StoreAddr = BuildMI(MBB, II, DL, TII->get(Opcode), MI.getOperand(0).getReg())
                                    .add(StackSlot)
                                    .addImm(0);

      MI.eraseFromParent();
      return eliminateFrameIndex(StoreAddr, 0, 1, RS);
    }
    case RISCV::VLE32_V:
    case RISCV::VSE32_V:
    case RISCV::VL1RE8_V:
    case RISCV::VL2RE8_V:
    case RISCV::VL4RE8_V:
    case RISCV::VL8RE8_V:
    case RISCV::VS1R_V:
    case RISCV::VS2R_V:
    case RISCV::VS4R_V:
    case RISCV::VS8R_V: {
      MachineOperand StackSlot = MI.getOperand(FIOperandNum);
      unsigned Opcode = getRegSizeInBits(RISCV::GPRRegClass) == 32 ? RISCV::LW :
                                                                   RISCV::LD;
      Register addr = MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
      MachineInstr *StoreAddr = BuildMI(MBB, II, DL, TII->get(Opcode), addr)
                                    .add(StackSlot)
                                    .addImm(0);

      MI.getOperand(FIOperandNum).ChangeToRegister(addr, false, false,
                                                   false);
      return eliminateFrameIndex(StoreAddr, 0, 1, RS);
    }
    default:
      break;
    }
  }
  Offset += MI.getOperand(FIOperandNum + 1).getImm();
  bool FrameRegIsKill = false;

  if (!isInt<12>(Offset)) {
    assert(isInt<32>(Offset) && "Int32 expected");
    // The offset won't fit in an immediate, so use a scratch register instead
    // Modify Offset and FrameReg appropriately
    Register ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
    TII->movImm(MBB, II, DL, ScratchReg, Offset);
    BuildMI(MBB, II, DL, TII->get(RISCV::ADD), ScratchReg)
        .addReg(FrameReg)
        .addReg(ScratchReg, RegState::Kill);
    Offset = 0;
    FrameReg = ScratchReg;
    FrameRegIsKill = true;
  }

  MI.getOperand(FIOperandNum)
      .ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
  MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
}

Register RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
  const TargetFrameLowering *TFI = getFrameLowering(MF);
  return TFI->hasFP(MF) ? RISCV::X8 : RISCV::X2;
}

const uint32_t *
RISCVRegisterInfo::getCallPreservedMask(const MachineFunction & MF,
                                        CallingConv::ID /*CC*/) const {
  auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();


int
ACE_Shared_Memory_SV::close (void)
{
  ACE_TRACE ("ACE_Shared_Memory_SV::close");
  return shared_memory_.detach ();
}

#include "ace/Shared_Memory_SV.h"

#if !defined (__ACE_INLINE__)
#include "ace/Shared_Memory_SV.inl"
#endif /* __ACE_INLINE__ */

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_SV)

void
ACE_Shared_Memory_SV::dump (void) const
{
#if defined (ACE_HAS_DUMP)
  ACE_TRACE ("ACE_Shared_Memory_SV::dump");
#endif /* ACE_HAS_DUMP */
}

ACE_Shared_Memory_SV::ACE_Shared_Memory_SV (key_t id,
                                            size_t length,
                                            int create,
                                            int perms,
                                            void *addr,
                                            int flags)
  : shared_memory_ (id, length, create, perms, addr, flags)
{
  ACE_TRACE ("ACE_Shared_Memory_SV::ACE_Shared_Memory_SV");
}

// The overall size of the segment.

size_t
ACE_Shared_Memory_SV::get_segment_size (void) const
{
  ACE_TRACE ("ACE_Shared_Memory_SV::get_segment_size");
  // This cast is ok since the 'open' method for this class allows only
  // an 'int' size. Therefore, this case should not lose information.
  return this->shared_memory_.get_segment_size ();
}

// Removes the shared memory segment.

int
ACE_Shared_Memory_SV::remove (void)
{
  ACE_TRACE ("ACE_Shared_Memory_SV::remove");
  return shared_memory_.remove ();
}

// Closes (detaches) the shared memory segment.

void *
ACE_Shared_Memory_SV::malloc (size_t)
{
  ACE_TRACE ("ACE_Shared_Memory_SV::malloc");
  return this->shared_memory_.get_segment_ptr ();
}

ACE_HANDLE
ACE_Shared_Memory_SV::get_id (void) const
{
  ACE_TRACE ("ACE_Shared_Memory_SV::get_id");
  return this->shared_memory_.get_id ();
}

int
ACE_Shared_Memory_SV::free (void *p)
{
  ACE_TRACE ("ACE_Shared_Memory_SV::free");
  return p != 0;
}

ACE_END_VERSIONED_NAMESPACE_DECL


std::unique_ptr<BlobView> BufferSliceBlobView::create(td::BufferSlice slice) {
  return std::make_unique<BufferSliceBlobViewImpl>(std::move(slice));
}

/*
    This file is part of TON Blockchain Library.

*/
#include "vm/db/BlobView.h"

#include "td/utils/port/FileFd.h"
#include "td/utils/HashMap.h"

#include "td/utils/format.h"
#include "td/utils/port/RwMutex.h"
#include "td/utils/port/MemoryMapping.h"

#include <limits>
#include <mutex>

namespace vm {
td::Result<td::Slice> BlobView::view(td::MutableSlice slice, td::uint64 offset) {
  if (offset > size() || slice.size() > size() - offset) {
    return td::Status::Error(PSLICE() << "BlobView: invalid range requested " << td::tag("slice offset", offset)
                                      << td::tag("slice size", slice.size()) << td::tag("blob size", size()));
  }
  return view_impl(slice, offset);
}
namespace {
class BufferSliceBlobViewImpl : public BlobView {
 public:
  BufferSliceBlobViewImpl(td::BufferSlice slice) : slice_(std::move(slice)) {
  }
  td::Result<td::Slice> view_impl(td::MutableSlice slice, td::uint64 offset) override {
    // optimize anyway
    if (offset > std::numeric_limits<std::size_t>::max()) {
      return td::Slice();
    }
    return slice_.as_slice().substr(static_cast<std::size_t>(offset), slice.size());
  }
  td::uint64 size() override {
    return slice_.size();
  }

 private:
  td::BufferSlice slice_;
};
}  // namespace

class FileBlobViewImpl : public BlobView {
 public:
  FileBlobViewImpl(td::FileFd fd, td::uint64 file_size) : fd_(std::move(fd)), file_size_(file_size) {
  }

  td::uint64 size() override {
    return file_size_;
  }
  td::Result<td::Slice> view_impl(td::MutableSlice slice, td::uint64 offset) override {
    CHECK(offset < size());
    CHECK(size() - offset >= slice.size());
    slice.truncate(file_size_ - offset);
    auto first_page = offset / page_size;
    auto last_page = (offset + slice.size() - 1) / page_size;
    td::uint64 res_offset = 0;
    for (auto page_i = first_page; page_i <= last_page; page_i++) {
      auto page_offset = page_i * page_size;
      auto from = td::max(page_offset, offset);
      auto till = td::min(page_offset + page_size, offset + slice.size());
      CHECK(from < till);
      TRY_RESULT(page, load_page(page_i));
      auto len = till - from;
      slice.substr(res_offset, len).copy_from(page.substr(from - page_offset, len));
      res_offset += len;
    }
    CHECK(slice.size() == res_offset);
    total_view_size_ += slice.size();
    return slice;
  }
  ~FileBlobViewImpl() {
  }

 private:
  td::FileFd fd_;
  td::uint64 file_size_;
  const td::uint64 page_size = 4096;
  td::uint64 total_view_size_{0};

  td::RwMutex pages_rw_mutex_;
  td::HashMap<td::uint64, td::BufferSlice> pages_;

  std::mutex fd_mutex_;

  td::Result<td::Slice> load_page(td::uint64 page_i) {
    {
      auto pages_guard = pages_rw_mutex_.lock_read();
      auto it = pages_.find(page_i);
      if (it != pages_.end()) {
        return it->second.as_slice();
      }
    }

    std::lock_guard<std::mutex> fd_guard(fd_mutex_);
    {
      auto pages_guard = pages_rw_mutex_.lock_read();
      auto it = pages_.find(page_i);
      if (it != pages_.end()) {
        return it->second.as_slice();
      }
    }
    auto offset = page_i * page_size;

    auto size = td::min(file_size_ - offset, page_size);
    auto buffer_slice = td::BufferSlice(size);
    TRY_RESULT(read_size, fd_.pread(buffer_slice.as_slice(), offset));
    if (read_size != buffer_slice.size()) {
      return td::Status::Error("not enough data in file");
    }

    auto pages_guard = pages_rw_mutex_.lock_write();
    auto &res = pages_[page_i];
    res = std::move(buffer_slice);
    return res.as_slice();
  }
};
td::Result<std::unique_ptr<BlobView>> FileBlobView::create(td::CSlice file_path, td::uint64 file_size) {
  TRY_RESULT(fd, td::FileFd::open(file_path, td::FileFd::Flags::Read));
  TRY_RESULT(stat, fd.stat());
  if (file_size == 0) {
    file_size = stat.size_;
  } else if (file_size != (td::uint64)stat.size_) {
    return td::Status::Error("Wrong file size");
  }
  return std::make_unique<FileBlobViewImpl>(std::move(fd), file_size);
}

class FileMemoryMappingBlobViewImpl : public BlobView {
 public:
  FileMemoryMappingBlobViewImpl(td::MemoryMapping mapping) : mapping_(std::move(mapping)) {
  }
  td::Result<td::Slice> view_impl(td::MutableSlice slice, td::uint64 offset) override {
    // optimize anyway
    return mapping_.as_slice().substr(offset, slice.size());
  }
  td::uint64 size() override {
    return mapping_.as_slice().size();
  }

 private:
  td::MemoryMapping mapping_;
};

td::Result<std::unique_ptr<BlobView>> FileMemoryMappingBlobView::create(td::CSlice file_path, td::uint64 file_size) {
  TRY_RESULT(fd, td::FileFd::open(file_path, td::FileFd::Flags::Read));
  TRY_RESULT(stat, fd.stat());
  if (file_size == 0) {
    file_size = stat.size_;
  } else if (file_size != (td::uint64)stat.size_) {
    return td::Status::Error("Wrong file size");
  }

  TRY_RESULT(mapping, td::MemoryMapping::create_from_file(fd));

  return std::make_unique<FileMemoryMappingBlobViewImpl>(std::move(mapping));
}

}  // namespace vm


try
	{
		clear();
	}
	catch (...)
	{
		poco_unexpected();
	}

// TimedNotificationQueue.cpp
// Library: Foundation
// Package: Notifications
// Module:  TimedNotificationQueue

#include "Poco/TimedNotificationQueue.h"
#include "Poco/Notification.h"
#include <limits>

namespace Poco {

TimedNotificationQueue::TimedNotificationQueue()
{
}

TimedNotificationQueue::~TimedNotificationQueue()
{

}

void TimedNotificationQueue::enqueueNotification(Notification::Ptr pNotification, Timestamp timestamp)
{
	poco_check_ptr (pNotification);

	Timestamp tsNow;
	Clock clock;
	Timestamp::TimeDiff diff = timestamp - tsNow;
	clock += diff;

	FastMutex::ScopedLock lock(_mutex);
	_nfQueue.insert(NfQueue::value_type(clock, pNotification));
	_nfAvailable.set();
}

void TimedNotificationQueue::enqueueNotification(Notification::Ptr pNotification, Clock clock)
{
	poco_check_ptr (pNotification);

	FastMutex::ScopedLock lock(_mutex);
	_nfQueue.insert(NfQueue::value_type(clock, pNotification));
	_nfAvailable.set();
}

Notification* TimedNotificationQueue::dequeueNotification()
{
	FastMutex::ScopedLock lock(_mutex);

	NfQueue::iterator it = _nfQueue.begin();
	if (it != _nfQueue.end())
	{
		Clock::ClockDiff sleep = -it->first.elapsed();
		if (sleep <= 0)
		{
			Notification::Ptr pNf = it->second;
			_nfQueue.erase(it);
			return pNf.duplicate();
		}
	}
	return 0;
}

Notification* TimedNotificationQueue::waitDequeueNotification()
{
	for (;;)
	{
		_mutex.lock();
		NfQueue::iterator it = _nfQueue.begin();
		if (it != _nfQueue.end())
		{
			_mutex.unlock();
			Clock::ClockDiff sleep = -it->first.elapsed();
			if (sleep <= 0)
			{
				return dequeueOne(it).duplicate();
			}
			else if (!wait(sleep))
			{
				return dequeueOne(it).duplicate();
			}
			else continue;
		}
		else
		{
			_mutex.unlock();
		}
		_nfAvailable.wait();
	}
}

Notification* TimedNotificationQueue::waitDequeueNotification(long milliseconds)
{
	while (milliseconds >= 0)
	{
		_mutex.lock();
		NfQueue::iterator it = _nfQueue.begin();
		if (it != _nfQueue.end())
		{
			_mutex.unlock();
			Clock now;
			Clock::ClockDiff sleep = it->first - now;
			if (sleep <= 0)
			{
				return dequeueOne(it).duplicate();
			}
			else if (sleep <= 1000*Clock::ClockDiff(milliseconds))
			{
				if (!wait(sleep))
				{
					return dequeueOne(it).duplicate();
				}
				else
				{
					milliseconds -= static_cast<long>((now.elapsed() + 999)/1000);
					continue;
				}
			}
		}
		else
		{
			_mutex.unlock();
		}
		if (milliseconds > 0)
		{
			Clock now;
			_nfAvailable.tryWait(milliseconds);
			milliseconds -= static_cast<long>((now.elapsed() + 999)/1000);
		}
		else return 0;
	}
	return 0;
}

bool TimedNotificationQueue::wait(Clock::ClockDiff interval)
{
	const Clock::ClockDiff MAX_SLEEP = 8*60*60*Clock::ClockDiff(1000000); // sleep at most 8 hours at a time
	while (interval > 0)
	{
		Clock now;
		Clock::ClockDiff sleep = interval <= MAX_SLEEP ? interval : MAX_SLEEP;
		if (_nfAvailable.tryWait(static_cast<long>((sleep + 999)/1000)))
			return true;
		interval -= now.elapsed();
	}
	return false;
}

bool TimedNotificationQueue::empty() const
{
	FastMutex::ScopedLock lock(_mutex);
	return _nfQueue.empty();
}

int TimedNotificationQueue::size() const
{
	FastMutex::ScopedLock lock(_mutex);
	return static_cast<int>(_nfQueue.size());
}

void TimedNotificationQueue::clear()
{
	FastMutex::ScopedLock lock(_mutex);
	_nfQueue.clear();
}

Notification::Ptr TimedNotificationQueue::dequeueOne(NfQueue::iterator& it)
{
	FastMutex::ScopedLock lock(_mutex);
	Notification::Ptr pNf = it->second;
	_nfQueue.erase(it);
	return pNf;
}

} // namespace Poco


try {
				//acquire frame
				if (FAILED(multiFrame->get_LongExposureInfraredFrameReference(&reference))) {
					return; // we often throw here when no new frame is available
				}
				if (FAILED(reference->AcquireFrame(&frame))) {
					return; // we often throw here when no new frame is available
				}
				BaseImageSimple::update(frame);
			} catch (std::exception & e) {
				OFXKINECTFORWINDOWS2_ERROR << e.what();
			}

#include "LongExposureInfrared.h"
#include "ofMain.h"

namespace ofxKinectForWindows2 {
	namespace Source {
		string LongExposureInfrared::getTypeName() const {
			return "LongExposureInfrared";
		}

		void LongExposureInfrared::initReader(IKinectSensor * sensor) {
			this->reader = NULL;
			try {
				ILongExposureInfraredFrameSource * source = NULL;

				if (FAILED(sensor->get_LongExposureInfraredFrameSource(&source))) {
					throw(Exception("Failed to initialise LongExposureInfrared source"));
				}

				if (FAILED(source->OpenReader(&this->reader))) {
					throw(Exception("Failed to initialise LongExposureInfrared reader"));
				}

				SafeRelease(source);
			} catch (std::exception & e) {
				SafeRelease(this->reader);
				throw (e);
			}
		}

		void LongExposureInfrared::update(IMultiSourceFrame * multiFrame) {
			this->isFrameNewFlag = false;
			ILongExposureInfraredFrame * frame = NULL;
			ILongExposureInfraredFrameReference * reference;

			SafeRelease(reference);
			SafeRelease(frame);
		}
	}
}


template<class F, class ...Rest> struct first_impl { typedef F type; };
template<class ...Args> using first = typename first_impl<Args...>::type;

namespace simple_explicit_capture {
  void test() {
    int i;
    auto L = [i](auto a) { return i + a; };
    L(3.14);
  }
}

namespace explicit_call {
int test() {
  auto L = [](auto a) { return a; };
  L.operator()(3);
  L.operator()<char>(3.14); //expected-warning{{implicit conversion}}
  return 0;
}
} //end ns

namespace test_conversion_to_fptr_2 {

template<class T> struct X {

  T (*fp)(T) = [](auto a) { return a; };

};

X<int> xi;

template<class T>
void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {
  fp(t);
}

int test() {
{
  auto L = [](auto a) { return a; };
  int (*fp)(int) = L;
  fp(5);
  L(3);
  char (*fc)(char) = L;
  fc('b');
  L('c');
  double (*fd)(double) = L;
  fd(3.14);
  fd(6.26);
  L(4.25);
}
{
  auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
  int (*fp)(int) = L;
  char (*fc)(char) = L; //expected-error{{no viable conversion}}
  double (*fd)(double) = L; //expected-error{{no viable conversion}}
}
{
  int x = 5;
  auto L = [=](auto b, char c = 'x') {
    int i = x;
    return [](auto a) ->decltype(a) { return a; };
  };
  int (*fp)(int) = L(8);
  fp(5);
  L(3);
  char (*fc)(char) = L('a');
  fc('b');
  L('c');
  double (*fd)(double) = L(3.14);
  fd(3.14);
  fd(6.26);

}
{
 auto L = [=](auto b) {
    return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };
  };
  int* (*fp)(int) = L(8);
  fp(5);
  L(3);
  char* (*fc)(char) = L('a');
  fc('b');
  L('c');
  double* (*fd)(double) = L(3.14);
  fd(3.14);
  fd(6.26);
}
{
 auto L = [=](auto b) {
    return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}
  };
  char* (*fp)(int) = L('8');
  fp(5);
  char* (*fc)(char) = L('a');
  fc('b');
  double* (*fi)(int) = L(3.14);
  fi(5);
  int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}
}

{
 auto L = [=](auto b) {
    return [](auto a) {
      return [=](auto c) {
        return [](auto d) ->decltype(a + b + c + d) { return d; };
      };
    };
  };
  int (*fp)(int) = L('8')(3)(short{});
  double (*fs)(char) = L(3.14)(short{})('4');
}

  fooT(3);
  fooT('a');
  fooT(3.14);
  fooT("abcdefg");
  return 0;
}
int run2 = test();

}

namespace test_conversion_to_fptr {

void f1(int (*)(int)) { }
void f2(char (*)(int)) { } // expected-note{{candidate}}
void g(int (*)(int)) { } // #1 expected-note{{candidate}}
void g(char (*)(char)) { } // #2 expected-note{{candidate}}
void h(int (*)(int)) { } // #3
void h(char (*)(int)) { } // #4

int test() {
{
  auto glambda = [](auto a) { return a; };
  glambda(1);
  f1(glambda); // OK
  f2(glambda); // expected-error{{no matching function}}
  g(glambda); // expected-error{{call to 'g' is ambiguous}}
  h(glambda); // OK: calls #3 since it is convertible from ID

  int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK

}
{

  auto L = [](auto a) { return a; };
  int (*fp)(int) = L;
  fp(5);
  L(3);
  char (*fc)(char) = L;
  fc('b');
  L('c');
  double (*fd)(double) = L;
  fd(3.14);
  fd(6.26);
  L(4.25);
}
{
  auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
  int (*fp)(int) = L;
  char (*fc)(char) = L; //expected-error{{no viable conversion}}
  double (*fd)(double) = L; //expected-error{{no viable conversion}}
}
{
  int* (*fp)(int*) = [](auto *a) -> auto* { return a; };
  fp(0);
}
}

namespace more_converion_to_ptr_to_function_tests {

int test() {
  {
    int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
    int (*fp2)(int) = [](auto b) -> int {  return b; };
    int (*fp3)(char) = [](auto c) -> int { return c; };
    char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
    char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
                                                 //expected-note{{candidate template ignored}}

    fp2(3);
    fp3('\n');
    fp3('a');
    return 0;
  }
} // end test()

template<class ... Ts> void vfun(Ts ... ) { }

int variadic_test() {

 int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; };
 fp(3, '4', 3.14);

 int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; };
 fp(3, '4', 3.14);
 return 2;
}

} // end ns

namespace conversion_operator {
  void test() {
    auto L = [](auto a) -> int { return a; }; // expected-error {{cannot initialize}}
    int (*fp)(int) = L;
    int (&fp2)(int) = [](auto a) { return a; };  // expected-error{{non-const lvalue}}
    int (&&fp3)(int) = [](auto a) { return a; };  // expected-error{{no viable conversion}}\

    using F = int(int);
    using G = int(void*);
    L.operator F*();
    L.operator G*(); // expected-note-re {{instantiation of function template specialization '{{.*}}::operator()<void *>'}}

    // Here, the conversion function is named 'operator auto (*)(int)', and
    // there is no way to write that name in valid C++.
    auto M = [](auto a) -> auto { return a; };
    M.operator F*(); // expected-error {{no member named 'operator int (*)(int)'}}
  }
}
}

namespace return_type_deduction_ok {
 auto l = [](auto a) ->auto { return a; }(2);
 auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
 auto l3 = [](auto a) { return a; }(2);

}

namespace generic_lambda_as_default_argument_ok {
  void test(int i = [](auto a)->int { return a; }(3)) {
  }
}

namespace nested_non_capturing_lambda_tests {
template<class ... Ts> void print(Ts ...) { }
int test() {
{
  auto L = [](auto a) {
    return [](auto b) {
      return b;
    };
  };
  auto M = L(3);
  M(4.15);
 }
{
  int i = 10; //expected-note 3{{declared here}}
  auto L = [](auto a) {
    return [](auto b) { //expected-note 3{{begins here}}
      i = b;  //expected-error 3{{cannot be implicitly captured}}
      return b;
    };
  };
  auto M = L(3); //expected-note{{instantiation}}
  M(4.15); //expected-note{{instantiation}}
 }
 {
  int i = 10;
  auto L = [](auto a) {
    return [](auto b) {
      b = sizeof(i);  //ok
      return b;
    };
  };
 }
 {
  auto L = [](auto a) {
    print("a = ", a, "\n");
    return [](auto b) ->decltype(a) {
      print("b = ", b, "\n");
      return b;
    };
  };
  auto M = L(3);
  M(4.15);
 }

{
  auto L = [](auto a) ->decltype(a) {
    print("a = ", a, "\n");
    return [](auto b) ->decltype(a) { //expected-error{{no viable conversion}}\
                                      //expected-note{{candidate template ignored}}
      print("b = ", b, "\n");
      return b;
    };
  };
  auto M = L(3); //expected-note{{in instantiation of}}
 }
{
  auto L = [](auto a) {
    print("a = ", a, "\n");
    return [](auto ... b) ->decltype(a) {
      print("b = ", b ..., "\n");
      return 4;
    };
  };
  auto M = L(3);
  M(4.15, 3, "fv");
}

{
  auto L = [](auto a) {
    print("a = ", a, "\n");
    return [](auto ... b) ->decltype(a) {
      print("b = ", b ..., "\n");
      return 4;
    };
  };
  auto M = L(3);
  int (*fp)(double, int, const char*) = M;
  fp(4.15, 3, "fv");
}

{
  auto L = [](auto a) {
    print("a = ", a, "\n");
    return [](char b) {
      return [](auto ... c) ->decltype(b) {
        print("c = ", c ..., "\n");
        return 42;
      };
    };
  };
  L(4);
  auto M = L(3);
  M('a');
  auto N = M('x');
  N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
  char (*np)(const char*, int, const char*, double, const char*, int) = N;
  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
}

{
  auto L = [](auto a) {
    print("a = ", a, "\n");
    return [](decltype(a) b) {
      return [](auto ... c) ->decltype(b) {
        print("c = ", c ..., "\n");
        return 42;
      };
    };
  };
  L('4');
  auto M = L('3');
  M('a');
  auto N = M('x');
  N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
  char (*np)(const char*, int, const char*, double, const char*, int) = N;
  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
}

{
 struct X {
  static void foo(double d) { }
  void test() {
    auto L = [](auto a) {
      print("a = ", a, "\n");
      foo(a);
      return [](decltype(a) b) {
        foo(b);
        foo(sizeof(a) + sizeof(b));
        return [](auto ... c) ->decltype(b) {
          print("c = ", c ..., "\n");
          foo(decltype(b){});
          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
          return 42;
        };
      };
    };
    L('4');
    auto M = L('3');
    M('a');
    auto N = M('x');
    N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
    char (*np)(const char*, int, const char*, double, const char*, int) = N;
    np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
  }
};
X x;
x.test();
}
// Make sure we can escape the function
{
 struct X {
  static void foo(double d) { }
  auto test() {
    auto L = [](auto a) {
      print("a = ", a, "\n");
      foo(a);
      return [](decltype(a) b) {
        foo(b);
        foo(sizeof(a) + sizeof(b));
        return [](auto ... c) ->decltype(b) {
          print("c = ", c ..., "\n");
          foo(decltype(b){});
          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
          return 42;
        };
      };
    };
    return L;
  }
};
  X x;
  auto L = x.test();
  L('4');
  auto M = L('3');
  M('a');
  auto N = M('x');
  N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
  char (*np)(const char*, int, const char*, double, const char*, int) = N;
  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
}

{
 struct X {
  static void foo(double d) { }
  auto test() {
    auto L = [](auto a) {
      print("a = ", a, "\n");
      foo(a);
      return [](decltype(a) b) {
        foo(b);
        foo(sizeof(a) + sizeof(b));
        return [](auto ... c) {
          print("c = ", c ..., "\n");
          foo(decltype(b){});
          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
            print("d = ", d ..., "\n");
            foo(decltype(b){});
            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
            return decltype(a){};
          };
        };
      };
    };
    return L;
  }
};
  X x;
  auto L = x.test();
  L('4');
  auto M = L('3');
  M('a');
  auto N = M('x');
  auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
  char (*np)(const char*, int, const char*, double, const char*, int) = O;
  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
  int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}

}
} // end test()

namespace wrapped_within_templates {

namespace explicit_return {
template<class T> int fooT(T t) {
  auto L = [](auto a) -> void {
    auto M = [](char b) -> void {
      auto N = [](auto c) -> void {
        int x = 0;
        x = sizeof(a);
        x = sizeof(b);
        x = sizeof(c);
      };
      N('a');
      N(decltype(a){});
    };
  };
  L(t);
  L(3.14);
  return 0;
}

int run = fooT('a') + fooT(3.14);

} // end explicit_return

namespace implicit_return_deduction {
template<class T> auto fooT(T t) {
  auto L = [](auto a)  {
    auto M = [](char b)  {
      auto N = [](auto c)  {
        int x = 0;
        x = sizeof(a);
        x = sizeof(b);
        x = sizeof(c);
      };
      N('a');
      N(decltype(a){});
    };
  };
  L(t);
  L(3.14);
  return 0;
}

int run = fooT('a') + fooT(3.14);

template<class ... Ts> void print(Ts ... ts) { }

template<class ... Ts> auto fooV(Ts ... ts) {
  auto L = [](auto ... a) {
    auto M = [](decltype(a) ... b) {
      auto N = [](auto c) {
        int x = 0;
        x = sizeof...(a);
        x = sizeof...(b);
        x = sizeof(c);
      };
      N('a');
      N(N);
      N(first<Ts...>{});
    };
    M(a...);
    print("a = ", a..., "\n");
  };
  L(L, ts...);
  print("ts = ", ts..., "\n");
  return 0;
}

int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});

} //implicit_return_deduction

} //wrapped_within_templates

namespace at_ns_scope {
  void foo(double d) { }
  auto test() {
    auto L = [](auto a) {
      print("a = ", a, "\n");
      foo(a);
      return [](decltype(a) b) {
        foo(b);
        foo(sizeof(a) + sizeof(b));
        return [](auto ... c) {
          print("c = ", c ..., "\n");
          foo(decltype(b){});
          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
            print("d = ", d ..., "\n");
            foo(decltype(b){});
            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
            return decltype(a){};
          };
        };
      };
    };
    return L;
  }
auto L = test();
auto L_test = L('4');
auto M = L('3');
auto M_test = M('a');
auto N = M('x');
auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
char (*np)(const char*, int, const char*, double, const char*, int) = O;
auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}

}

namespace variadic_tests_1 {
template<class ... Ts> void print(Ts ... ts) { }

template<class F, class ... Rest> F& FirstArg(F& f, Rest...) { return f; }

template<class ... Ts> int fooV(Ts ... ts) {
  auto L = [](auto ... a) -> void {
    auto M = [](decltype(a) ... b) -> void {
      auto N = [](auto c) -> void {
        int x = 0;
        x = sizeof...(a);
        x = sizeof...(b);
        x = sizeof(c);
      };
      N('a');
      N(N);
      N(first<Ts...>{});
    };
    M(a...);
    print("a = ", a..., "\n");
  };
  L(L, ts...);
  print("ts = ", ts..., "\n");
  return 0;
}

int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});

namespace more_variadic_1 {

template<class ... Ts> int fooV(Ts ... ts) {
  auto L = [](auto ... a) {
    auto M = [](decltype(a) ... b) -> void {
      auto N = [](auto c) -> void {
        int x = 0;
        x = sizeof...(a);
        x = sizeof...(b);
        x = sizeof(c);
      };
      N('a');
      N(N);
      N(first<Ts...>{});
    };
    M(a...);
    return M;
  };
  auto M = L(L, ts...);
  decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
  void (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);

  {
    auto L = [](auto ... a) {
      auto M = [](decltype(a) ... b) {
        auto N = [](auto c) -> void {
          int x = 0;
          x = sizeof...(a);
          x = sizeof...(b);
          x = sizeof(c);
        };
        N('a');
        N(N);
        N(first<Ts...>{});
        return N;
      };
      M(a...);
      return M;
    };
    auto M = L(L, ts...);
    decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
    fp(L, ts...);
    decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
    fp2 = fp(L, ts...);
    void (*fp3)(char) = fp2(L, ts...);
    fp3('a');
  }
  return 0;
}

int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});

} //end ns more_variadic_1

} // end ns variadic_tests_1

namespace at_ns_scope_within_class_member {
 struct X {
  static void foo(double d) { }
  auto test() {
    auto L = [](auto a) {
      print("a = ", a, "\n");
      foo(a);
      return [](decltype(a) b) {
        foo(b);
        foo(sizeof(a) + sizeof(b));
        return [](auto ... c) {
          print("c = ", c ..., "\n");
          foo(decltype(b){});
          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
            print("d = ", d ..., "\n");
            foo(decltype(b){});
            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
            return decltype(a){};
          };
        };
      };
    };
    return L;
  }
};
X x;
auto L = x.test();
auto L_test = L('4');
auto M = L('3');
auto M_test = M('a');
auto N = M('x');
auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
char (*np)(const char*, int, const char*, double, const char*, int) = O;
auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}

} //end at_ns_scope_within_class_member

namespace at_ns_scope_within_class_template_member {
 struct X {
  static void foo(double d) { }
  template<class T = int>
  auto test(T = T{}) {
    auto L = [](auto a) {
      print("a = ", a, "\n");
      foo(a);
      return [](decltype(a) b) {
        foo(b);
        foo(sizeof(a) + sizeof(b));
        return [](auto ... c) {
          print("c = ", c ..., "\n");
          foo(decltype(b){});
          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
            print("d = ", d ..., "\n");
            foo(decltype(b){});
            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
            return decltype(a){};
          };
        };
      };
    };
    return L;
  }

};
X x;
auto L = x.test();
auto L_test = L('4');
auto M = L('3');
auto M_test = M('a');
auto N = M('x');
auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
char (*np)(const char*, int, const char*, double, const char*, int) = O;
auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}

} //end at_ns_scope_within_class_member

namespace nested_generic_lambdas_123 {
void test() {
  auto L = [](auto a) -> int {
    auto M = [](auto b, decltype(a) b2) -> int {
      return 1;
    };
    M(a, a);
  };
  L(3);
}
template<class T> void foo(T) {
 auto L = [](auto a) { return a; };
}
template void foo(int);
} // end ns nested_generic_lambdas_123

namespace nested_fptr_235 {
int test()
{
  auto L = [](auto b) {
    return [](auto a) ->decltype(a) { return a; };
  };
  int (*fp)(int) = L(8);
  fp(5);
  L(3);
  char (*fc)(char) = L('a');
  fc('b');
  L('c');
  double (*fd)(double) = L(3.14);
  fd(3.14);
  fd(6.26);
  return 0;
}
int run = test();
}

namespace fptr_with_decltype_return_type {
template<class F, class ... Rest> F& FirstArg(F& f, Rest& ... r) { return f; };
template<class ... Ts> auto vfun(Ts&& ... ts) {
  print(ts...);
  return FirstArg(ts...);
}
int test()
{
 {
   auto L = [](auto ... As) {
    return [](auto b) ->decltype(b) {
      vfun([](decltype(As) a) -> decltype(a) { return a; } ...)(first<decltype(As)...>{});
      return decltype(b){};
    };
   };
   auto LL = L(1, 'a', 3.14, "abc");
   LL("dim");
 }
  return 0;
}
int run = test();
}

} // end ns nested_non_capturing_lambda_tests

namespace PR17476 {
struct string {
  string(const char *__s) { }
  string &operator+=(const string &__str) { return *this; }
};

template <class T>
void finalizeDefaultAtomValues() {
  auto startEnd = [](const char * sym) -> void {
    string start("__");
    start += sym;
  };
  startEnd("preinit_array");
}

void f() { finalizeDefaultAtomValues<char>(); }

}

namespace PR17476_variant {
struct string {
  string(const char *__s) { }
  string &operator+=(const string &__str) { return *this; }
};

template <class T>
void finalizeDefaultAtomValues() {
  auto startEnd = [](const T *sym) -> void {
    string start("__");
    start += sym;
  };
  startEnd("preinit_array");
}

void f() { finalizeDefaultAtomValues<char>(); }

}

namespace PR17877_lambda_declcontext_and_get_cur_lambda_disconnect {

template<class T> struct U {
  int t = 0;
};

template<class T>
struct V {
  U<T> size() const { return U<T>{}; }
};

template<typename T>
void Do() {
  V<int> v{};
  [=] { v.size(); };
}

}

namespace inclass_lambdas_within_nested_classes {
namespace ns1 {

struct X1 {
  struct X2 {
    enum { E = [](auto i) { return i; }(3) }; //expected-error{{inside of a constant expression}}\
    int L = ([] (int i) { return i; })(2);

    int B : ([](int i) { return i; })(3); //expected-error{{inside of a constant expression}}\
    int arr[([](int i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
                                           //expected-error{{must have a constant size}}
    int (*fp)(int) = [](int i) { return i; };
    void fooptr(int (*fp)(char) = [](char c) { return 0; }) { }
    int L2 = ([](auto i) { return i; })(2);
    void fooG(int i = ([] (auto i) { return i; })(2)) { }
    int BG : ([](auto i) { return i; })(3); //expected-error{{inside of a constant expression}}  \
    int arrG[([](auto i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
                                             //expected-error{{must have a constant size}}
    int (*fpG)(int) = [](auto i) { return i; };
    void fooptrG(int (*fp)(char) = [](auto c) { return 0; }) { }
  };
};
} //end ns

namespace ns2 {
struct X1 {
  template<class T>
  struct X2 {
    int L = ([] (T i) { return i; })(2);
    void foo(int i = ([] (int i) { return i; })(2)) { }
    int B : ([](T i) { return i; })(3); //expected-error{{inside of a constant expression}}\
    int arr[([](T i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
                                         //expected-error{{must have a constant size}}
    int (*fp)(T) = [](T i) { return i; };
    void fooptr(T (*fp)(char) = [](char c) { return 0; }) { }
    int L2 = ([](auto i) { return i; })(2);
    void fooG(T i = ([] (auto i) { return i; })(2)) { }
    int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}\
                                            //expected-error{{inside of a constant expression}}
    int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}} \
                                             //expected-error{{inside of a constant expression}}
    int (*fpG)(T) = [](auto i) { return i; };
    void fooptrG(T (*fp)(char) = [](auto c) { return 0; }) { }
    template<class U = char> int fooG2(T (*fp)(U) = [](auto a) { return 0; }) { return 0; }
    template<class U = char> int fooG3(T (*fp)(U) = [](auto a) { return 0; });
  };
};
template<class T>
template<class U>
int X1::X2<T>::fooG3(T (*fp)(U)) { return 0; }
X1::X2<int> x2; //expected-note {{in instantiation of}}
int run1 = x2.fooG2();
int run2 = x2.fooG3();
} // end ns

} //end ns inclass_lambdas_within_nested_classes

namespace pr21684_disambiguate_auto_followed_by_ellipsis_no_id {
int a = [](auto ...) { return 0; }();
}

namespace PR22117 {
  int x = [](auto) {
    return [](auto... run_args) {
      using T = int(decltype(run_args)...);
      return 0;
    };
  }(0)(0);
}

namespace PR23716 {
template<typename T>
auto f(T x) {
  auto g = [](auto&&... args) {
    auto h = [args...]() -> int {
      return 0;
    };
    return h;
  };
  return g;
}

auto x = f(0)();
}

namespace PR13987 {
class Enclosing {
  void Method(char c = []()->char {
    int d = [](auto x)->int {
        struct LocalClass {
          int Method() { return 0; }
        };
      return 0;
    }(0);
    return d; }()
  );
};

class Enclosing2 {
  void Method(char c = [](auto x)->char {
    int d = []()->int {
        struct LocalClass {
          int Method() { return 0; }
        };
      return 0;
    }();
    return d; }(0)
  );
};

class Enclosing3 {
  void Method(char c = [](auto x)->char {
    int d = [](auto y)->int {
        struct LocalClass {
          int Method() { return 0; }
        };
      return 0;
    }(0);
    return d; }(0)
  );
};
}

namespace PR32638 {
 void test() {
    [](auto x) noexcept(noexcept(x)) { } (0);
 }
}