<?php

namespace Drupal\user_provisioning\Helpers;

/**
 * Provides a ready-made table with ajax add/remove rows button.
 *
 * This class provides you three functionality:
 *
 *    (1) Generate Tables
 *
 *    (2) Generate Add more button
 *
 *    (3) Generate unique id array
 *
 * - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * (1) Generate Tables:
 * You can generate simple table by providing few parameters
 * to function generateTables().
 * This function required following parameters:
 * (i) ID: Unique ID of table useful for ajax operations
 * (ii) fields: Number of fields in table.
 * You can add as many fields as you want.
 * Field should be an array in following format:
 * @code
 * $fields = [
 *  'first_name' => [
 *     'type' => 'select',
 *  ],
 * 'last_name' => [
 *    'type' => 'textfield',
 *    'placeholder' => 'Last Name of User'
 *  ],
 * 'delete_button' => [
 *    'type' => 'submit',
 *    'submit' => '::removeCallback',
 *    'callback' => '::removeButtonCallback',
 *    'wrapper' => 'names-fieldset-wrapper',
 *    ]
 *  ];
 * (iii) Unique ID array: This is the array which contains array of unique array to print rows
 * (iv) Options: default options to show in the  table
 * (v) Headers (optional): header of the table in the array format
 * (vi) Option to show in drop-down list (optional): This should be an array with following format:
 * @code
 * $select_list = [
 *  1 => [
 *    'first_column_row_1' => 'one',
 *    'first_column_row_2' => 'two',
 *    'first_column_row_3' => 'three',
 *    'first_column_row_4' => 'four',
 *  ]
 *  2 => [
 *    'second_column_row_1' => 'one',
 *    'second_column_row_2' => 'two',
 *    'second_column_row_3' => 'three',
 *    'second_column_row_4' => 'four',
 *  ]
 * ]
 * In above array $select_list -> 1 and 2 denoted column number where you want to show drop-down select list
 *
 * - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * (2) Generate Add more button:
 * You can easily generate add more button by providing few parameters to generateAddButton() function
 * You need to provide name of button, submit function, callback function, text before button etc.
 *
 * - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * (3) Generate unique id array:
 * Unique id array contains array key of each table row, and it is used to print rows of table.
 * This array updates on every ajax call. Use generateAddButton() function to generate this array.
 */
class AjaxTables {

  /**
   * Main function to generate tables.
   *
   * @param string $id
   *   ID of the table, useful for ajax wrapper.
   * @param array $fields
   *   Array of fields to be used in table.
   * @param array $unique_array
   *   Array containing index of rows.
   * @param array $options
   *   Main data to be printed in table.
   * @param array $headers
   *   Header of the table.
   * @param array $select_list
   *   Options for select element (optional).
   * @param array $default_rows
   *   Row ids that must not show delete action.
   *
   * @return array
   *   Returns complete table.
   */
  public static function generateTables($id, $fields, $unique_array, $options, array $headers = [], array $select_list = [], array $default_rows = []) {
    $form['table'] = [
      '#type' => 'table',
      '#header' => $headers,
      '#prefix' => '<div id="' . $id . '">',
      '#suffix' => '</div>',
    ];

    foreach ($unique_array as $row) {
      $form['table'][$row] = static::generateFields($fields, $row, $select_list, $default_rows);
      foreach ($fields as $key => $value) {
        if ($value['type'] != 'submit') {
          $form['table'][$row][$key]['#default_value'] = $options[$row][$key] ?? '';
        }
        if (count($unique_array) == 1 && $value['type'] == 'submit') {
          unset($form['table'][$row][$key]);
        }
      }
    }

    return $form['table'];
  }

