/// Split this function (if needed) into a list of independent functions.
/// The number of functions must be the number of domains this function is
/// working on (== getNumberDomains()). The result of evaluation of the
/// created functions on their domains must be the same as if this function
/// was evaluated on the composition of those domains.
std::vector<IFunction_sptr>
CompositeFunction::createEquivalentFunctions() const {
  auto nd = getNumberDomains();
  if (nd == 1) {
    return std::vector<IFunction_sptr>(
        1, FunctionFactory::Instance().createInitialized(asString()));
  }

  auto nf = nFunctions();
  std::vector<std::vector<IFunction_sptr>> equiv;
  equiv.reserve(nf);
  for (size_t i = 0; i < nf; ++i) {
    equiv.push_back(getFunction(i)->createEquivalentFunctions());
  }

  std::vector<IFunction_sptr> funs;
  funs.reserve(nd);
  for (size_t i = 0; i < nd; ++i) {
    auto comp = new CompositeFunction;
    funs.push_back(IFunction_sptr(comp));
    for (size_t j = 0; j < nf; ++j) {
      comp->addFunction(equiv[j][i]);
    }
  }
  return funs;
}
/// Build a function for a single spectrum.
API::IFunction_sptr CrystalFieldMultiSpectrum::buildSpectrum(
    int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf,
    double temperature, double fwhm, size_t iSpec) const {
  FunctionValues values;
  calcExcitations(nre, en, wf, temperature, values, iSpec);
  m_nPeaks[iSpec] = CrystalFieldUtils::calculateNPeaks(values);

  auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
  auto peakShape = IFunction::getAttribute("PeakShape").asString();
  auto bkgdShape = IFunction::getAttribute("Background").asUnquotedString();
  size_t nRequiredPeaks = IFunction::getAttribute("NPeaks").asInt();
  bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();

  if (!bkgdShape.empty() && bkgdShape.find("name=") != 0 &&
      bkgdShape.front() != '(') {
    bkgdShape = "name=" + bkgdShape;
  }

  auto spectrum = new CompositeFunction;
  auto background =
      API::FunctionFactory::Instance().createInitialized(bkgdShape);
  spectrum->addFunction(background);

  m_nPeaks[iSpec] = CrystalFieldUtils::buildSpectrumFunction(
      *spectrum, peakShape, values, m_fwhmX[iSpec], m_fwhmY[iSpec],
      fwhmVariation, fwhm, nRequiredPeaks, fixAllPeaks);
  return IFunction_sptr(spectrum);
}
/**
 * Returns the shrared pointer to the function conataining a parameter
 * @param ref :: The reference
 * @return A function containing parameter pointed to by ref
 */
IFunction_sptr
CompositeFunction::getContainingFunction(const ParameterReference &ref) const {
  for (size_t iFun = 0; iFun < nFunctions(); iFun++) {
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams()) {
      return fun;
    }
  }
  return IFunction_sptr();
}
/**
 * Is the function set and valid?
 */
bool CostFuncFitting::isValid() const
{
  return m_function != IFunction_sptr();
}