// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void AlignSections::execute()
{
  setErrorCondition(0);
  dataCheck();
  if(getErrorCondition() < 0) { return; }

  DataContainer::Pointer m = getDataContainerArray()->getDataContainer(getDataContainerName());

  size_t dims[3] = { 0, 0, 0 };
  m->getGeometryAs<ImageGeom>()->getDimensions(dims);

  int64_t xspot = 0, yspot = 0;
  int64_t newPosition = 0;
  int64_t currentPosition = 0;

  std::vector<int64_t> xshifts(dims[2], 0);
  std::vector<int64_t> yshifts(dims[2], 0);

  find_shifts(xshifts, yshifts);


  QList<QString> voxelArrayNames = m->getAttributeMatrix(getCellAttributeMatrixName())->getAttributeArrayNames();
  size_t progIncrement = dims[2] / 100;
  size_t prog = 1;
  size_t progressInt = 0;
  size_t slice = 0;

  for (size_t i = 1; i < dims[2]; i++)
  {
    if (i > prog)
    {

      progressInt = ((float)i / dims[2]) * 100.0f;
      QString ss = QObject::tr("Transferring Cell Data || %1% Complete").arg(progressInt);
      notifyStatusMessage(getMessagePrefix(), getHumanLabel(), ss);
      prog = prog + progIncrement;
    }
    if (getCancel() == true)
    {
      return;
    }
    slice = (dims[2] - 1) - i;
    for (size_t l = 0; l < dims[1]; l++)
    {
      for (size_t n = 0; n < dims[0]; n++)
      {
        if (yshifts[i] >= 0) { yspot = l; }
        else if (yshifts[i] < 0) { yspot = dims[1] - 1 - l; }
        if (xshifts[i] >= 0) { xspot = n; }
        else if (xshifts[i] < 0) { xspot = dims[0] - 1 - n; }
        newPosition = (slice * dims[0] * dims[1]) + (yspot * dims[0]) + xspot;
        currentPosition = (slice * dims[0] * dims[1]) + ((yspot + yshifts[i]) * dims[0]) + (xspot + xshifts[i]);
        if ((yspot + yshifts[i]) >= 0 && (yspot + yshifts[i]) <= static_cast<int64_t>(dims[1]) - 1 && (xspot + xshifts[i]) >= 0
            && (xspot + xshifts[i]) <= static_cast<int64_t>(dims[0]) - 1)
        {
          for (QList<QString>::iterator iter = voxelArrayNames.begin(); iter != voxelArrayNames.end(); ++iter)
          {
            IDataArray::Pointer p = m->getAttributeMatrix(getCellAttributeMatrixName())->getAttributeArray(*iter);
            p->copyTuple( static_cast<size_t>(currentPosition), static_cast<size_t>(newPosition));
          }
        }
        if ((yspot + yshifts[i]) < 0 || (yspot + yshifts[i]) > static_cast<int64_t>(dims[1] - 1) || (xspot + xshifts[i]) < 0
            || (xspot + xshifts[i]) > static_cast<int64_t>(dims[0]) - 1)
        {
          for (QList<QString>::iterator iter = voxelArrayNames.begin(); iter != voxelArrayNames.end(); ++iter)
          {
            IDataArray::Pointer p = m->getAttributeMatrix(getCellAttributeMatrixName())->getAttributeArray(*iter);
            EXECUTE_FUNCTION_TEMPLATE(this, initializeArrayValues, p, p, newPosition)
          }
        }
      }
    }
  }

  // If there is an error set this to something negative and also set a message
  notifyStatusMessage(getHumanLabel(), "Complete");
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void AlignSections::execute()
{
  setErrorCondition(0);
  dataCheck();
  if(getErrorCondition() < 0) { return; }

  DataContainer::Pointer m = getDataContainerArray()->getDataContainer(getDataContainerName());

  size_t udims[3] = { 0, 0, 0 };
  m->getGeometryAs<ImageGeom>()->getDimensions(udims);
#if (CMP_SIZEOF_SIZE_T == 4)
  typedef int32_t DimType;
#else
  typedef int64_t DimType;
#endif
  DimType dims[3] =
  {
    static_cast<DimType>(udims[0]),
    static_cast<DimType>(udims[1]),
    static_cast<DimType>(udims[2]),
  };

  DimType slice = 0;
  DimType xspot = 0, yspot = 0;
  DimType newPosition = 0;
  DimType currentPosition = 0;

  std::vector<int64_t> xshifts(dims[2], 0);
  std::vector<int64_t> yshifts(dims[2], 0);

  find_shifts(xshifts, yshifts);

  if (getSubtractBackground())
  {
    /**fit x and y shifts to lines
     *
     * y = mx + b
     *
     * m = (n*sum(x_i * y_i) - sum(x_i) * sum(y_i)) / (n*sum(x_i^2)-sum(x_i)^2
     *
     * b = (sum(y_i)-m*sum(x_i))/n
     *
     */

    // same for both
    double sumX = 0.0; // sum(x_i)
    double sumX_2 = 0.0; // sum(x_i^2)

    // x shift line
    double x_sumY = 0.0; // sum(y_i)
    double x_sumXY = 0.0; // sum(x_i * y_i)

    // y shift line
    double y_sumY = 0.0; // sum(y_i)
    double y_sumXY = 0.0; // sum(x_i * y_i)

    for (DimType iter = 0; iter < dims[2]; iter++)
    {
      slice = static_cast<DimType>( (dims[2] - 1) - iter );
      sumX = static_cast<double>(sumX + iter);
      sumX_2 = static_cast<double>(sumX_2 + iter * iter);
      x_sumY = static_cast<double>(x_sumY + xshifts[iter]);
      x_sumXY = static_cast<double>(x_sumXY + iter * xshifts[iter]);
      y_sumY = static_cast<double>(y_sumY + yshifts[iter]);
      y_sumXY = static_cast<double>(y_sumXY + iter * yshifts[iter]);
    }

    double mx = static_cast<double>((dims[2] * x_sumXY - x_sumXY) / (dims[2] * sumX_2 - sumX));
    double my = static_cast<double>((dims[2] * y_sumXY - y_sumXY) / (dims[2] * sumX_2 - sumX));

    // adjust shifts so that fit line has 0 slope (~ends of the sample are fixed)
    for (DimType iter = 1; iter < dims[2]; iter++)
    {
      slice = (dims[2] - 1) - iter;
      xshifts[iter] = static_cast<int64_t>(xshifts[iter] - iter * mx);
      yshifts[iter] = static_cast<int64_t>(yshifts[iter] - iter * my);
    }
  }

  QList<QString> voxelArrayNames = m->getAttributeMatrix(getCellAttributeMatrixName())->getAttributeArrayNames();
  DimType progIncrement = dims[2] / 100;
  DimType prog = 1;
  DimType progressInt = 0;

  for (DimType i = 1; i < dims[2]; i++)
  {
    if (i > prog)
    {

      progressInt = ((float)i / dims[2]) * 100.0f;
      QString ss = QObject::tr("Transferring Cell Data || %1% Complete").arg(progressInt);
      notifyStatusMessage(getMessagePrefix(), getHumanLabel(), ss);
      prog = prog + progIncrement;
    }
    if (getCancel() == true)
    {
      return;
    }
    slice = (dims[2] - 1) - i;
    for (DimType l = 0; l < dims[1]; l++)
    {
      for (DimType n = 0; n < dims[0]; n++)
      {
        if (yshifts[i] >= 0) { yspot = l; }
        else if (yshifts[i] < 0) { yspot = dims[1] - 1 - l; }
        if (xshifts[i] >= 0) { xspot = n; }
        else if (xshifts[i] < 0) { xspot = dims[0] - 1 - n; }
        newPosition = (slice * dims[0] * dims[1]) + (yspot * dims[0]) + xspot;
        currentPosition = (slice * dims[0] * dims[1]) + ((yspot + yshifts[i]) * dims[0]) + (xspot + xshifts[i]);
        if ((yspot + yshifts[i]) >= 0 && (yspot + yshifts[i]) <= dims[1] - 1 && (xspot + xshifts[i]) >= 0
            && (xspot + xshifts[i]) <= dims[0] - 1)
        {
          for (QList<QString>::iterator iter = voxelArrayNames.begin(); iter != voxelArrayNames.end(); ++iter)
          {
            IDataArray::Pointer p = m->getAttributeMatrix(getCellAttributeMatrixName())->getAttributeArray(*iter);
            p->copyTuple(currentPosition, newPosition);
          }
        }
        if ((yspot + yshifts[i]) < 0 || (yspot + yshifts[i]) > dims[1] - 1 || (xspot + xshifts[i]) < 0
            || (xspot + xshifts[i]) > dims[0] - 1)
        {
          for (QList<QString>::iterator iter = voxelArrayNames.begin(); iter != voxelArrayNames.end(); ++iter)
          {
            IDataArray::Pointer p = m->getAttributeMatrix(getCellAttributeMatrixName())->getAttributeArray(*iter);
            p->initializeTuple(newPosition, 0);
          }
        }
      }
    }
  }

  // If there is an error set this to something negative and also set a message
  notifyStatusMessage(getHumanLabel(), "Complete");
}