/**
  * Main entry point for PKP statistics reports.
  *
  * @see <http://pkp.sfu.ca/wiki/index.php/OJSdeStatisticsConcept#Input_and_Output_Formats_.28Aggregation.2C_Filters.2C_Metrics_Data.29>
  * for a full specification of the input and output format of this method.
  *
  * @param $metricType null|string|array metrics selection
  *   NB: If you want to use the default metric on journal level then you must
  *   set $metricType = null and add an explicit filter on a single journal ID.
  *   Otherwise the default site-level metric will be used.
  * @param $columns string|array column (aggregation level) selection
  * @param $filters array report-level filter selection
  * @param $orderBy array order criteria
  * @param $range null|DBResultRange paging specification
  *
  * @return null|array The selected data as a simple tabular result set or
  *   null if the given parameter combination is not supported.
  */
 function getMetrics($metricType = null, $columns = array(), $filter = array(), $orderBy = array(), $range = null)
 {
     import('classes.statistics.StatisticsHelper');
     $statsHelper = new StatisticsHelper();
     // Check the parameter format.
     if (!(is_array($filter) && is_array($orderBy))) {
         return null;
     }
     // Check whether which context we are.
     $context = $statsHelper->getContext($filter);
     // Identify and canonicalize filtered metric types.
     $defaultSiteMetricType = $this->getDefaultMetricType();
     $siteMetricTypes = $this->getMetricTypes();
     $metricType = $statsHelper->canonicalizeMetricTypes($metricType, $context, $defaultSiteMetricType, $siteMetricTypes);
     if (!is_array($metricType)) {
         return null;
     }
     $metricTypeCount = count($metricType);
     // Canonicalize columns.
     if (is_scalar($columns)) {
         $columns = array($columns);
     }
     // The metric type dimension is not additive. This imposes two important
     // restrictions on valid report descriptions:
     // 1) We need at least one metric Type to be specified.
     if ($metricTypeCount === 0) {
         return null;
     }
     // 2) If we have multiple metrics then we have to force inclusion of
     // the metric type column to avoid aggregation over several metric types.
     if ($metricTypeCount > 1) {
         if (!in_array(STATISTICS_DIMENSION_METRIC_TYPE, $columns)) {
             array_push($columns, STATISTICS_DIMENSION_METRIC_TYPE);
         }
     }
     // Retrieve report plugins.
     if (is_a($context, 'Context')) {
         $contextId = $context->getId();
     } else {
         $contextId = CONTEXT_SITE;
     }
     $reportPlugins = PluginRegistry::loadCategory('reports', true, $contextId);
     if (!is_array($reportPlugins)) {
         return null;
     }
     // Run through all report plugins and try to retrieve the requested metrics.
     $report = array();
     foreach ($reportPlugins as $reportPlugin) {
         // Check whether one (or more) of the selected metrics can be
         // provided by this plugin.
         $availableMetrics = $reportPlugin->getMetricTypes();
         $availableMetrics = array_intersect($availableMetrics, $metricType);
         if (count($availableMetrics) == 0) {
             continue;
         }
         // Retrieve a (partial) report.
         $partialReport = $reportPlugin->getMetrics($availableMetrics, $columns, $filter, $orderBy, $range);
         // Merge the partial report with the main report.
         $report = array_merge($report, $partialReport);
         // Remove the found metric types from the metric type array.
         $metricType = array_diff($metricType, $availableMetrics);
     }
     // Check whether we found all requested metric types.
     if (count($metricType) > 0) {
         return null;
     }
     // Return the report.
     return $report;
 }