[% PROCESS _header.tt
    js           => [ "vendor/flot-d7c58b5/jquery.flot.js",
                      "vendor/flot-d7c58b5/jquery.flot.time.js",
                      "vendor/flot-d7c58b5/jquery.flot.stack.js",
                    ]
%]
[% PROCESS _message.tt %]
[% USE date %]

<h1>
  Core Scheduling Overview
  [% IF hostgroup       == 'all' %] For All Host Groups
  [% ELSIF hostgroup    != ''    %] For Host Group '[% hostgroup %]'
  [% ELSIF servicegroup == 'all' %] For All Service Groups
  [% ELSIF servicegroup != ''    %] For Service Group '[% servicegroup %]'
  [% END %]
</h1>


<div class="card mx-auto w-[1000px] mt-5">
  <div class="head justify-between">
    [% PROCESS _status_filter.tt %]
    <button id="reschedule_btn" class="header-button">
      <i class="fa-solid fa-wand-magic-sparkles"></i>
      balance all hosts and services
    </button>
  </div>
  <div class="body">
    <div id="queue_graph" class="w-full h-[350px]"></div>

    <div class="flexrow flex-nowrap gap-3 justify-between">
      <form>
        <table class="w-fit cellspacing-x">
          <tr>
            <th colspan=2 class="text-center">Graph Options</th>
          </tr>
          <tr>
            <td colspan=2><hr class="pb-1 mt-1"></td>
          </tr>
          <tr>
            <th>Look ahead seconds</th>
            <td><input class="w-16" type="text" id="look_ahead" value="[% look_ahead | html %]" onchange="updateGraphDelayed()"> s</td>
          </tr>
          <tr>
            <th>Look back seconds</th>
            <td><input class="w-16" type="text" id="look_back" value=[% look_back %] onchange="updateGraphDelayed()"> s</td>
          </tr>
          <tr>
            <th>Group Checks</th>
            <td><input class="w-16" type="text" id="group_seconds" value=[% group_seconds %] onchange="updateGraphDelayed()"> s</td>
          </tr>
          <tr>
            <th>Update interval</th>
            <td><input class="w-16" type="text" id="update_interval" value=5 onchange="updateGraphDelayed()"> s</td>
          </tr>
        </table>
      </form>

      <table class="w-fit cellspacing-x">
        <tr>
          <th colspan=2 class="text-center">Check Interval Distribution</th>
        </tr>
        <tr>
          <td colspan=2><hr class="pb-1 mt-1"></td>
        </tr>
        <tr>
          <th class="text-right">Interval</th>
          <th class="text-right">Checks</th>
        </tr>
        [% FOREACH interval = intervals.keys.nsort %]
          <tr>
            <th class="text-right">[% duration(interval, 4) %]</th>
            <td class="text-right">[% intervals.$interval %]</td>
          </tr>
        [% END %]
        <tr>
          <th class="text-right border-t borderDefault">Average: [% duration(interval_avg, 4) %]</th>
          <td class="text-right border-t borderDefault">[% count_all %]</td>
        </tr>
      </table>

      <div class="flexcol gap-3">
        <table class="w-fit">
          <tr>
            <th colspan=3 class="text-center">Check Statistics</th>
          </tr>
          <tr>
            <td colspan=3><hr class="pb-1 mt-1"></td>
          </tr>
          <tr title="This is the estimated average rate of checks per seconds, based on the check interval and the number of host/service checks.">
            <th class="text-right">Estimated Check Rate</th>
            <td class="text-right pl-2">[% sprintf("%.2f", check_rate) %]</td>
            <td>/s</td>
          </tr>
          <tr title="This is the rolling average of finished checks per second.">
            <th class="text-right">Current Rate</th>
            <td id="current_rate" class="text-right pl-2">[% sprintf("%.2f", perf_stats.host_checks_rate + perf_stats.service_checks_rate) %]</td>
            <td>/s</td>
          </tr>
          <tr title="Average latency over all hosts and services.">
            <th class="text-right pt-5">Average Latency</th>
            <td id="current_latency" class="text-right pl-2 pt-5">[% sprintf("%.2f", latency_avg) %]</td>
            <td class="pt-5">s</td>
          </tr>
          <tr title="Average execution time over all hosts and services.">
            <th class="text-right">Average Execution Time</th>
            <td id="current_exec_time" class="text-right pl-2">[% sprintf("%.2f", execution_time_avg) %]</td>
            <td>s</td>
          </tr>
          <tr title="This amount of checks will run concurrently, based on execution_time and check_interval. Basically the amount of required worker when using mod-gearman.">
            <th class="text-right pt-5">Concurrent Checks</th>
            <td class="text-right pl-2 pt-5">[% sprintf("%.2f", concurrent_rate) %]</td>
            <td></td>
          </tr>
          <tr>
            <th class="text-right pt-5 align-top">Interval Length</th>
            <td class="text-right pl-2 pt-5">
              [% IF interval_lengths.keys.size == 1 %]
                [% FOREACH i = interval_lengths.keys.nsort %]
                  [% duration(i, 6) %]
                [% END %]
              [% ELSE %]
                [% FOREACH i = interval_lengths.keys.nsort %]
                  <div class="flexrow flex-nowrap">
                    <div class="w-10 text-left">
                      [% duration(i, 6) %]
                    </div>
                    <div class="max-w-[120px] truncate overflow-hidden">
                      [% names = [] %]
                      [% FOREACH s = interval_lengths.$i.keys.sort %]
                        [% names.push(peer_name(s)) %]
                      [% END %]
                      [% names.sort().join(", ") %]
                    </div>
                  </div>
                [% END %]
              [% END %]
            </td>
            <td></td>
          </tr>
        </table>
      </div>
    </div>
  </div>

