<?php
class Repeat {
  private static $data;

  /**
   * Método estático para inicialização de uma repetição, adicionando um array com propriedades no data
   * 
   * @param string $key Chave associativa da repetição
   * @param int $qtd Quantidade de campos dentro da repetição
   * @return void
   */
  public static function init_repeat($key, $qtd) {
    if (empty(self::$data)) {
      self::$data = [];
      $slug = $key;
      $values = Helper::get_meta($key);
      MetaboxController::add_field($key);
    } else {
      $prev_data = end(self::$data);

      /* Group */
      if ($prev_data['type'] == 'group') {
        $col = $key == "*" ? $prev_data["col"] : $key;
        $slug = $prev_data["slug"] . "[$col]";

        self::$data[array_key_last(self::$data)]['col']++;

        $values = Helper::get_value_by_indexs($prev_data["values"], $col);
      } else {
        /* Repeat */
        $row = $prev_data["row"];
        $col = $key == "*" ? $prev_data["col"] : $key;

        if ($prev_data['qtd'] == 1 && $qtd == 1)
          $slug = $prev_data["slug"] . "[$row]";
        else
          $slug = $prev_data["slug"] . "[$row][$col]";

        self::$data[array_key_last(self::$data)]['col']++;

        $values = Helper::get_value_by_indexs($prev_data["values"], $row, $col);
        // if ($qtd > 1) {
        // } else {
        // debug($prev_data["values"]);
        // $values = Helper::get_value_by_indexs($prev_data["values"], $row);
        // }
      }
    }

    self::$data[] = [
      "type" => "repeat",
      "row" => 0,
      "col" => 0,
      "qtd" => $qtd,
      "slug" => $slug,
      "values" => $values
    ];
  }

  /**
   * Método estático para inicialização de uma grupo dentro da repetição, adiciona um array com propriedades no data
   * 
   * @param string $key Chave associativa da grupo
   * @return void
   */
  public static function init_group($key, $callback) {
    $current_data = self::$data[array_key_last(self::$data)];

    $col = $key === "*" ? $current_data['col'] : $key;
    $slug = $current_data["slug"] . "[{$current_data['row']}][$col]";
    $values = Helper::get_value_by_indexs($current_data['values'], $current_data['row'], $col);

    self::$data[] = [
      "type" => "group",
      "col" => 0,
      "values" => $values,
      "slug" => $slug,
    ];

    call_user_func($callback);

    array_pop(self::$data);
  }

  /**
   * Método estático para contagem de array das retições. Pega o último valor do data e acessa a chave values, coletando o tamanho do array
   * 
   * @param void
   * @return int
   */
  public static function count() {
    $current_data = end(self::$data);

    if (empty($current_data['values'])) return 0;

    if (is_array($current_data['values']))
      return count($current_data['values']);
    else
      return 0;
  }

  /**
   * Método estático para incrementar na coluna no ultimo valor do data
   * 
   * @param void
   * @return void 
   */
  public static function increment() {
    self::$data[array_key_last(self::$data)]['col']++;
  }

  public static function end() {
    array_pop(self::$data);
  }

  /**
   * Verifica se o código está dentro de um loop.
   * 
   * @param void
   * @return boolean Retorna true se estiver dentro de um loop e false caso contrário
   */
  public static function in_loop() {
    return !empty(self::$data) ? count(self::$data) > 0 : false;
  }

  /**
   * Método estático responsável por retornar conforme estado atual do data um name correspondente, verificando as chaves e tambem os tipos atuais.
   * 
   * @param string $key Chave associativa, para usar o valor da coluna atual usar '*'
   * @return string 
   */
  public static function get_name($key = "*") {
    $current_data = end(self::$data);

    /* Group */
    if ($current_data['type'] === 'group') {
      return $key === "*" ?  $current_data['slug'] . "[{$current_data['col']}]" : $current_data['slug'] . "[$key]";
    }

    /* Repeat */
    $name = $current_data['slug'] . "[{$current_data['row']}]";

    if ($current_data['qtd'] > 1)
      $name .= ($key === "*" ? "[{$current_data['col']}]" : "[$key]");
    else
      $name .= $key !== "*" ? "[$key]" : "";

    return $name;
  }

  /**
   * Método estático responsável por retornar o valor conforme o estado atual do data, verificando as chaves e tambem os tipos atuais.
   * 
   * @param string $key Chave associativa, para usar o valor da coluna atual usar '*'
   * @return string
   */
  public static function get_value($key = "*") {
    $current_data = end(self::$data);

    if (empty($current_data['values'])) return "";


    if ($current_data['type'] === 'group') {
      $index = $key === "*" ? $current_data['col'] : $key;
      $value = Helper::get_value_by_indexs($current_data['values'], $index);
    } else {
      $value = Helper::get_value_by_indexs($current_data['values'], $current_data['row']);

      if ($current_data['qtd'] > 1) {
        $index = $key === "*" ? $current_data['col'] : $key;
        $value = Helper::get_value_by_indexs($value, $index);
      } else {
      }
    }

    return $value;
  }

  /**
   * Método estático que retorna um array com name e value obtidos através do get_name e get_value, a função inclui também a chamada do increment
   * 
   * @param string $key Chave associativa, para usar o valor da coluna atual usar '*'
   * @return array
   */
  public static function get_attr($key = "*") {
    $data = [
      "name" => self::get_name($key),
      "value" => self::get_value($key),
    ];
    self::increment();

    return $data;
  }

  /**
   * Método estático para definir o $data (usado para configurar uma repetição)
   * 
   * @param array $data Array com as configurações
   */
  public static function set_data($data) {
    self::$data = $data;
  }

  /**
   * Método estático para renderizar a repetiação
   * 
   * @param string $key Chave associativa, para usar o valor da coluna atual usar '*'
   * @param int $qtd Quantidade de campos dentro da repetição
   * @param callable $callback Função usada para renderização da repetição
   * @return string HTML dos campos gerados
   */
  public static function render($key, $qtd, $callback) {
    self::init_repeat($key, $qtd);

    for ($i = 0; $i < self::count(); $i++) {
      call_user_func($callback, $i);
      self::$data[array_key_last(self::$data)]['col'] = 0;
      self::$data[array_key_last(self::$data)]['row']++;
    }

    // Retira de data o último array
    self::end();
  }

  /**
   * Método estático para criar um grupo dentro de uma repetição
   * 
   * @param string $key Chave associativa, para usar o valor da coluna atual usar '*'
   * @param int $qtd Quantidade de campos dentro do grupo
   * @param callable $callback Função usada para renderização do grupo
   * @return string HTML do grupo
   */
  public static function group($key, $qtd, $callback) {
    self::init_group($key);

    call_user_func($callback);

    array_pop(self::$data);
  }

  /**
   * Método estático para criar um modelo do item da repetição que deve ser clonado posteriormente para adicionar mais itens
   * 
   * @param string $key Chave associativa, para usar o valor da coluna atual usar '*'
   * @param int $qtd Quantidade de campos dentro da repetição
   * @param callable $callback Função usada para renderização da repetição
   * @return string HTML dos campos gerados
   */
  public static function renderModel($key, $qtd, $callback) {
    ob_start();
    self::init_repeat($key, $qtd);
    call_user_func($callback);
    self::end();
    return ob_get_clean();
  }
}
