<?php
/**
 * Description: Creating a table of stun servers in the admin panel.
 *
 * PHP version 8.0.1
 *
 * @category class
 * @package  core
 * @author   Oleg Klenitsky <klenitskiy.oleg@mail.ru>
 * @version  1.7.4
 * @license  GPLv2 or later
 * @filesource
 */

if ( ! defined( "ABSPATH" ) ) {
	exit();
}

class WebRTC2_List_Table_Srv extends WP_List_Table {
  /**
   * Constructor.
   */
  public function __construct() {
    parent::__construct(
      array(
        "plural"   => "",
        "singular" => "",
        "ajax"     => false,
      )
    );
  }
  /**
   * [extra_tablenav description]
   * @param  [type] $which [description]
   * @return [type]        [description]
   */
  public function extra_tablenav($which) {
    global $wpdb;

    $result_srv = "";

    if(isset($_GET['result'])){
      $result_srv = $_GET['result'];
    }

    switch ($result_srv) {
      case "srv_all":
        $checked1 = "checked";
        $checked2 = "";
        $checked3 = "";
        $checked4 = "";
        break;
      case "srv_live":
        $checked1 = "";
        $checked2 = "checked";
        $checked3 = "";
        $checked4 = "";
        break;
      case "srv_failed":
        $checked1 = "";
        $checked2 = "";
        $checked3 = "checked";
        $checked4 = "";
        break;
      case "srv_undefined":
        $checked1 = "";
        $checked2 = "";
        $checked3 = "";
        $checked4 = "checked";
        break;
      default:
        $checked1 = "checked";
        $checked2 = "";
        $checked3 = "";
        $checked4 = "";
    }

    $where1 = "WHERE id NOT LIKE ''";
    $where2 = "WHERE time_delay NOT LIKE '' AND response NOT LIKE '%failed%'";
    $where3 = "WHERE response LIKE '%failed%'";
    $where4 = "WHERE country LIKE ''";

    $srv_all       = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}webrtc2_stun_servers {$where1}");
    $srv_live      = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}webrtc2_stun_servers {$where2}");
    $srv_failed    = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}webrtc2_stun_servers {$where3}");
    $srv_undefined = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}webrtc2_stun_servers {$where4}");

    if ( "top" == $which ) {
      ?>
        <input id="srv_all" name="result" type="radio" style='margin-left:80px;' <?php echo($checked1); ?> onclick="stun_srv(id)">
        <label for="srv_all" style=";cursor:pointer;"><?php echo __( "All servers", "webrtc2" ); ?>(<?php echo($srv_all); ?>) </label>

        <input id="srv_live" name="result" type="radio" style="margin-left:20px;" <?php echo($checked2); ?> onclick="stun_srv(id)">
        <label for="srv_live" style="cursor:pointer;"><?php echo __( "Live servers", "webrtc2" ); ?>(<?php echo($srv_live); ?>) </label>

        <input id="srv_failed" name="result" type="radio" style="margin-left:20px;" <?php echo($checked3); ?> onclick="stun_srv(id)">
        <label for="srv_failed" style="cursor:pointer;"><?php echo __( "Failed servers", "webrtc2" ); ?>(<?php echo($srv_failed); ?>) </label>

        <input id="srv_undefined" name="result" type="radio" style="margin-left:20px;" <?php echo($checked4); ?> onclick="stun_srv(id)">
        <label for="srv_undefined" style="cursor:pointer;"><?php echo __( "Undefined", "webrtc2" ); ?>(<?php echo($srv_undefined); ?>) </label>
      <?php
    }
  }
  public function no_items() {
    $prm_search = get_option( "webrtc2_search_srv" );
    if ( "" === $prm_search ) {
      _e( "No items found." );
    } else {
      _e( "No results were found for this filter value: " . "<b>" .$prm_search  . "</b>");
      update_option( "webrtc2_search_srv", "" );
    }
  }
  /**
   * Prepare the items for the table to process
   *
   * @return Void
   */
  public function prepare_items() {
    // default...
    $data = $this->webrtc2_table_data();
    $this->process_bulk_action();
    // search...
    if ( isset($_POST["s"]) && "" !== $_POST["s"]) {
      update_option("webrtc2_search_srv", $_POST["s"]);
      $data = $this->webrtc2_table_data($_POST["s"]);
    // paged into search...
    } else if (!isset($_POST["s"]) && "" !== get_option( "webrtc2_search_srv" ) ) {
      $data = $this->webrtc2_table_data(get_option( "webrtc2_search_srv"));
    // reset search...
    } else if ( isset($_POST["s"]) && "" === $_POST["s"] ) {
      update_option("webrtc2_search_srv", "");
      $data = $this->webrtc2_table_data();
    }

    $columns  = $this->get_columns();
    $hidden   = $this->get_hidden_columns();

    $sortable = $this->get_sortable_columns();
    $this->_column_headers = $this->get_column_info();

    /* pagination */
    $srv_per_page = $this->get_items_per_page( "srv_per_page", 50 );
    $currentPage = $this->get_pagenum();
    $totalItems = count($data);

    $data = array_slice($data,(($currentPage-1) * $srv_per_page), $srv_per_page);

    $this->set_pagination_args( array(
      "total_items" => $totalItems,
      "per_page"    => $srv_per_page,
    ) );

    $this->items = $data;
  }
  /**
   * Sorting data of table.
   *
   * @return array Bulk actions
   */
  function webrtc2_usort_reorder($a, $b) {
    // If no sort, default to user_login
    $orderby = (!empty($_GET["orderby"])) ? $_GET["orderby"] : "id";
    // If no order, default to asc
    $order = (!empty($_GET["order"])) ? $_GET["order"] : "asc";
    // Determine sort order
    $result = strnatcmp($a[$orderby], $b[$orderby]);
    // Send final sort direction to usort
    return ($order === "asc") ? $result : -$result;
  }
  /**
   * Get the table data
   *
   * @param string  $search Search.
   * @return Array
   */
  private function webrtc2_table_data($search = "") {
    global $wpdb;

    $result_srv = "";

    if(isset($_GET['result'])){
      $result_srv = $_GET['result'];
    }

    switch ($result_srv) {
      case "srv_all":
        $where = "WHERE id NOT LIKE ''";
        break;
      case "srv_live":
        $where = "WHERE  time_delay NOT LIKE '' AND response NOT LIKE '%failed%'";
        break;
      case "srv_failed":
        $where = "WHERE response LIKE '%failed%'";
        break;
      case "srv_undefined":
        $where = "WHERE country LIKE ''";
        break;
      default:
        $where = "WHERE id NOT LIKE ''";
    }

    if ( !empty($search) ) {
      $result = $wpdb->get_results(
        "
        SELECT * FROM {$wpdb->prefix}webrtc2_stun_servers
        {$where} AND
        `timezone` LIKE '%{$search}%' OR
        `server_name` LIKE '%{$search}%' OR
        `ip_address` LIKE '%{$search}%'
        ",
        "ARRAY_A"
      );
    } else {
      $result = $wpdb->get_results(
        "
        SELECT *
        FROM {$wpdb->prefix}webrtc2_stun_servers
        {$where}",
        "ARRAY_A"
      );
    }

    usort($result, array($this, "webrtc2_usort_reorder"));

    return $result;
  }
  /**
   * Determines list of bulk actions.
   *
   * @return array Bulk actions
   */
  public function get_bulk_actions() {
    $actions = array(
      "delete" => __( "Delete", "webrtc2" ),
      "report" => __( "Report", "webrtc2" ),
      "update" => __( "Update", "webrtc2" ),
    );
    return $actions;
  }
  /**
   * Performs bulk actions.
   */
  private function process_bulk_action() {
    global $wpdb;

    $_id = filter_input( INPUT_POST, "id", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );

    // security check.
    if ( isset( $_POST["_wpnonce"] ) && ! empty( $_POST["_wpnonce"] ) ) {

      $nonce  = filter_input( INPUT_POST, "_wpnonce", FILTER_DEFAULT );
      $action = "bulk-" . $this->_args["plural"];

      if ( ! wp_verify_nonce( $nonce, $action ) ) {
        wp_die( "Security check failed." );
      }
    }

    $action = $this->current_action();

    switch( $action ) {
      case "delete":
        if ($_id) {
          $ids = implode( ",", $_id );
          $result = $wpdb->query(
            "
            DELETE
            FROM {$wpdb->prefix}webrtc2_stun_servers
            WHERE `id` IN ($ids)
            "
          );
        }
        break;
      case "report":
        if ($_id) {
          $_ids = implode( ",", $_id );
          $result = $wpdb->get_results(
            "
            SELECT *
            FROM {$wpdb->prefix}webrtc2_stun_servers
            WHERE `id` IN ($_ids)
            ",
            "ARRAY_A"
          );
          $this->webrtc2_create_report_stun($result);
        }
        break;
      case "update":
        if ($_id) {
          $_ids = implode( ",", $_id );
          $result = $wpdb->get_results(
            "
            SELECT *
            FROM {$wpdb->prefix}webrtc2_stun_servers
            WHERE `id` IN ($_ids)
            ",
            "ARRAY_A"
          );
          if ( !empty($result) ) {
            $this->webrtc2_update_tbl($result, "manually");
          }
        }
        break;
    }
  }
  /**
   * Update fields of tbl webrtc2_stun_servers.
   *
   * @param array $result Selected records of tbl.
   * @param array $repeat Update records or not (auto/manually/no).
   */
  public function webrtc2_update_tbl($result, $repeat) {
    global $wpdb;

    $val           = get_option( "webrtc2_main_settings" );
    $whois_service = isset( $val["whois_service"] ) ? esc_attr( $val["whois_service"] ) : "none";

    $stun_client = new WebRTC2_Stun_Client();

    foreach ( $result as $key => $record ) {
      $response_prev = $record["response"];
      $response_add = "";

      $arr = webrtc2_who_is( $record["server_name"], $whois_service );

      // A necessary pause, otherwise the WHO-IS service will choke.
      usleep(360000);

      if (!empty($arr) ) {
        if ( isset($arr["ip_address"]) && filter_var($arr["ip_address"], FILTER_VALIDATE_IP) ) {
          $stun_client->createSocket();
          $stun_client->setServerAddr($record["id"], $arr["ip_address"], $record["port"]);
          $response = $stun_client->getPublicIp();
          $stun_client->closeSocket();

          if(str_contains($response["ip"], "failed")){
            if(str_contains($response_prev, "failed")){

              $tz = wp_timezone();

              $prev_response = explode(": ", $response_prev);
              $prev_failed_days = (0 !== intval(end($prev_response))) ?intval(end($prev_response)) :1;

              $time1 = new DateTime($record["check_date"],$tz);
              $date1 = $time1->format("Y-m-d");

              $time2 = new DateTime('now',$tz);
              $date2 = $time2->format("Y-m-d");

              $short_date1 = new DateTime($date1,$tz);
              $short_date2 = new DateTime($date2,$tz);

              $interval = $short_date1->diff($short_date2);

              $failed_days = $interval->format("%d");

              if ("no" === $repeat ) {
                $response_add = $response["ip"].": ".$response["port"];
              } else {
                $response_add = $response["ip"].": ".$response["port"];
                $response_add = $response_add."<br>repeat: ".$repeat;
              }
              $sum_days = $prev_failed_days + $failed_days;
              $response_add = $response_add."<br>failed days: ".$sum_days;
            }else{
              if ("no" === $repeat ) {
                $response_add = $response["ip"].": ".$response["port"];
              } else {
                $response_add = $response["ip"].": ".$response["port"]."<br>repeat: ".$repeat;
              }
            }
          }else{
            if ("no" === $repeat ) {
              $response_add = $response["ip"].": ".$response["port"];
            } else {
              $response_add = $response["ip"].": ".$response["port"]."<br>repeat: ".$repeat;
            }
          }

          $wpdb->update( $wpdb->prefix . "webrtc2_stun_servers",
            [
            "ip_address"   => $arr["ip_address"],
            "provider"     => $arr["provider"],
            "country"      => $arr["country"],
            "timezone"     => $arr["timezone"],
            "check_date"   => current_time("mysql"),
            "response"     => $response_add,
            "time_delay"   => $response["time_delay"],
            ],
            [ 'ID' => $record["id"] ]
          );
        }
      } else {
        $wpdb->update( $wpdb->prefix . "webrtc2_stun_servers",
          [
          "ip_address" => "<span style='color:red;'>failed</span>",
          "provider"   => "<span style='color:red;'>failed</span>",
          "country"    => "<span style='color:red;'>failed</span>",
          "timezone"   => "<span style='color:red;'>failed</span>",
          "check_date" => current_time("mysql"),
          "response"   => "",
          "time_delay" => "",
          ],
          [ "id" => $record["id"] ]
        );
      }
    }
  }
  /**
   * Create report file of WP-WebRTC2: stun servers
   *
   * @param array $result Selected records for report.
   */
  public function webrtc2_create_report_stun($result) {
    WP_Filesystem();
    global $wp_filesystem;

    $path = plugin_dir_path(__FILE__) . "/report";

    $tbody = "";
    foreach ( $result as $key => $tr_value ) {
      $tr = "";
      $td = "";
      foreach ( $tr_value as $key => $td_value ) {
        $td = $td . "<td>" . $td_value . "</td>";
      }
      $tr = "<tr>" . $td . "</tr>";
      $tbody = $tbody . $tr;
    }

    $tbody = "<tbody>" . $tbody . "</tbody>";

    $table = "
    <table>
    <thead>
    <tr>
    <th>№</th>
    <th>Server name</th>
    <th>Port</th>
    <th>IP address</th>
    <th>Provider IP</th>
    <th>Country</th>
    <th>Time zone</th>
    <th>Check date</th>
    <th>Response</th>
    <th>Time delay</th>
    </tr>
    </thead>" .
    $tbody .
    "
    </table>
    ";

    $copyright = "Belarus, Minsk © 2019. Developer: Oleg Klenitsky";
    $foot = "<footer><img src='" . plugins_url( "doc/img/BY.gif" , __FILE__ ) ."'>" . $copyright . "</footer>";

    $template = "
    <!doctype html>
    <html lang='en'>
    <head>
      <meta charset='utf-8' />
      <meta name='viewport' content='width=device-width, initial-scale=1' />
      <title>Report of WP-WebRTC2: stun servers</title>
      <style type='text/css'>
        table: {
          width: 100%;
          border: 1px solid black;
        }
        th {
          background-color: #E0E0E0;
          border: 1px solid black;
        }
        td {
          border: 1px solid black;
        }
      </style>
    </head>
    <body>
    <h1>Report of WP-WebRTC2: stun servers (" . current_time('mysql') . ")</h1>" .
    $table . $foot .
    "</body></html>";

    if ($wp_filesystem->exists($path)) {
      $wp_filesystem->put_contents( $path . "/report.html", $template, FS_CHMOD_FILE );
    }
  }
  /**
   * Override the parent columns method. Defines the columns to use in your listing table
   *
   * @return Array
   */
  public function get_columns() {
    $columns = array(
      "cb"           => "<input type='checkbox'/>",
      "id"           => __( "№", "webrtc2" ),
      "server_name"  => __( "Server name", "webrtc2" ),
      "port"         => __( "Port", "webrtc2" ),
      "ip_address"   => __( "IP address", "webrtc2" ),
      "provider"     => __( "Provider", "webrtc2" ),
      "country"      => __( "Country", "webrtc2" ),
      "timezone"     => __( "Time zone", "webrtc2" ),
      "check_date"   => __( "Check date", "webrtc2" ),
      "response"     => __( "Response", "webrtc2" ),
      "time_delay"   => __( "Time delay", "webrtc2" ),
    );

    echo '<style type="text/css">';
    echo '.wp-list-table .column-cb { width: 1.5%; }';
    echo '.wp-list-table .column-id { width: 5%; }';
    echo '.wp-list-table .column-server_name { width: 12%; }';
    echo '.wp-list-table .column-port { width: 6%; }';
    echo '.wp-list-table .column-ip_address { width: 10%; }';
    echo '.wp-list-table .column-provider { width: 12%; }';
    echo '.wp-list-table .column-country { width: 11%; }';
    echo '.wp-list-table .column-timezone { width: 12%; }';
    echo '.wp-list-table .column-check_date { width: 10%; }';
    echo '.wp-list-table .column-response { width: 11%; }';
    echo '.wp-list-table .column-time_delay { width: 9%; }';
    echo '</style>';

    return $columns;
  }
  /**
   * Fills table cells with data in column cb (column 0).   intval($item[ $column_name ])
   *
   * @param  array  Content cell of table.
   * @return string sprintf(...)
   */
  public function column_cb( $item ) {
    return sprintf(
      "<input type='checkbox' name='id[]' value='%s' />", $item["id"]
    );
  }
  /**
   * Define which columns are hidden.
   *
   * @return Array
   */
  public function get_hidden_columns() {
    $hidden_cols = array();

    return $hidden_cols;
  }
  /**
   * Define the sortable columns
   *
   * @return Array
   */
  public function get_sortable_columns() {
    $sortable_columns = array(
      "id"           => array( "id", true ),
      "server_name"  => array( "server_name", true ),
      "port"         => array( "port", true ),
      "ip_address"   => array( "ip_address", true ),
      "provider"     => array( "provider", true ),
      "country"      => array( "country", true ),
      "timezone"     => array( "timezone", true ),
      "check_date"   => array( "check_date", true ),
      "response"     => array( "response", true ),
      "time_delay"   => array( "time_delay", true ),
    );
    return $sortable_columns;
  }
  /**
   * Define what data to show on each column of the table
   *
   * @param  Array $item         Data
   * @param  String $column_name Current column name
   *
   * @return Mixed
   */
  public function column_default( $item, $column_name ) {
    WP_Filesystem();
    global $wp_filesystem;

    switch( $column_name ) {
      case "id":
      case "server_name":
      case "port":
      case "ip_address":
      case "provider":
      case "timezone":
      case "check_date":
      case "country":
        $plugin_dir = plugin_dir_path( __FILE__ );
        $dir_flags  = $wp_filesystem->find_folder($plugin_dir . "images/flags/");
        $data       = explode("<br>", $item[ $column_name ]);
        $file       = trailingslashit($dir_flags) . $data[0] . ".gif";
        if ($wp_filesystem->exists($file)) {
          $plugin_url = plugins_url();
          $path_img = set_url_scheme( $plugin_url."/wp-webrtc2/", "https" )."images/flags/".$data[0].".gif";
          $img_flag = "<image src='$path_img' >";
        }else{
          $img_flag = "";
        }
        return $img_flag . $item[ $column_name ];
      case "response":
        return $item[ $column_name ];
      case "time_delay":
        if ("" !== $item[ $column_name ]) {
          return $item[ $column_name ] . " msec";
        }
    }
  }
}
