{#
    (C) 2021 - ntop.org    
    Base template for datatables.
#}
<style>
.table.dataTable {
  padding: 0;
}
</style>
<!--
.table.dataTable th {
    white-space: nowrap;
    overflow: hidden;
}
 

.table.dataTable td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
-->
<!-- vue3 -->
<!-- <script src="{* ntop.getHttpPrefix() *}/vue/vue-dev.js?{* ntop.getStaticFileEpoch() *}"></script> 
<script src="{* ntop.getHttpPrefix() *}/vue/vue3-sfc-loader.js?{* ntop.getStaticFileEpoch() *}"></script>
<script src="{* ntop.getHttpPrefix() *}/vue/ntopng_vue_loader.js?{* ntop.getStaticFileEpoch() *}"></script>
-->
<!-- defines base_path globals const-->
<script type='text/javascript'>
  const base_path = '{* ntop.getHttpPrefix() *}';
  const default_ifid = '{* interface.getId() *}';
  const show_permalink = '{* show_permalink *}' == 'true';
  const show_download = '{* show_download *}' == 'true';
  const download_endpoint = '{* datatable.download.endpoint *}';
  const navbar_context = {* navbar *};
  const show_pcap_download = '{* show_pcap_download *}' == 'true';
  const isNtopEnterpriseM = '{* ntop.isEnterpriseM() *}' == 'true';
  const show_chart = '{* show_chart *}' == 'true';
</script>
<div id="navbar">
<page-navbar
	id="page_navbar"
	:main_title="navbar_context.main_title"
	:base_url="navbar_context.base_url"
	:help_link="navbar_context.help_link"
	:items_table="navbar_context.items_table"
	@click_item="click_item">
</page-navbar>
</div>

<div class='row'>
  <div class='col-12'>
    <div class="mb-2">
      <div class="w-100">
	<div clas="range-container d-flex flex-wrap">
	  <div class="range-picker d-flex m-auto flex-wrap" id="rangepicker">
	  <alert-info id="alert_info" :global="true" ref="alert_info"></alert-info>
	  <modal-traffic-extraction id="modal_traffic_extraction" ref="modal_traffic_extraction"></modal-traffic-extraction>
	  <modal-snapshot ref="modal_snapshot"
	    :csrf="csrf">
	  </modal-snapshot>
	    <range-picker ref="range-picker-vue" :id="id_range_picker">
	    <template v-slot:extra_range_buttons>
	    <button v-if="show_permalink" class="btn btn-link btn-sm" @click="get_permanent_link" :title="i18n('graphs.get_permanent_link')" ref="permanet_link_button"><i class="fas fa-lg fa-link"></i></button>
	    <a v-if="show_download" class="btn btn-link btn-sm" id="dt-btn-download" :title="i18n('graphs.download_records')" ><i class="fas fa-lg fa-file"></i></a>
	    <button v-if="show_pcap_download" class="btn btn-link btn-sm" @click="show_modal_traffic_extraction" :title="i18n('traffic_recording.pcap_download')"><i class="fas fa-lg fa-download"></i></button>
	    <button v-if="is_ntop_enterprise_m" class="btn btn-link btn-sm" @click="show_modal_snapshot" :title="i18n('datatable.manage_snapshots')"><i class="fas fa-lg fa-camera-retro"></i></button>
	    </template>
	    </range-picker>
	  </div>
	</div>
      </div>
    </div>
  </div>

  <div class='col-12'>
    <div class="card card-shadow">
      <div class="overlay justify-content-center align-items-center position-absolute h-100 w-100">
        <div class="text-center">
          <div class="spinner-border text-primary mt-5" role="status">
            <span class="sr-only position-absolute">Loading...</span>
          </div>
        </div>
      </div>

      <div class="card-body">

        {% if show_chart then %}
        <div class="row">

          <div class="col-12 mb-2" id="chart-vue">
            <div class="card h-100 overflow-hidden">
              <chart ref="chart"
	        id="chart_0"
          :chart_type="chart_type"
	        :base_url_request="chart_base_url_request"
		:register_on_status_change="false">
	      </chart>
	      <modal-alerts-filter
	        :alert="current_alert"
		:page="page"
		@exclude="add_exclude"
		ref="modal_alerts_filter">
	      </modal-alerts-filter>
            </div>
          </div>
      {% end  %}          

          <table id='{{ datatable.name }}' class='table table-striped table-bordered w-100'>
            <thead>
              <tr>
                {* datatable.columns_header *}
              </tr>
            </thead>
          </table>

          <div class="mt-2">
            {% if show_tot_records then %}
            <div class="text-end">
                <small id="{{ datatable.name }}-tot_records" style="display: none;" class="query text-end"><span class="records">{}</span>.</small>
            </div>
            {% end %}
            <div class="text-start">
                <small id="{{ datatable.name }}-query-time" style="display: none;" class="query">{{ i18n('db_search.query_performed') }} <span class="seconds">{}</span> seconds. <span id="{{ datatable.name }}-query" style="display: none; cursor: pointer;" class="badge bg-secondary">SQL</span></small>
            </div>
          </div>
      {% if show_chart then %}
        </div>
      {% end  %}
      </div>

      {% if show_acknowledge_all or show_delete_all then %}
      <div class="card-footer">

        {% if show_acknowledge_all then %}
        <button id="dt-btn-acknowledge" {{ ternary(datatable.show_admin_controls, "", 'hidden="hidden"') }} data-bs-target='#dt-acknowledge-modal' data-bs-toggle="modal" class="btn btn-primary">
          <i class="fas fa fa-user-check"></i> {{ i18n("acknowledge_alerts")}}
        </button>
        {% end %}

        {% if show_delete_all then %}
        <button id="dt-btn-delete" {{ ternary(datatable.show_admin_controls, "", 'hidden="hidden"') }} data-bs-target='#dt-delete-modal' data-bs-toggle="modal" class="btn btn-danger">
          <i class="fas fa fa-trash"></i> {{ i18n("delete_alerts")}}
        </button>
        {% end %}

      </div>
      {% end %}
    </div>

    {% if notes then %}
      {* ui_utils.render_notes({ {content = notes} }) *}
    {% end %}

  </div>
</div>

{# add modals if defined #}
{% if datatable.modals then %}
<div class="modals">
    {% for _, modal in pairs(datatable.modals) do %}
        {* modal *}
    {% end %}
</div>
{% end %}

<script type="text/javascript">
    i18n_ext.showing_x_to_y_rows = "{{ i18n('showing_x_to_y_rows', {x='_START_', y='_END_', tot='_TOTAL_'}) }}";
</script>
<script type='text/javascript'>
  let pageCsrf = "{{ ntop.getRandomCSRFValue() }}";
  let $table;
  let RANGEPICKER_APP;
  let CHART_APP;
  let datatable_columns;
  const datatableButton = {* (datatable.buttons or '[]') *};
  const ifid = {{ ifid }}
  const local_storage_order_key = "{* datatable.name *}_column" + ifid
  const local_storage_order_asc_desc = "{* datatable.name *}_order" + ifid

    const INITIAL_ROWS_LENGTH = {{datatable.initialLength}};

    {% if show_chart then %}
    const chartParams = {* json.encode(chart.params) *};
    {% end %}

    let intervalId = 0;

    $(`#{{ datatable.name }}-query`).click(function(e) {
        NtopUtils.copyToClipboard($(e.target).attr('title'), this);
    })

    function updateDownloadButton() {
        if (!$(`#dt-btn-download`)) return;

	let dataSourceParams = ntopng_url_manager.get_url_object();
        // update the link of the download button
        //const href = $(`#dt-btn-download`).attr('href');
        const newDownloadURL = new URL(download_endpoint, location.origin);
        newDownloadURL.search = new URLSearchParams(dataSourceParams); 
        newDownloadURL.searchParams.set("visible_columns", getVisibleColumns($table).join(','));
        newDownloadURL.searchParams.set("format", "txt");
        $(`#dt-btn-download`).attr('href', newDownloadURL.toString());
    }

    // define a globals cache for cards
    let globalCardsCache = { cardsData: null, requestDictionary: {} };

    const updateCardsCache = function(cache) {
      return (cardsData) => {
        if (cache.cardsData == null) { cache.cardsData = cardsData; }
	for (let i = 0; i < cardsData.length; i += 1) {
	  let newTopData = cardsData[i];
	  if (newTopData.value == null || newTopData.value.length == 0) {
	    continue;
	  }
	  // update cache
	  cache.cardsData[i] = newTopData;
	}
      }
    }(globalCardsCache);

    const getTopCardsData = function(cache) {
      return async (endpoint_url, action) => {
	// check if we have cards requested in cache
        if (cache.requestDictionary[action] == null) {
	  let res = await $.getJSON(`${endpoint_url}`);
	  let cardsData = res.rsp;
	  cache.requestDictionary[action] = true;
	  updateCardsCache(cardsData);
	}
	return cache.cardsData;
      };
    }(globalCardsCache);

    const updateCardStatsContent = function(cache) {
      let lastUrlParams = null;
      return async (cardId, action) => {
        let params = ntopng_url_manager.get_url_params();
	// check if we must reset cache 
	if (lastUrlParams != params) { cache.requestDictionary = {}; }
	lastUrlParams = params;
	// check if we have already data in cache
	if (cache.requestDictionary[action] == true) { return; }
        if ($(`#${cardId}`).dropdown().hasClass("show")) {
	  $(`#${cardId}`).dropdown("hide");
	}
	$(`#${cardId} > .spinner-border`).show();
	await updateCardStats(action);
	$(`#${cardId} > .spinner-border`).hide();
	$(`#${cardId}`).dropdown("show");
      };
    }(globalCardsCache);
    
    /* Cards */
  {% if show_cards then %}
    let tableBarMenuHtml = null;
    let updateCardStats = async (action) => {
	// if action == 'overview' we ask only the names of the menu (avoiding queries for menu content) 
    	let paramAction = "";
	if (action != null) { paramAction = `&action=${action}`; }
	let params = ntopng_url_manager.get_url_params();
	let cardsData;
	try {
          // data = await $.getJSON(`{* endpoint_cards *}?${params}${paramAction}`);
	  let endpoint_url = `{* endpoint_cards *}?${params}${paramAction}`;
          cardsData = await getTopCardsData(endpoint_url, action);
	} catch(e) {
	  console.error(e); return;
	}
	let menuContent = [];
	for (i = 0; i < cardsData.length; i++){
	  if (cardsData[i] == null || cardsData[i].value == null){
	  continue;
	} else {
	    let menuOptions = [];
	    if (cardsData[i].value != null) {
	      for (j = 0; j < cardsData[i].value.length; j++) {
	        // Concat the name with the percentage of the stat
	        // NB: These name should be filters if available
	        if(cardsData[i].value[j] != null){
	          let restText = " (" + (cardsData[i].value[j].count).toFixed(1) + "%)";
	          if(cardsData[i].value[j].count != 0 && cardsData[i].value[j].count < 0.1){restText = " (< 0.1%)";}

		  let operator = "";
		  if (cardsData[i].value[j].operator != null) {
		    operator = `  data-tag-operator='${cardsData[i].value[j].operator}' `;
		  }
	          let a_tag = "<a class='ntopng-truncate tag-filter dropdown-item' data-tag-key='" + cardsData[i].value[j].key + 
	            "' title='" + ( cardsData[i].value[j].title || cardsData[i].value[j].value) +
		    "' data-tag-value='" + cardsData[i].value[j].value + 
		    "' data-tag-label='" + cardsData[i].value[j].label + "'" +
		    operator +
		    " href='#'>" + cardsData[i].value[j].label + "" + restText + "</a>";

                  let itemText = '<li style="max-width:90rem;" class="dropdown-item pointer">' + a_tag + '</li>';
		  menuOptions.push(itemText);
		}
	      }
	    }
	    //if (menuOptions.length > 0){
	      let cardId = `card_id_${i}`;
	      let cardAction = cardsData[i].action;
	      let menu = `<div class="btn-group dropdown">
	      <button id="${cardId}" onClick="updateCardStatsContent('${cardId}', '${cardAction}')" class="btn btn-link dropdown-toggle" data-bs-toggle="dropdown" type="button" title="`+ cardsData[i].tooltip + `">
	      <div class="spinner-border spinner-border-sm" style="display:none;" role="status">
	      <span class="visually-hidden">Loading...</span>
	      </div>	      

	      ` + cardsData[i].label +
	      `</button>
	      <ul class="dropdown-menu">`
	    	+ menuOptions.join("") + 
              `</ul>
	      </div>`;
              menuContent.push(menu);
            //}
          }
        }
        if (tableBarMenuHtml == null) {
          tableBarMenuHtml = $(".dataTables_wrapper .row .text-end").html();
        }
        let menuContentHtml = '' + menuContent.join("") + '';
        $(".dataTables_wrapper .row .text-end").html(menuContentHtml);
        $(".dataTables_wrapper .row .text-end").append(tableBarMenuHtml);
        $(".dataTables_wrapper .dropdown .tag-filter" ).addClass("dropdown-item");
    };
    {% end %}

  async function reloadTable($table, url_params) {
      if ($table == null) {
	  return;
      }
      //NtopUtils.showOverlays();
      // reload the table
        $table.ajax.url(`{* datatable.datasource.name *}?` + url_params).load();

        {% if show_cards then %}
        //updateCardStats();
        {% end %} 
    }

    function printQueryTime($table) {
        const response = $table.ajax.json();
        // if the response contains the query time period
        if (response !== undefined && (response.rsp.stats !== undefined && response.rsp.stats.query_duration_msec !== undefined)) {
            const sec = response.rsp.stats.query_duration_msec / 1000.0;
            $(`#{{ datatable.name }}-query-time`).show();
            $(`#{{ datatable.name }}-query-time .seconds`).text((sec < 0.01) ? '< 0.01' : NtopUtils.ffloat(sec)); // The time is in sec
            $(`#{{ datatable.name }}-query`).show();
            $(`#{{ datatable.name }}-query`).prop('title', response.rsp.stats.query);
            {% if show_tot_records then %}
            if(response.rsp.stats.num_records_processed !== undefined) {
                const num_records_processed = response.rsp.stats.num_records_processed;
                $(`#{{ datatable.name }}-tot_records`).show();
                $(`#{{ datatable.name }}-tot_records .records`).text(num_records_processed);
            }
            {% end %}
        }
    }

    function getVisibleColumns($tableApi) {
        const visibleColumns = [];
        $tableApi.columns().every(function(idx) {   
            const $column = $tableApi.column(idx);
            if ($column.visible() && $column.name() !== '') {
                visibleColumns.push($column.name());
            } 
        });

        return visibleColumns;
    }

    function loadColumns() {

        let columns = [];
        {% if datatable.columns_js then %}
        columns = {* datatable.columns_js *};
        {% end %}

        /* Actions Column */
        {% if show_actions then %}
	let handlerId = "disableAlerts";
        columns.push({responsivePriority: 1, width: '5%', targets: -1, className: 'text-center text-nowrap', orderable: false, data: null, handlerId, render: (rowData, type, dataRow) => {
            let handlerDisableAlerts = {
	      handlerId,
	      onClick: () => {
		CHART_APP.show_modal_alerts_filter(rowData);
	      },
	    };
            const buttons = [
                {% if actions.show_info then %}
                {icon: 'fa fa-search-plus', title: "{{ i18n('info') }}", href: '#check_info'},
                {% end %}

                {% if actions.show_snmp_info then %}
                {icon: 'fa fa-search-plus', title: "{{ i18n('info') }}", href: '#check_snmp_info'},
                {% end %}

                {% if actions.show_alerts then %}
                /* Button to jump to flow alerts within the same time period */
                {icon: 'fas fa-exclamation-triangle', title: "{{ i18n('show_alerts.flow_alerts') }}", href: '#check_alerts'},
		{% end %}

                {% if actions.show_flows then %}
                /* Button to jump to flow alerts within the same time period */
                {icon: 'fa-exclamation-triangle', title: "{{ i18n('show_alerts.flow_alerts') }}", modal: '#flow_alerts'},
		{% end %}

                {% if actions.show_historical then %}
		/* Button to jump to historical flows */
                {icon: 'fa-stream', title: "{{ i18n('db_explorer.historical_data') }}", modal: '#past_flows'},
		{% end %}

                {% if actions.show_pcap_download then %}
		/* Button to open the pcap download dialog */
                {icon: 'fa-download', title: "{{ i18n('traffic_recording.pcap_download') }}", onclick: 'pcapDownload(' + dataRow.filter.epoch_begin + ', ' + dataRow.filter.epoch_end+ ', "' + dataRow.filter.bpf + '"); return false;'},
		{% end %}

                {% if actions.show_acknowledge then %}
                {icon: 'fa fa-user-check', title: "{{ i18n('acknowledge') }}", modal: '#acknowledge_alert_dialog'},
                {% end %}

                {% if actions.show_disable then %}
                /* Bell button to disable alerts is only supported for hosts and flows */
                {icon: 'fa-bell-slash', class: "pointer", handler: handlerDisableAlerts, title: "{{ i18n('disable') }}"},
                {% end %}

                {% if actions.show_settings then %}
                {icon: 'fa fa-cog', title: "{{ i18n('settings') }}", href: '#check_settings'},
                {% end %}

                {% if actions.show_delete then %}
                {icon: 'fa fa-trash', title: "{{ i18n('remove') }}", modal: '#delete_alert_dialog'},
                {% end %}
            ];

            return DataTableUtils.createActionButtons(buttons, dataRow);
          }
        });
        {% end %}

        return columns;
    }

  function setUserColumnsDefWidths() {
    let userColumnDef;
    /* Get the settings for this table from localStorage */
    let userColumnDefs = JSON.parse(localStorage.getItem('{{ datatable.name }}')) || [];

    if (userColumnDefs.length === 0 ) return;
    datatable_columns.forEach( function(columnDef, index) {
      // Check if there is a width specified for this column
      userColumnDef = userColumnDefs.find( function(column) {
        return column.targets === index /* Column target */;
      });

      // If there is, set the width of this columnDef in px
      if ( userColumnDef ) {
        columnDef.width = userColumnDef.width + 'px';
      }
    });
  }


  function saveColumnSettings() {
    let userColumnDefs = JSON.parse(localStorage.getItem('{{ datatable.name }}')) || [];
    let width, header, existingSetting; 

    $table.columns().every( function ( targets ) {
      // Check if there is a setting for this column in localStorage
      existingSetting = userColumnDefs.findIndex( function(column) { return column.targets === targets;});
      // Get the width of this column
      header = this.header();
      width = $(header).width();

      if ( existingSetting !== -1 ) {
        // Update the width
        userColumnDefs[existingSetting].width = width;
      } else {
        // Add the width for this column
        userColumnDefs.push({
          targets: targets,
          width:  width,
        });
      }
    });

    // Save (or update) the settings in localStorage
    localStorage.setItem('{{ datatable.name }}', JSON.stringify(userColumnDefs));
  }

  function refreshTime() {
      let epoch_status = ntopng_status_manager.get_status();
      let now = Number.parseInt(Date.now() / 1000);
      let delta = now - Number.parseInt(epoch_status.epoch_end);
      if (delta < 0) { return; }
      let epoch_begin = Number.parseInt(epoch_status.epoch_begin) + delta;
      ntopng_events_manager.emit_event(ntopng_events.EPOCH_CHANGE, { epoch_begin, epoch_end: now });
  }
  function start_navbar() {
      let navbar_vue_options = {
	  components: {	  
   	      // 'page-navbar': Vue.defineAsyncComponent( () => ntopng_vue_loader.loadModule(`${base_path}/vue/components/page-navbar.vue`, ntopng_vue_loader.loadOptions) ),
   	      'page-navbar': ntopVue.PageNavbar,	      
	  },
	  /**
	   * First method called when the component is created.
	   */
	  created() {},
	  mounted() {
	  },
	  data() {
	      return {
		  navbar_context: navbar_context,
	      };
	  },
	  methods: {
	      remove_filters_from_url: function() {
	        let status = ntopng_status_manager.get_status();
		let filters = status.filters;
		if (filters == null) { return; }		
		ntopng_url_manager.delete_params(filters.map((f) => f.id));
	      },
	      click_item: function(item) {
	        ntopng_url_manager.set_key_to_url('page', item.page_name);
	        let is_alert_stats_url = window.location.toString().match(/alert_stats.lua/) != null;
	        if (is_alert_stats_url) {
	          this.remove_filters_from_url();
	        }
		ntopng_url_manager.reload_url();
	      },
	  },
      };
      const navbar_vue = ntopVue.Vue.createApp(navbar_vue_options);
      const vue_app = navbar_vue.mount("#navbar");
      return vue_app;
      }

  function start_chart() {
    let is_alert_stats_url = window.location.toString().match(/alert_stats.lua/) != null;
    let page;
    let chart_data_url = `${base_path}/lua/pro/rest/v2/get/db/ts.lua`;
    if (is_alert_stats_url) {
      page = ntopng_url_manager.get_url_entry("page");
      if (page == null) { page = "all"; }
      chart_data_url = (page == "snmp_device") ? `${base_path}/lua/pro/rest/v2/get/snmp/device/alert/ts.lua` : `${base_path}/lua/rest/v2/get/${page}/alert/ts.lua`;
    }

    let chart_vue_options = {
    	components: {
   	      // 'chart': Vue.defineAsyncComponent( () => ntopng_vue_loader.loadModule(`${base_path}/vue/components/chart.vue`, ntopng_vue_loader.loadOptions) ),
   	      'chart': ntopVue.Chart,
	      'modal-alerts-filter': ntopVue.ModalAlertsFilter,
	  },
	  /**
	   * First method called when the component is created.
	   */
	  created() {},
	  mounted() {},
	  data() {
	      return {
	          csrf: pageCsrf,
            chart_type: ntopChartApex.typeChart.TS_COLUMN,
		  chart_base_url_request: chart_data_url,
		  page: page,
		  current_alert: null,
		  i18n: (t) => { return i18n(t); },
	      };
	  },
	  methods: {
	    chart_options_converter: function(options) {
	      
	      let formatter = ntopChartOptionsUtility.getApexYFormatter()
	      if (is_alert_stats_url) {
	        
	      }
	    },
	    show_modal_alerts_filter: function(alert) {
	      this.current_alert = alert;
	      this.$refs["modal_alerts_filter"].show();
	    },
	    register_status: function() {
	      this.$refs["chart"].register_status();
	    },
	    add_exclude: async function(params) {
	      params.csrf = pageCsrf;
	      let url = `${http_prefix}/lua/pro/rest/v2/add/alert/exclusion.lua`;
	      try {
	        let headers = {
		  'Content-Type': 'application/json'
		};
		await ntopng_utility.http_request(url, { method: 'post', headers, body: JSON.stringify(params) });
		let url_params = ntopng_url_manager.get_url_params();
		setTimeout(() => {
		  reloadTable($table, url_params);
		  ntopng_events_manager.emit_custom_event(ntopng_custom_events.SHOW_GLOBAL_ALERT_INFO, { text_html: i18n('check_exclusion.disable_warn'), type: "alert-info", timeout: 2 });
		  
		}, 1000);
              } catch(err) {
	        console.error(err);
              }
	    }
	  },
      }; 
      const chart_vue = ntopVue.Vue.createApp(chart_vue_options);
      const vue_app = chart_vue.mount("#chart-vue");
      return vue_app;
  }

  function start_range_picker() {
      let rangepicker_vue_options = {
	  props: {
	      id: String,
	  },
	  components: {
   	      // 'range-picker': Vue.defineAsyncComponent( () => ntopng_vue_loader.loadModule(`${base_path}/vue/components/range-picker.vue`, ntopng_vue_loader.loadOptions) ),
   	      // 'modal-traffic-extraction': Vue.defineAsyncComponent( () => ntopng_vue_loader.loadModule(`${base_path}/vue/components/modal-traffic-extraction.vue`, ntopng_vue_loader.loadOptions) ),
   	      // 'alert-info': Vue.defineAsyncComponent( () => ntopng_vue_loader.loadModule(`${base_path}/vue/components/alert-info.vue`, ntopng_vue_loader.loadOptions) ),
   	      'range-picker': ntopVue.RangePicker,
   	      'modal-traffic-extraction': ntopVue.ModalTrafficExtraction,
	      'modal-snapshot': ntopVue.ModalSnapshot,
   	      'alert-info': ntopVue.AlertInfo,
	  },
	  /**
	   * First method called when the component is created.
	   */
	  created() {},
	  mounted() {},
	  data() {
	      return {
	          csrf: pageCsrf,
		  is_ntop_enterprise_m: isNtopEnterpriseM,
            chart_type: ntopChartApex.typeChart.TS_COLUMN,
		  chart_base_url_request: `${base_path}/lua/rest/v2/get/flow/alert/ts.lua`,
		  show_download: show_download,
		  show_permalink: show_permalink,
		  show_pcap_download: show_pcap_download,
		  id_range_picker: `range_picker`,
		  i18n: (t) => { return i18n(t); },
	      };
	  },
	  methods: {
	  show_modal_traffic_extraction: async function() {
	  this.$refs["modal_traffic_extraction"].show();
	  },
	  show_modal_snapshot: function() {
	    this.$refs["modal_snapshot"].show();
	  },
	  get_permanent_link: function() {
	  const $this = $(this.$refs['permanet_link_button']);
	  const placeholder = document.createElement('input');
	  placeholder.value = location.href;
	  document.body.appendChild(placeholder);
	  placeholder.select();

	  // copy the url to the clipboard from the placeholder
	  document.execCommand("copy");
	  document.body.removeChild(placeholder);

	  $this.attr("title", "{{ i18n('copied') }}!")
	  .tooltip("dispose")
	  .tooltip()
	  .tooltip("show");
	  },
	  download_chart_data: function() {
	  }
	  },
      }; 
      const rangepicker_vue = ntopVue.Vue.createApp(rangepicker_vue_options);
      const vue_app = rangepicker_vue.mount("#rangepicker");
      return vue_app;
  }
  
  $(document).ready(async function(){
  setTimeout(() => start_navbar(), 0);
      if (ntopng_url_manager.get_url_entry("ifid") == null) {
	  ntopng_url_manager.set_key_to_url("ifid", default_ifid);
      }
      if (ntopng_url_manager.get_url_entry("epoch_begin") == null
      	 || ntopng_url_manager.get_url_entry("epoch_end") == null) {
	 let default_epoch_begin = Number.parseInt((Date.now() - 1000 * 30 * 60) / 1000);
	 let default_epoch_end = Number.parseInt(Date.now() / 1000);
	 ntopng_url_manager.set_key_to_url("epoch_begin", default_epoch_begin);
	 ntopng_url_manager.set_key_to_url("epoch_end", default_epoch_end);
      }
      if (ntopng_url_manager.get_url_entry("page") == "flow"
      	 && ntopng_url_manager.get_url_entry("status") == "engaged") {
	 ntopng_url_manager.set_key_to_url("status", "historical");
      }
      if (show_chart) {
        CHART_APP = start_chart();
      }
      RANGEPICKER_APP = start_range_picker();
    datatableButton.push({
        text: '<i class="fas fa-sync"></i>',
        action: async function (e, dt, node, config) {
	    refreshTime();
        }
    });
    
    datatable_columns = loadColumns();
    const column_order_name = "{{ datatable.order_name }}";
    let column_order_id = 1;
    datatable_columns.forEach((element, index) => {
        if(element.data && element.data == column_order_name) {
            column_order_id = index;
        }
    });
    column_order_id = localStorage.getItem(local_storage_order_key) || column_order_id
    const column_order_sorting = localStorage.getItem(local_storage_order_asc_desc) || "{* datatable.order_sorting *}"
    

    /* Ordering the array in order to have the selected row length at the beginning of the array */
    let length_array = NtopUtils.getNumTableRows();
    let index = length_array.indexOf(INITIAL_ROWS_LENGTH);
    /* Validate index */
    (index >= 0) ? index = index : index = length_array.length - 1; /* Use the last index */

      let url_params = ntopng_url_manager.get_url_params();
      let config = DataTableUtils.getStdDatatableConfig(datatableButton);
      config = DataTableUtils.extendConfig(config, {
          serverSide: true,
          searching: false,
          info: false,
          order: [[ column_order_id,  column_order_sorting]],
          pagingType: '{{ datatable.pagination }}',
          autoWidth: false,
          destroy: false,
          responsive: false,
          scrollX: true,
          ajax: {
              method: 'get',
              url: '{* datatable.datasource.name *}?' + url_params,
              dataSrc: 'rsp.records',
              data: (data, settings) => {

                  const tableApi = settings.oInstance.api();
                  const orderColumnIndex = data.order[0].column;
                  const orderColumnName = tableApi.column(orderColumnIndex).name() || undefined;
                  
                  if (data.order) {
                      data.order = data.order[0].dir;
                      data.sort = orderColumnName;
                      localStorage.setItem(local_storage_order_key, orderColumnIndex);
                      localStorage.setItem(local_storage_order_asc_desc, data.order || "{* datatable.order_sorting *}")
                  }

                  if (data.columns !== undefined) {
                      delete data.columns;
                  }

                  if (data.search !== undefined) {
                      delete data.search;
                  }
                
                  data.visible_columns = getVisibleColumns(tableApi).join(',');
                  return data;
              },
              beforeSend: function() {
                NtopUtils.showOverlays();
              },
              complete: function() {
                NtopUtils.hideOverlays();
              }
          },
          drawCallback: () => {
              updateDownloadButton();
          },
          lengthMenu: [length_array, length_array],
          pageLength: INITIAL_ROWS_LENGTH,
          columns: datatable_columns,
      });

      $table = $(`#{{ datatable.name }}`).DataTable(config);
      {% if datatable.refresh_rate and datatable.refresh_rate > 0 then %}
      intervalId = setInterval(function() {
    refreshTime();
      }, {{ datatable.refresh_rate }});
      {% end %}

      let toggleColumnsDropdownAlreadyAdded = false;

      // on ajax request complete then print the query time
      $table.on('xhr', function() {
        printQueryTime($table);
        $(this).css('table-layout', 'auto')
        if (toggleColumnsDropdownAlreadyAdded == true) { return; }
        DataTableUtils.addToggleColumnsDropdown($table, function(col, visible) {
          $table.ajax.reload();
        });
        toggleColumnsDropdownAlreadyAdded = true;
      });

      $table.on('click', `a.tag-filter`, async function (e) {
          addFilter(e, $(this), $table);
      });

    /* Top Host and Top Alerts filters */
    {% if show_cards then %}
      $(".dataTables_wrapper .row .text-end").on("click", "a.tag-filter", async function (e) {
            addFilter(e, $(this));
    });
    {% end %}

    const addFilter = (e, a, from_table) => {
	e.preventDefault();

	let key = undefined;
	let displayValue = undefined;
	let realValue = undefined;
	let operator = 'eq';

	if (from_table != undefined) {
            const colIndex = from_table.cell(a.parent()).index().column;

            // Read tag key from the column
            key = from_table.column(colIndex).name()

	    // Read tag key from the cell if any
            const data = from_table.cell(a.parent()).data();
            if (data.tag_key)
		key = data.tag_key;

	    // Read value from the cell
            displayValue = (data.label ? data.label : ((data.value != undefined) ? data.value : data));
            displayValue  = NtopUtils.stripTags(displayValue);
            realValue = ((data.value != undefined) ? data.value : data);
	}
	
	// Read tag key and value from the <a> itself if provided
	if (a.data('tagKey')        != undefined) key          = a.data('tagKey');
	if (a.data('tagLabel')      != undefined) displayValue = a.data('tagLabel');
	if (a.data('tagRealvalue')  != undefined) realValue    = a.data('tagRealvalue');
	else if (a.data('tagValue') != undefined) realValue    = a.data('tagValue');
	if (a.data('tagOperator')   != undefined) operator     = a.data('tagOperator');

	// const tag = {
        //     label: i18n_ext.tags[key],
        //     key: key,
        //     value: displayValue,
        //     realValue: realValue,
        //     title: realValue,
        //     selectedOperator: operator
	// };
	//addFilterTag(tag);
	let filter = {
	    id: key,
	    value: realValue,
	    operator: operator,
	};
	if (RANGEPICKER_APP.$refs["range-picker-vue"].is_filter_defined(filter)) {
	    ntopng_events_manager.emit_custom_event(ntopng_custom_events.SHOW_MODAL_FILTERS, filter);
	} else {
	    ntopng_url_manager.set_key_to_url("query_preset", "");
	    ntopng_url_manager.set_key_to_url(filter.id, `${filter.value};${filter.operator}`);
	    ntopng_url_manager.reload_url();
	}

	// let status = ntopng_status_manager.get_status();
	// let filters = status["filters"] == null ? [] : status["filters"];
	// filters.push(filter);
	// // notifies to all the updated status
	// ntopng_status_manager.add_value_to_status("filters", filters);
    }    
    {% if show_cards then %}
    updateCardStats('overview');
    {% end %}

    /* HTTP copy URL button */
    $table.on('click', `.copy-http-url`, function (e) {
        let sampleTextarea = document.createElement("textarea");
        document.body.appendChild(sampleTextarea);
        sampleTextarea.value = $(this).attr('data-to-copy'); //url
        sampleTextarea.select(); //select textarea content
        document.execCommand("copy");
        document.body.removeChild(sampleTextarea);
    });

    /* Auto-refresh handling */
    $(`#autoRefreshEnabled`).on('click', async function(e) {
      const auto_refresh_button = $(this);
      const enable_refresh_rate = (auto_refresh_button.hasClass('fa-spin') == false);
      const auto_refresh_url = '{* ntop.getHttpPrefix() *}/lua/rest/v2/set/checks/auto_refresh.lua' 

      $.post(auto_refresh_url, {
        ifid: {{ ifid }},
        alert_page_refresh_rate_enabled: enable_refresh_rate,
        csrf: pageCsrf,
      })  
      .done(function(rsp) {
        if(enable_refresh_rate) {
          if (rsp.rsp.refresh_rate > 0 && !intervalId) {
            intervalId = setInterval(function() {
              refreshTime();
            }, rsp.rsp.refresh_rate);
            auto_refresh_button.addClass('fa-spin');
          }
        } else {
          clearInterval(intervalId);
          intervalId = null;
          auto_refresh_button.removeClass('fa-spin');
        }
      })
    });

    // register to global event change status
    await ntopng_sync.on_ready("range_picker");
    if (show_chart) {      
      CHART_APP.register_status();
    }
    updateDownloadButton();
    ntopng_status_manager.on_status_change("datatable", (new_status) => {
      let url_params = ntopng_url_manager.get_url_params();
      reloadTable($table, url_params);
    }, false);

    {% if extra_js then %}
      {* template_utils.gen(extra_js, extra_js_context) *}
    {% end %}

}); 
</script>