</div>

<div id='tooltip'></div>

<style>
  DIV.legend TABLE {
    width: auto !important;
  }
  #tooltip {
    position: absolute;
    display: none;
    padding: 8px;
    background-color: var(--tooltip-bg);
    color: var(--tooltip-fg);
    opacity: 0.80;
    border-radius: 5px;
  }
</style>

<script>
<!--
var updateInterval = 5000;
var standard_grid = {
    backgroundColor: "#F0F0ED",
    markings: [% encode_json_obj(markings) %],
    hoverable: true
};
var standard_legend = {
    position: 'ne',
    margin: [10, 40]
};
var queue_options = {
    xaxis: {
        mode:     "time",
        timezone: "browser"
    },
    yaxes: [{
        min:           0,
        tickFormatter: function(val, axis) {
          if(val >= axis.max) { return('#'); }
          val = Math.round(val);
          if(val >= 10000) {
            val = val / 1000;
            val = Math.round(val)+'k';
            return(val);
          }
          if(val >= 1000) {
            val = val / 1000;
            if(val != Math.round(val)) {
              val = Number(val).toFixed(1)+'k';
            } else {
              val = val+'k';
            }
            return(val);
          }
          return(val);
        },
        labelWidth:   20
    }],
    grid:      standard_grid,
    legend:    standard_legend
};
var queue_series = [% encode_json_obj(scheduling_queue) %];

jQuery().ready(function() {
  var look_ahead = get_hash(1);
  if(look_ahead != undefined && jQuery.isNumeric(look_ahead)) {
      jQuery('#look_ahead').val(look_ahead);
  }
  var look_back = get_hash(2);
  if(look_back != undefined && jQuery.isNumeric(look_back)) {
      jQuery('#look_back').val(look_back);
  }
  var group_seconds = get_hash(3);
  if(group_seconds != undefined && jQuery.isNumeric(group_seconds)) {
      jQuery('#group_seconds').val(group_seconds);
  }
  var update_interval = get_hash(4);
  if(update_interval != undefined && jQuery.isNumeric(update_interval)) {
      jQuery('#update_interval').val(update_interval);
  }

  jQuery('#reschedule_btn').click(function() {
    if(confirm('really reschedule everything?')) {
        updateGraph(true);
    }
    return(false);
  });

  updateGraph();
});

