#!/usr/bin/env php
<?php

// FIXME: Make this a proper app with unit-tests

$civi_pkgs_dir = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'packages';
require_once $civi_pkgs_dir . DIRECTORY_SEPARATOR . 'simple_html_dom.php';
exit(main($argv));

/**
 * Scan a series of files for suspicious code
 *
 * example: find templates -name '*.tpl' | xargs php tools/scripts/tpl-lint
 *
 * @param array $argv
 * @return int
 */
function main($argv) {
  $files = $argv;
  array_shift($files); // skip program name
  foreach ($files as $file) {
    check_tpl($file, function ($code, $message) use ($file) {
      printf("[%s] %s\n", $file, $message);
    });
  }
  return 0;
}

/**
 * Scan a file for suspicious code
 *
 * @param string $file
 * @param callable $reporter
 * @return void
 */
function check_tpl($file, $reporter) {
  $html = file_get_html($file);
  foreach ($html->find('a') as $a) {
    check_a($a, $reporter);
  }
}

/**
 * Scan an <A> tag
 *
 * @param object $a
 * @param callable $reporter
 * @return void
 */
function check_a($a, $reporter) {
  if (!$a->hasAttribute('href')) {
    // anchor, don't care
    return;
  }

  $href = trim($a->getAttribute('href'));
  if (preg_match('/javascript:/', $href)) {
    $reporter('javascript-url', "<a> has javascript url: $href");
    return;
  }
  if ($href == '#' && $a->hasAttribute('onclick')) {
    $onclick = $a->getAttribute('onclick');
    if (!js_returns_false($onclick) && !js_returns_func($onclick)) {
      $reporter('a-no-return', "<a> has href=# but handler fails to return false: $onclick");
      return;
    }
  }
  if ($href != '#' && $a->hasAttribute('onclick')) {
    $onclick = $a->getAttribute('onclick');
    $reporter('a-double-action', "<a> has both URL ($href) and onclick ($onclick)");
    return;
  }
}

/**
 * Determine if snippet of JS returns strictly false
 * @param $js
 * @return bool
 */
function js_returns_false($js) {
  return
    // last in a series of statements
    preg_match('/; *return +false *; *$/', $js)
    ||
    // only statement
    preg_match('/^ *return +false *;? *$/', $js);
}

/**
 * Determine if snippet of JS returns a function call
 * @param $js
 * @return int
 */
function js_returns_func($js) {
  return preg_match('/^ *return +[a-zA-Z0-9\._$]+\(/', $js);
}
