<?php

class Helper {
  /**
   * Método estático que recebe um array e as posições desejadas, a função verifica se cada posição existe
   * e avança para a próxima posição ate atingir a última e retorna se o valor existir naquela posição, caso
   * não exista, ele retorna null
   * 
   * @param mixed $array Espera array de origem
   * @param mixed ...$indexs Posições de acesso
   * @return array|string O valor correspondente ou null 
   */
  public static function get_value_by_indexs($data, ...$indexs) {
    $current_data = $data;

    foreach ($indexs as $index) {
      if (isset($current_data[$index]))
        $current_data = $current_data[$index];
      else
        return null;
    }

    return $current_data;
  }

  /**
   * Recupera valor do id do post/tag através da variavel global $post ou do GET
   * 
   * @return int|null Retorna o id do post/tag
   */
  public static function get_the_ID() {
    global $post, $pagenow;
    if (empty($post))
      if ($pagenow === 'post.php')
        return $_GET['post'] ?? null;
      else
        return $_GET['tag_ID'] ?? null;

    return $post->ID ?? null;
  }

  /**
   * Recuperar valor correspondente ao estado atual do código, verificando se deve puxar do get_post ou do get_term
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_meta($key) {
    switch (MetaboxController::get_type()) {
      case 'post':
        return get_post_meta(Helper::get_the_ID(), $key, true);
        break;
      case 'term':
        return get_term_meta(Helper::get_the_ID(), $key, true);
        break;
      case 'none':
        return get_option($key);
        break;
    }
  }

  /**
   * Recuperar valor correspondente ao estado atual do código
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_value($key = "*") {

    /* Dentro de uma repetição */
    if (Repeat::in_loop())
      return Repeat::get_value($key);

    /* Dentro de um grupo */
    if (Group::in_group())
      return Group::get_value($key);

    /* Recurar meta */
    return self::get_meta($key);
  }

  /**
   * Método estático que recebe um valor e retorna ele sanitizado, caso o valor seja um array retornará string vazia
   * 
   * @param mixed $value 
   * @return string Valor serializado ou string vazia
   */
  public static function sanitize_value($value) {
    if (is_array($value)) return "";
    return htmlspecialchars($value);
  }

  /**
   * Adiciona o nome do campo no atributo do Metabox para ser salvo posteriormente
   * 
   * @param $key O nome do campo.
   */
  public static function save_field($key) {
    MetaboxController::add_field($key);
  }

  /**
   * Recuperar valor correspondente ao estado atual do código e retorna ele sanitizado
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_sanitized_value($key = "*") {
    return self::sanitize_value(self::get_value($key));
  }

  /**
   * Recuperar um nome correspondente ao estado atual do código
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_name($key = "*") {
    /* Dentro de uma repetição */
    if (Repeat::in_loop())
      return Repeat::get_name($key);

    /* Dentro de um grupo */
    if (Group::in_group())
      return Group::get_name($key);

    /* Recurar meta */
    return $key;
  }

  /**
   * Recuperar um nome correspondente ao estado atual do código e retorna ele sanitizado
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_sanitized_name($key = "*") {
    return self::sanitize_value(self::get_name($key));
  }

  /**
   * Retorna o nome e valor correspondente ao estado atual do código 
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_attr($key = "*") {

    /* Dentro de uma repetição */
    if (Repeat::in_loop())
      return Repeat::get_attr($key);

    /* Dentro de um grupo */
    if (Group::in_group())
      return Group::get_attr($key);

    self::save_field($key);

    /* Recurar meta */
    return ["name" => $key, "value" => self::get_meta($key)];
  }

  /**
   * Retorna o nome e valor correspondente ao estado atual do código sanitizados
   * 
   * @param strin $key Chave associativa, para usar o valor atual da coluna definir como '*'
   */
  public static function get_sanitized_attr($key = "*") {
    $attr = self::get_attr($key);
    $attr["name"] = Helper::sanitize_value($attr["name"]);
    $attr["value"] = Helper::sanitize_value($attr["value"]);
    return $attr;
  }

  /**
   * Verifica se o array passado é associativo ou não
   * 
   * Essa função retornará true ou falso em caso de ser associativo.
   * 
   * @param array $array Array de teste.
   * @return bool Retorna true ou falso para o teste
   */
  public static function is_associative_array($array) {
    if (!is_array($array)) return false;
    $keys = array_keys($array);
    // Verifica se pelo menos uma chave não é um número ou se as chaves numéricas não são sequenciais
    return count(array_filter($keys, 'is_string')) > 0 || array_keys($array) !== range(0, count($array) - 1);
  }

  /**
   * Verifica se o valor é igual ou se está contido no segundo parâmetro.
   *
   * Esta função recebe um valor como primeiro parâmetro e verifica se ele é igual ao segundo parâmetro fornecido. 
   * Caso o segundo parâmetro seja um array, a função verifica se o valor está contido nesse array.
   *
   * @param mixed $value O valor a ser verificado.
   * @param mixed $parameter O segundo parâmetro que pode ser um valor único ou um array.
   * @return bool Retorna true se o valor for igual ao parâmetro ou se estiver contido no array (caso seja um array), caso contrário retorna false.
   */
  public static function check_value($value, $parameter) {
    if (is_array($parameter)) {
      return in_array($value, $parameter);
    } else {
      return $value == $parameter;
    }
  }

  /**
   * Verifica se o array fornecido é um array de arrays ou um array simples.
   *
   * @param mixed $arr O array a ser verificado.
   * @return bool Retorna true se o array for um array de arrays, caso contrário, retorna false.
   */
  public static function is_array_of_arrays($arr) {
    $is_array_of_arrays = true;

    if (!is_array($arr))
      return false;

    foreach ($arr as $element) {
      if (!is_array($element)) {
        $is_array_of_arrays = false;
        break;
      }
    }
    return $is_array_of_arrays;
  }
}