var updateTimer;
function updateGraphDelayed() {
  set_hash(jQuery('#look_ahead').val(), 1);
  set_hash(jQuery('#look_back').val(), 2);
  set_hash(jQuery('#group_seconds').val(), 3);
  set_hash(jQuery('#update_interval').val(), 4);

  window.clearTimeout(updateTimer);
  updateTimer = window.setTimeout(updateGraph, 200);
}

function updateGraph(reschedule) {
  window.clearTimeout(updateTimer);
  updateInterval = jQuery('#update_interval').val()*1000;

  // only update if visible, recheck every second
  if(document.visibilityState && document.visibilityState != 'visible') {
      jQuery("#now_label").html("<i class='fa-solid fa-circle-pause' style='color:#990000;'><\/i><div>paused<\/div>");
      updateTimer = window.setTimeout(updateGraph, 1000);
      return;
  }

  if(reschedule) {
    setBtnSpinner('#reschedule_btn');
  }

  jQuery.ajax({
      url:      "[%  uri_with(c, 'json' => 'true' ) %]",
      type:     "POST",
      data:     {
        look_ahead: jQuery('#look_ahead').val(),
        look_back: jQuery('#look_back').val(),
        group_seconds: jQuery('#group_seconds').val(),
        reschedule: reschedule
      },
      dataType: "json",
      success:  function(data) {
        var queue_series = data['queue'];
        var markings     = data['markings'];
        queue_options.grid.markings = markings;
        jQuery("#current_rate").html(data['rate']);
        jQuery("#current_latency").html(data['latency_avg']);
        jQuery("#current_exec_time").html(data['execution_time_avg']);

        var queue_plot = jQuery.plot('#queue_graph', queue_series, queue_options);
        queue_plot.draw();

        var o = queue_plot.pointOffset({ x: standard_grid['markings'][0]['xaxis']['from'], y: 0});
        var d = new Date(standard_grid['markings'][0]['xaxis']['from']);
        jQuery('#queue_graph').append("<div id='now_label' class='flexrow flex-nowrap gap-1 absolute' style='left:"+(o.left+4)+"px;top:20px;color:#990000;font-size:smaller'>now ("+d.strftime("%H:%M:%S")+")</div>");

        if(data['message'] != undefined) {
            thruk_message(0, data['message']);
        }

        if(reschedule) {
          setBtnNoSpinner('#reschedule_btn');
        }

        window.clearTimeout(updateTimer);
        updateTimer = window.setTimeout(updateGraph, updateInterval);
      },
      error:  function(jqXHR, textStatus, errorThrown) {
        window.clearTimeout(updateTimer);
        updateTimer = window.setTimeout(updateGraph, updateInterval*2);
        var msg = getXHRerrorMsg('', textStatus, jqXHR, errorThrown);
        jQuery("#now_label").html("<i class='fa-solid fa-exclamation round small yellow'></i> update error: "+msg);
      }
  });
}

jQuery("#queue_graph").bind("plothover", function (event, pos, item) {
  if (!pos.x || !pos.y) {
    return;
  }
  if (item) {
    var x = item.datapoint[0].toFixed(2),
    y = item.datapoint[1].toFixed(2);
    var suffix = "";
    if(item.series.label == "moving average") {
      suffix = "/s";
    }

    jQuery("#tooltip").html(item.series.label + ": " + y+suffix)
      .css({top: item.pageY+5, left: item.pageX+5})
      .fadeIn(200);
  } else {
    jQuery("#tooltip").hide();
  }
});

jQuery("#queue_graph").bind("plothovercleanup", function (event, pos, item) {
  jQuery("#tooltip").hide();
});

-->
</script>

[% PROCESS _footer.tt %]
