#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
 * Copyright 2012-2023, Bergware International.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation.
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */
?>
<?
$docroot  = '/usr/local/emhttp';
$varroot  = '/var/local/emhttp';
$log      = '/boot/config/parity-checks.log';
$stamps   = '/var/tmp/stamps.ini';
$resync   = '/var/tmp/resync.ini';
$md5_old  = $spot_old = $fs_old = $proc_old = $mover_old = -1;
$remove_resync_files = 0;
$timer = 3;

require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/publish.php";
extract(parse_plugin_cfg('dynamix',true));

// add translations
$_SERVER['REQUEST_URI'] = 'main';
$login_locale = _var($display,'locale');
require_once "$docroot/webGui/include/Translations.php";

$dot = _var($display,'number','.,')[0];
// remember current language
$locale_init = $locale;

function new_parity_log($timestamp) {
  global $log;
  return file_exists($log) ? explode('|',tail($log))[0]!=$timestamp : true;
}
function my_clock($time) {
  if (!$time) return _('less than a minute');
  $days = floor($time/1440);
  $hour = floor($time/60)%24;
  $mins = $time%60;
  return plus($days,'day',($hour|$mins)==0).plus($hour,'hour',$mins==0).plus($mins,'minute',true);
}
function update_translation($locale) {
  global $docroot,$language;
  $language = [];
  if ($locale) {
    $text = "$docroot/languages/$locale/translations.txt";
    if (file_exists($text)) {
      $store = "$docroot/languages/$locale/translations.dot";
      if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
      $language = unserialize(file_get_contents($store));
    }
    $text = "$docroot/languages/$locale/main.txt";
    if (file_exists($text)) {
      $store = "$docroot/languages/$locale/main.dot";
      if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
      $language = array_merge($language,unserialize(file_get_contents($store)));
    }
  }
}
function create_sync($file) {
  return file_exists($file) ? explode(',',file_get_contents($file)) : [];
}
function create_file($file,...$data) {
  if (!file_exists($file)) file_put_contents($file,implode(',',$data));
}
function mover_percent($value) {
  return max(0, min(100, is_numeric($value) ? round($value, 2) : 0));
}
function mover_html($value) {
  return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
function mover_duration($seconds) {
  $seconds = (int)$seconds;
  if ($seconds <= 0) return _('Unknown');
  $hours = floor($seconds / 3600);
  $mins = floor(($seconds % 3600) / 60);
  $secs = $seconds % 60;
  return ($hours ? $hours.':' : '').sprintf($hours ? '%02d:%02d' : '%d:%02d', $mins, $secs);
}
function mover_bar($percent, $text='') {
  $percent = mover_percent($percent);
  $text = $text ?: $percent.'%';
  return "<div class='usage-disk' style='width:50%'><span style='width:$percent%' class='greenbar'></span><span>$text</span></div>";
}
function mover_pid() {
  $pid = trim((string)@file_get_contents('/var/run/mover.pid'));
  return ctype_digit($pid) && (int)$pid > 0 ? (int)$pid : 0;
}
function mover_running_pid() {
  $pid = mover_pid();
  if (!$pid) return 0;
  $cmdline = (string)@file_get_contents("/proc/$pid/cmdline");
  $cmdline = str_replace("\0", ' ', $cmdline);
  return preg_match('/(^|[[:space:]])([^[:space:]]*\/)?mover([[:space:]]|$)/', $cmdline) === 1 ? $pid : 0;
}

while (true) {
	$var = (array)@parse_ini_file("$varroot/var.ini");

	/* Check for language changes */
	extract(parse_plugin_cfg('dynamix', true));
	if (_var($display, 'locale') != $locale_init) {
		$locale_init = _var($display, 'locale');
		update_translation($locale_init);
	}

	$synced = create_sync($stamps);
	$sbSynced = array_shift($synced) ?: _var($var, 'sbSynced', 0);
	$echo = [];
	$spot = _var($var, 'mdResyncPos', 0);

	if ($spot > 0) {
		$size = _var($var, 'mdResyncSize', 0);
		$delta = _var($var, 'mdResyncDt', 0);
		$bytes = _var($var, 'mdResyncDb', 0);

		create_file($resync, _var($var, 'mdResyncAction'), $size);

		$echo[] = my_scale($size * 1024, $unit, -1) . " $unit";
		$echo[] = _(my_clock(floor((time() - $sbSynced) / 60)), 2) . ($delta ? '' : ' (' . _('paused') . ')');
		$echo[] = my_scale($spot * 1024, $unit) . " $unit (" . number_format($spot / ($size / 100 + 1), 1, $dot, '') . " %)";
		$echo[] = $delta ? my_scale($bytes * 1024 / $delta, $unit, 1) . " $unit/sec" : '---';
		$echo[] = $bytes ? _(my_clock(round(((($delta * (($size - $spot) / ($bytes / 100 + 1))) / 100) / 60), 0)), 2) : _('Unknown');
		$echo[] = $var['sbSyncErrs'];
	} elseif (_var($var, 'sbSynced') && _var($var, 'sbSynced2')) {
		$timestamp = str_replace(['.0', '.'], ['  ', ' '], date('Y.M.d H:i:s', $var['sbSynced2']));

		if (new_parity_log($timestamp)) {
			/* Get the results from the latest parity check. */
			list($duration, $speed, $status, $error, $action, $size) = last_parity_check();

			/* Save the result in the parity history log. */
			file_put_contents($log, "$timestamp|$duration|$speed|$status|$error|$action|$size\n", FILE_APPEND);

			/* Remove the resync files after the history file has been updated. */
			$remove_resync_files = 1;

			/* Parity check is completed. */
			$echo = "";
		} elseif ($remove_resync_files >= 3) {
			delete_file($stamps, $resync);

			$remove_resync_files = 0;
		} elseif ($remove_resync_files != 0) {
			$remove_resync_files++;
		}
	}




	/* Handle fsState changes */
	if (_var($var, 'fsState') == 'Copying') {
		$fsState = _var($var, 'fsCopyPrcnt') . "% " . _('completed');
	} elseif (_var($var, 'fsState') == 'Clearing') {
		$fsState = _var($var, 'fsClearPrcnt') . "% " . _('completed');
	} elseif (substr(_var($var, 'fsState'), -3) != 'ing') {
		$fsState = 'stop';
	} else {
		$fsState = '';
	}

	/* Determine process state */
	$mover_pid = mover_running_pid();
	if (_var($var, 'fsState') != "Started") {
		$process = -1;
	} elseif ($spot > 0 && $bytes > 0) {
		$process = 1;
	} elseif (_var($var, 'shareMoverActive') == "yes" && $mover_pid) {
		$process = 2;
	} elseif (exec('ps -C btrfs -o cmd=|grep -cv show') > 0) {
		$process = 3;
	} elseif (exec("zpool status 2>/dev/null | grep -c 'scrub in progress'") > 0) {
		$process = 4;
	} else {
		$process = 0;
	}

  if ($process == 2) {
    $moverdata = [];
    if (file_exists("$varroot/mover.ini") && $mover_pid) {
      $moverstat = @parse_ini_file("$varroot/mover.ini") ?: [];
      if ((int)_var($moverstat, 'MoverPid', 0) === $mover_pid) {
        $mover = $moverstat;
        $totalSize = _var($moverstat, 'TotalSize', _var($moverstat, 'TotalToArray', 0) + _var($moverstat, 'TotalFromArray', 0));
        $remainSize = _var($moverstat, 'RemainSize', _var($moverstat, 'RemainToArray', 0) + _var($moverstat, 'RemainFromArray', 0));
        $perc = mover_percent(_var($moverstat, 'Filepercent', 0));
        $throughput = _var($moverstat, 'Throughput', 0);
        $eta = mover_duration(_var($moverstat, 'ETA', 0));
        $rate = $throughput > 0 ? my_scale($throughput, $unit, 1)." $unit/sec" : _('Unknown');
        $value1 = mover_bar($perc);
        if ($totalSize > 0) {
          $totalPerc = mover_percent(($totalSize - $remainSize) / $totalSize * 100);
          $value2 = $remainSize > 0
            ? mover_bar($totalPerc)
            : _("Transfer complete");
        } else {
          $value2 = _("Nothing to move");
        }
        $value3 = _("ETA").": $eta &bullet; "._("Speed").": $rate";
        $moverdata = [
          'Showlines' => (int)_var($moverstat, 'Showlines', 0),
          'Selectlines' => _var($moverstat, 'Selectlines', ''),
          'movertitle0' => mover_html(_(_var($moverstat, 'movertitle1', 'File being processed:'))),
          'movertitle1' => mover_html(_(_var($moverstat, 'movertitle2', 'Action:'))),
          'movertitle2' => mover_html(_(_var($moverstat, 'movertitle3', 'Progress:'))),
          'movertitle3' => mover_html(_(_var($moverstat, 'movertitle4', 'Overall Progress:'))),
          'movertitle4' => mover_html(_(_var($moverstat, 'movertitle5', 'Estimated Completion:'))),
          'moverline0' => mover_html(_var($moverstat, 'File')),
          'moverline1' => mover_html(_var($moverstat, 'Action')),
          'moverline2' => $value1,
          'moverline3' => $value2,
          'moverline4' => $value3,
        ];
        $timer = 1;
      } else {
        $moverdata['Showlines'] = 0; $mover = -1 ; $timer = 3 ;
      }
    } else {
      $moverdata['Showlines'] = 0; $mover = -1 ; $timer = 3 ;
    }
  } else {
    $moverdata = [];
    $moverdata['Showlines'] = 0; $mover = -1 ; $timer = 3 ;
  }

  // publish but don't republish duplicate messages
  publish_noDupe('parity', json_encode($echo));
	publish_noDupe('paritymonitor', $spot > 0 ? 1 : 0);
  publish_noDupe('fsState', $fsState);
	publish_noDupe('mymonitor', $process);
  publish_noDupe('mover', json_encode($moverdata));

	// ping the page so we can terminate if nobody is listening
	ping("mainPingListener");

	sleep($timer);
}
?>
