// Assumes: metrics are of type Metric::SampledDesc and values are
// only at leaves (CCT::Stmt)
void
MetricComponentsFact::make(Prof::CallPath::Profile& prof)
{
  using namespace Prof;
  
  // ------------------------------------------------------------
  // Create destination metric descriptors and mapping from source
  //   metrics to destination metrics
  // ------------------------------------------------------------
  std::vector<uint> metricSrcIds;
  std::vector<uint> metricDstIds;
  
  Metric::Mgr* metricMgr = prof.metricMgr();

  uint numMetrics_orig = metricMgr->size();
  for (uint mId = 0; mId < numMetrics_orig; ++mId) {
    Metric::ADesc* m = metricMgr->metric(mId);
    if (MetricComponentsFact::isTimeMetric(m)) {
      DIAG_Assert(typeid(*m) == typeid(Metric::SampledDesc), DIAG_UnexpectedInput << "temporary sanity check");
      
      MetricComponentsFact::convertToWorkMetric(m);
      metricSrcIds.push_back(m->id());

      Metric::ADesc* m_new = m->clone();
      m_new->nameBase("overhead");
      m_new->description("parallel overhead");

      metricMgr->insert(m_new);
      DIAG_Assert(m_new->id() >= numMetrics_orig, "Currently, we assume new metrics are added at the end of the metric vector.");
      
      metricDstIds.push_back(m_new->id());
    }
  }

  if (metricSrcIds.empty()) {
    return;
  }

  // ------------------------------------------------------------
  // Create values for metric components
  // ------------------------------------------------------------
  make(prof.cct()->root(), metricSrcIds, metricDstIds, false);
}
// make: ...temporary holding pattern...
void
MPIBlameShiftIdlenessFact::make(Prof::CallPath::Profile& prof)
{
  using namespace Prof;

  // ------------------------------------------------------------
  // Create destination metric descriptors and mapping from source
  //   metrics to destination metrics
  // ------------------------------------------------------------
  std::vector<uint> metricSrcIds;
  std::vector<uint> metricBalanceIds;
  std::vector<uint> metricImbalInclIds, metricImbalExclIds;
  std::vector<uint> metricIdleInclIds;

  Metric::Mgr* metricMgr = prof.metricMgr();

  uint numMetrics_orig = metricMgr->size();
  for (uint mId = 0; mId < numMetrics_orig; ++mId) {
    Metric::ADesc* m = metricMgr->metric(mId);

    // find main source metric
    if (MetricComponentsFact::isTimeMetric(m)
	&& MetricComponentsFact::isDerivedMetric(m, s_sum)
	&& m->type() == Metric::ADesc::TyIncl
	&& m->isVisible() /* not a temporary */) {

      DIAG_Assert(m->computedType() == Prof::Metric::ADesc::ComputedTy_NonFinal,
		  DIAG_UnexpectedInput);
      metricSrcIds.push_back(m->id());

      // FIXME: For now we use only Metric::ADesc::DerivedIncrDesc()
      //   We should also support Metric::ADesc::DerivedDesc()
      DIAG_Assert(typeid(*m) == typeid(Metric::DerivedIncrDesc), DIAG_UnexpectedInput);

      Metric::DerivedIncrDesc* m_imbalIncl =
	static_cast<Metric::DerivedIncrDesc*>(m->clone());
      m_imbalIncl->nameBase("imbalance" + s_sum);
      m_imbalIncl->description("imbalance for MPI SPMD executions");
      m_imbalIncl->expr(new Metric::SumIncr(Metric::IData::npos, // FIXME:Sum
					    Metric::IData::npos));

      Metric::DerivedIncrDesc* m_imbalExcl =
	static_cast<Metric::DerivedIncrDesc*>(m_imbalIncl->clone());
      m_imbalExcl->type(Metric::ADesc::TyExcl);
      m_imbalExcl->expr(new Metric::SumIncr(Metric::IData::npos,
					    Metric::IData::npos));
      m_imbalIncl->partner(m_imbalExcl);
      m_imbalExcl->partner(m_imbalIncl);

      Metric::DerivedIncrDesc* m_idleIncl =
	static_cast<Metric::DerivedIncrDesc*>(m->clone());
      m_idleIncl->nameBase("idleness" + s_sum);
      m_idleIncl->description("idleness for MPI executions");
      m_idleIncl->partner(NULL);
      m_idleIncl->expr(new Metric::SumIncr(Metric::IData::npos, // FIXME:Sum
					   Metric::IData::npos));

      metricMgr->insert(m_imbalIncl);
      metricMgr->insert(m_imbalExcl);
      metricMgr->insert(m_idleIncl);

      m_imbalIncl->expr()->accumId(m_imbalIncl->id());
      m_imbalExcl->expr()->accumId(m_imbalExcl->id());
      m_idleIncl->expr()->accumId(m_idleIncl->id());

      DIAG_Assert(m_imbalIncl->id() >= numMetrics_orig && m_imbalExcl->id() >= numMetrics_orig, "Currently, we assume new metrics are added at the end of the metric vector.");
      
      metricImbalInclIds.push_back(m_imbalIncl->id());
      metricImbalExclIds.push_back(m_imbalExcl->id());
      metricIdleInclIds.push_back(m_idleIncl->id());
    }

    // find secondary source metric
    if (MetricComponentsFact::isTimeMetric(m)
	&& MetricComponentsFact::isDerivedMetric(m, s_cfvar)
	&& m->type() == Metric::ADesc::TyIncl
	&& m->isVisible() /* not a temporary */) {
      DIAG_Assert(m->computedType() == Prof::Metric::ADesc::ComputedTy_NonFinal,
		  DIAG_UnexpectedInput);
      metricBalanceIds.push_back(m->id());
    }
  }

  DIAG_Assert(metricSrcIds.size() == metricBalanceIds.size(), DIAG_UnexpectedInput);

  if (metricSrcIds.empty()) {
    return;
  }
  
  // ------------------------------------------------------------
  // Create values for metric components
  // ------------------------------------------------------------

  // Note that metrics are non-finalized!
  CCT::ANode* cctRoot = prof.cct()->root();

  uint metricBalancedId = metricBalanceIds[0];
  Metric::AExprIncr* metricBalancedExpr = dynamic_cast<Metric::DerivedIncrDesc*>(metricMgr->metric(metricBalancedId))->expr();

  Metric::IData cctRoot_mdata(*cctRoot);
  metricBalancedExpr->finalize(cctRoot_mdata);
  
  double balancedThreshold = 1.2 * cctRoot_mdata.demandMetric(metricBalancedId);

  makeMetrics(cctRoot, metricSrcIds,
	      metricImbalInclIds, metricImbalExclIds, metricIdleInclIds,
	      metricBalancedId, metricBalancedExpr, balancedThreshold,
	      NULL, NULL);


  VMAIntervalSet metricDstInclIdSet;
  for (uint i = 0; i < metricImbalInclIds.size(); ++i) {
    uint mId = metricImbalInclIds[i];
    metricDstInclIdSet.insert(VMAInterval(mId, mId + 1)); // [ )

    mId = metricIdleInclIds[i];
    metricDstInclIdSet.insert(VMAInterval(mId, mId + 1)); // [ )
  }

  cctRoot->aggregateMetricsIncl(metricDstInclIdSet);
}