// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void BoundaryPhaseWidget::extractStatsData(VoxelDataContainer::Pointer m, int index)
{

  setPhaseIndex(index);

  IDataArray* iDataPtr = NULL;

  iDataPtr = m->getEnsembleData(DREAM3D::EnsembleData::CrystalStructures).get();
  UInt32ArrayType* data = UInt32ArrayType::SafeObjectDownCast<IDataArray*, UInt32ArrayType*>(iDataPtr);
  m_CrystalStructure = data->GetValue(index);

  iDataPtr = m->getEnsembleData(DREAM3D::EnsembleData::PhaseTypes).get();
  data = UInt32ArrayType::SafeObjectDownCast<IDataArray*, UInt32ArrayType*>(iDataPtr);
  m_PhaseType = data->GetValue(index);

  iDataPtr = m->getEnsembleData(DREAM3D::EnsembleData::Statistics).get();
  StatsDataArray* statsDataArray = StatsDataArray::SafeObjectDownCast<IDataArray*, StatsDataArray*>(iDataPtr);
  if (statsDataArray == NULL)
  {
    return;
  }
  StatsData::Pointer statsData = statsDataArray->getStatsData(index);
  BoundaryStatsData* boundaryStatsData = BoundaryStatsData::SafePointerDownCast(statsData.get());

  m_PhaseFraction = boundaryStatsData->getPhaseFraction();

}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void BoundaryPhaseWidget::extractStatsData(AttributeMatrix::Pointer attrMat, int index)
{

  setPhaseIndex(index);

  IDataArray::Pointer iDataArray = attrMat->getAttributeArray(DREAM3D::EnsembleData::CrystalStructures);
  unsigned int* attributeArray = boost::dynamic_pointer_cast< UInt32ArrayType >(iDataArray)->getPointer(0);
  m_CrystalStructure = attributeArray[index];

  iDataArray = attrMat->getAttributeArray(DREAM3D::EnsembleData::PhaseTypes);
  attributeArray = boost::dynamic_pointer_cast< UInt32ArrayType >(iDataArray)->getPointer(0);
  m_PhaseType = attributeArray[index];

  iDataArray = attrMat->getAttributeArray(DREAM3D::EnsembleData::Statistics);
  StatsDataArray* statsDataArray = StatsDataArray::SafeObjectDownCast<IDataArray*, StatsDataArray*>(iDataArray.get());
  if (statsDataArray == NULL)
  {
    return;
  }
  StatsData::Pointer statsData = statsDataArray->getStatsData(index);
  BoundaryStatsData* boundaryStatsData = BoundaryStatsData::SafePointerDownCast(statsData.get());

  m_PhaseFraction = boundaryStatsData->getPhaseFraction();

}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int BoundaryPhaseWidget::gatherStatsData(VoxelDataContainer::Pointer m)
{
  if (m_PhaseIndex < 1)
  {
    QMessageBox::critical(this, tr("StatsGenerator"),
                                  tr("The Phase Index is Less than 1. This is not allowed."),
                                  QMessageBox::Default);
    return -1;
  }
  int retErr = 0;
  float calcPhaseFraction = m_PhaseFraction / m_TotalPhaseFraction;

  typedef DataArray<unsigned int> XTalStructArrayType;
  typedef DataArray<unsigned int> PhaseTypeArrayType;
  typedef DataArray<unsigned int> ShapeTypeArrayType;
  size_t ensembles = m->getNumEnsembleTuples();

  // Get pointers
  unsigned int* crystalStructures = m->getEnsembleDataSizeCheck<unsigned int, XTalStructArrayType, AbstractFilter>(DREAM3D::EnsembleData::CrystalStructures, ensembles, 1, NULL);
  unsigned int* phaseTypes = m->getEnsembleDataSizeCheck<unsigned int, PhaseTypeArrayType, AbstractFilter>(DREAM3D::EnsembleData::PhaseTypes, ensembles, 1, NULL);

  //unsigned int* shapeTypes = m->getEnsembleDataSizeCheck<unsigned int, ShapeTypeArrayType, AbstractFilter>(DREAM3D::EnsembleData::ShapeTypes, ensembles*1, NULL);

  crystalStructures[m_PhaseIndex] = m_CrystalStructure;
  phaseTypes[m_PhaseIndex] = m_PhaseType;

  StatsDataArray* statsDataArray = StatsDataArray::SafeObjectDownCast<IDataArray*, StatsDataArray*>(m->getEnsembleData(DREAM3D::EnsembleData::Statistics).get());
  StatsData::Pointer statsData = statsDataArray->getStatsData(m_PhaseIndex);
  BoundaryStatsData* boundaryStatsData = BoundaryStatsData::SafePointerDownCast(statsData.get());

  boundaryStatsData->setPhaseFraction(calcPhaseFraction);

  return retErr;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int BoundaryPhaseWidget::gatherStatsData(AttributeMatrix::Pointer attrMat)
{
  if (m_PhaseIndex < 1)
  {
    QMessageBox::critical(this, tr("StatsGenerator"),
                          tr("The Phase Index is Less than 1. This is not allowed."),
                          QMessageBox::Default);
    return -1;
  }
  int retErr = 0;
  float calcPhaseFraction = m_PhaseFraction / m_TotalPhaseFraction;

  //size_t ensembles = attrMat->getNumTuples();

  // Get pointers
  IDataArray::Pointer iDataArray = attrMat->getAttributeArray(DREAM3D::EnsembleData::CrystalStructures);
  unsigned int* crystalStructures = boost::dynamic_pointer_cast< UInt32ArrayType >(iDataArray)->getPointer(0);
  iDataArray = attrMat->getAttributeArray(DREAM3D::EnsembleData::PhaseTypes);
  unsigned int* phaseTypes = boost::dynamic_pointer_cast< UInt32ArrayType >(iDataArray)->getPointer(0);

  crystalStructures[m_PhaseIndex] = m_CrystalStructure;
  phaseTypes[m_PhaseIndex] = m_PhaseType;

  StatsDataArray* statsDataArray = StatsDataArray::SafeObjectDownCast<IDataArray*, StatsDataArray*>(attrMat->getAttributeArray(DREAM3D::EnsembleData::Statistics).get());
  if (NULL != statsDataArray)
  {
    StatsData::Pointer statsData = statsDataArray->getStatsData(m_PhaseIndex);
    BoundaryStatsData* boundaryStatsData = BoundaryStatsData::SafePointerDownCast(statsData.get());

    boundaryStatsData->setPhaseFraction(calcPhaseFraction);
  }
  return retErr;
}
void fitData(IDataArray::Pointer inDataPtr, float* ensembleArray, int32_t* eIds, size_t numEnsembles, uint32_t dType, bool removeBiasedFeatures, bool* biasedFeatures)
{
  typename DataArray<T>::Pointer inputDataPtr = std::dynamic_pointer_cast<DataArray<T> >(inDataPtr);

  StatsData::Pointer sData = StatsData::New();

  std::vector<DistributionAnalysisOps::Pointer> distributionAnalysis;
  distributionAnalysis.push_back(BetaOps::New());
  distributionAnalysis.push_back(LogNormalOps::New());
  distributionAnalysis.push_back(PowerLawOps::New());

  QString distType;
  int32_t numComp = 1;

  // Determining number of components and name given distribution type
  if (dType == SIMPL::DistributionType::Beta) { distType = "Beta", numComp = SIMPL::DistributionType::BetaColumnCount; }
  else if (dType == SIMPL::DistributionType::LogNormal) { distType = "LogNormal", numComp = SIMPL::DistributionType::LogNormalColumnCount; }
  else if (dType == SIMPL::DistributionType::Power) { distType = "PowerLaw", numComp = SIMPL::DistributionType::PowerLawColumnCount; }

  T* fPtr = inputDataPtr->getPointer(0);

  std::vector<FloatArrayType::Pointer> dist;
  std::vector<std::vector<float > > values;

  size_t numfeatures = inputDataPtr->getNumberOfTuples();

  dist.resize(numEnsembles);
  values.resize(numEnsembles);

  for(size_t i = 1; i < numEnsembles; i++)
  {
    dist[i] = sData->CreateDistributionArrays(dType);
  }

  int32_t ensemble = 0;
  for (size_t i = 1; i < numfeatures; i++)
  {
    if (removeBiasedFeatures == false || biasedFeatures[i] == false)
    {
      ensemble = eIds[i];
      values[ensemble].push_back(static_cast<float>(fPtr[i]));
    }
  }
  for (size_t i = 1; i < numEnsembles; i++)
  {
    distributionAnalysis[dType]->calculateParameters(values[i], dist[i]);
    for (int32_t j = 0; j < numComp; j++)
    {
      FloatArrayType::Pointer data = dist[i];
      ensembleArray[numComp * i + j] = data->getValue(j);
    }
  }
}