<?php
/*  Copyright 2018 by Chuck Goldstein (cgpmw13@codingmaniac.com).
    You can redistribute this file and/or modify it under
    the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.

    This recipe circumvents the deprecated create_function()
    warnings in PHP 7.2. It can also summarize calls to 
    PCCF, PPRE and Markup_e in the StopWatch.

    This recipe requires PmWiki version 2.2.108 or later.
*/

function PCF_PCCF($code, $template = 'default', $args = '$m') {
  global $CallbackFnTemplates, $CallbackFunctions, $PCCFOverrideFunction;
  if (!isset($CallbackFnTemplates[$template]))
    Abort("No \$CallbackFnTemplates[$template]).");
  $code = sprintf($CallbackFnTemplates[$template], $code);
  if (!isset($CallbackFunctions[$code])) {
    $fn = PCF($args, $code);
    if ($fn) $CallbackFunctions[$code] = $fn;
    else StopWatch("Failed to create callback function: ".PHSC($code));
  } else {
    PCFWarn();
  }
  return $CallbackFunctions[$code];
}

$PCCFOverrideFunction = 'PCF_PCCF';

$PCFWarnCtrs = array();
if (! isset($StopWatch)) $StopWatch = array();

unset($HTMLFooterFmt['stopwatch']);
$HTMLFooterFmt['PCFWarnAddCounts'] = 'function:PCFWarnAddCounts';
$HTMLFooterFmt['stopwatch'] = 'function:PCFStopWatchHTML 1';

function PCF($args, $code) {
  global $EnablePCF;
  if (IsEnabled($EnablePCF, 0)) {
    static $plambdaCnt = 0;
    $fn = "plambda_" . ++$plambdaCnt;
    eval ("function {$fn} ({$args}) {{$code}}");
  } else {
    $fn = create_function($args, $code);
  }
  PCFWarn(' (function created)');
  return $fn;
}

function PCFWarn($sfx = '') {
  global $EnablePCFWarn, $PCFRootPat;
  global $StopWatch, $PCFWarnCtrs;
  if (IsEnabled($EnablePCFWarn, 0)) {
    if (function_exists('debug_backtrace')) {
      $dbg = debug_backtrace();
      for ($i=1, $ilen=count($dbg); $i<$ilen; $i++) {
        $func = $dbg[$i]['function'];
        if (! ($func == 'PCF' || $func == 'PCCF' || $func == 'PPRE' || $func == 'Markup_e' || $func == 'PCF_PCCF')) {
          break;
        }
      }
      $dbginfo = $dbg[$i-1];
      $file = $dbginfo['file'];
      if (isset($PCFRootPat)) {
        $file = preg_replace($PCFRootPat, '$1', $file);
      }
      $msgkey = "PCF_" . $dbginfo['function'] . '_' . $file . "_" . $dbginfo['line'];
      if (! isset($PCFWarnCtrs[$msgkey])) {
        $ndx = count($StopWatch);
        $PCFWarnCtrs[$msgkey] = array(0=>1, $ndx);
        $msg = "PCFWarn: {$dbginfo['function']} was called from {$file} line {$dbginfo['line']}!";
        $StopWatch[] = "{$msg}{$sfx}";
      } else {
        ++$PCFWarnCtrs[$msgkey][0];
      }
    }
    else {
      $StopWatch['PCF_unknown'] = "PCF was Called!";
    }
  }
}

function PCFWarnAddCounts () {
  global $StopWatch, $PCFWarnCtrs;
  foreach ($PCFWarnCtrs as $val) {
    list($cnt, $ndx) = $val;
    $times = $cnt . ($cnt > 1 ? ' times' : ' time');
    $StopWatch[$ndx] = preg_replace('/(\\d)!/', "\$1 $times!", $StopWatch[$ndx]);
  }
}

function PCFStopWatchHTML($pagename, $print = 0) {
  global $StopWatch;
  StopWatch('now');
  $l = strlen(count($StopWatch));
  $out = '<pre>';
  foreach((array)$StopWatch as $i => $x)
    $out .= sprintf("%{$l}d: %s\n", $i, $x);
  $out .= '</pre>';
  if (is_array($StopWatch)) array_pop($StopWatch);
  if ($print) print $out;
  return $out;
}