  /**
   * The $option parameter should use the following format.
   *
   * $option = ['unique_id' => ['field_name' => 'field_value']]
   *
   * @param array $form_state_value
   *   Value of unique array in form_state.
   * @param array $options
   *   The options array to print in table format.
   *
   * @return int[]|string[]
   *   Returns array of unique id array.
   */
  public static function getUniqueId($form_state_value, $options) {
    if (empty($form_state_value)) {
      $form_state_value = array_keys($options);
      if (empty($options)) {
        $uuid_service = \Drupal::service('uuid');
        $form_state_value[] = $uuid_service->generate();
      }
    }
    return $form_state_value;
  }

  /**
   * Generates row field elements for the dynamic table.
   *
   * @param array $fields
   *   Fields to be generated.
   * @param int|string $row
   *   Unique ID of the row.
   * @param array $select_list
   *   Options for form type select (optional).
   * @param array $default_rows
   *   Row ids where delete button should stay hidden.
   *
   * @return array
   *   Row field elements.
   */
  private static function generateFields($fields, $row, $select_list, $default_rows) {
    $form = [];
    $count = 1;
    foreach ($fields as $key => $value) {
      $form[$key] = [
        '#type' => $value['type'],
        '#title' => $value['title'] ?? '',
        '#attributes' => $value['attributes'] ?? [],
        '#description' => $value['description'] ?? '',
        '#disabled' => $value['disabled'] ?? FALSE,
      ];

      if (isset($value['prefix'])) {
        $form[$key]['#prefix'] = $value['prefix'];
      }

      if (isset($value['suffix'])) {
        $form[$key]['#suffix'] = $value['suffix'];
      }

      if ($value['type'] == 'select') {
        $form[$key]['#options'] = $select_list[$count];
        $form[$key]['#empty_option'] = t('Select Attribute Value');
      }

      if ($value['type'] == 'textfield') {
        $form[$key]['#size'] = 15;
      }

      if ($value['type'] == 'submit') {
        if (!in_array($row, $default_rows)) {
          unset($form[$key]['#title']);
          $form[$key]['#name'] = $row;
          $form[$key]['#type'] = 'image_button';
          $form[$key]['#src'] = '/modules/user_provisioning/images/trash.svg';
          $form[$key]['#attributes'] = [
            'alt' => t('Delete'),
            'title' => t('Delete this row'),
            'class' => ['delete-row-icon'],
          ];

          $form[$key]['#submit'] = [$value['submit']];
          $form[$key]['#ajax'] = [
            'callback' => $value['callback'],
            'wrapper' => $value['wrapper'],
            'progress' => ['type' => 'fullscreen'],
          ];
        }
        else {
          $form[$key]['#access'] = FALSE;
        }
      }
      $count++;
    }
    return $form;
  }

  /**
   * Automatically generates an AJAX "add more" button.
   *
   * If you have to generate more than one button on the same form,
   * use a different name for each button.
   *
   * @param string $value
   *   Value of the add button.
   * @param string $submit
   *   Function to call of ajax call where logic of add row is written.
   *   Function name should be in '::nameOfFunction' format.
   * @param string $callback
   *   Callback function in ajax call.
   *   Function name should be in '::callbackFunction' format.
   * @param string $wrapper
   *   An ajax wrapper.
   * @param string $text_before_button
   *   Text to show before the add button (optional).
   * @param bool $disabled
   *   Status of button i.e disabled or enabled.
   *
   * @return array
   *   Ajax add more button.
   */
  public static function generateAddButton($value, $submit, $callback, $wrapper, string $text_before_button = '', bool $disabled = FALSE) {
    $form['text_before_button'] = [
      '#markup'  => t('<b>@text&#8194;</b>', ['@text' => $text_before_button]),
      '#prefix'  => '<div class="container-inline">',
    ];

    $form['button'] = [
      '#type' => 'submit',
      '#suffix' => '</div>',
      '#attributes' => ['class' => ['button--small button--primary']],
      '#value' => $value,
      '#submit' => [$submit],
      '#disabled' => $disabled,
      '#ajax' => [
        'callback' => $callback,
        'wrapper' => $wrapper,
        'progress' => [
          'type' => 'fullscreen',
        ],
      ],
    ];
    return $form;
  }

}
