<?php
/**
 * @author Jaap Jansma <jaap.jansma@civicoop.org>
 * @license AGPL-3.0
 */

use Civi\DataProcessor\DataFlow\InvalidFlowException;
use Civi\DataProcessor\FieldOutputHandler\OutputHandlerAggregate;
use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
use CRM_Dataprocessor_ExtensionUtil as E;

class CRM_DataprocessorSearch_Form_Search extends CRM_DataprocessorSearch_Form_AbstractSearch {


  /**
   * Returns the url for view of the record action
   *
   * @param $row
   *
   * @return false|string
   */
  protected function link($row):? string {
    return false;
  }

  /**
   * Returns the link text for view of the record action
   *
   * @param $row
   *
   * @return false|string
   */
  protected function linkText($row):? string {
    return false;
  }

  /**
   * Return the data processor name
   *
   * @return String
   */
  protected function getDataProcessorName(): string {
    return str_replace('civicrm/dataprocessor_search/', '', CRM_Utils_System::currentPath());
  }

  /**
   * Returns the name of the output for this search
   *
   * @return string
   */
  protected function getOutputName(): string {
    return 'search';
  }

  /**
   * Checks whether the output has a valid configuration
   *
   * @return bool
   */
  protected function isConfigurationValid(): bool {
    if (!isset($this->dataProcessorOutput['configuration']['id_field'])) {
      return false;
    }
    return true;
  }

  /**
   * Returns the name of the ID field in the dataset.
   *
   * @return string
   */
  public function getIdFieldName(): string {
    return $this->dataProcessorOutput['configuration']['id_field'];
  }

  /**
   * @return false|string
   */
  protected function getEntityTable():? string {
    return false;
  }

  /**
   * Returns an array with hidden columns
   *
   * @return array
   */
  protected function getHiddenFields(): array {
    $hiddenFields = array();
    if (!$this->isIdFieldVisible()) {
      $hiddenFields[] = $this->getIdFieldName();
    }
    if ($this->isSubmitted() && isset($this->dataProcessorOutput['configuration']['expose_hidden_fields']) && $this->dataProcessorOutput['configuration']['expose_hidden_fields']) {
      $submittedHiddenFields = isset($this->_formValues['hidden_fields']) && is_array($this->_formValues['hidden_fields']) ? $this->_formValues['hidden_fields'] : array();
      $hiddenFields = array_merge($hiddenFields, $submittedHiddenFields);
    } elseif (isset($this->dataProcessorOutput['configuration']['hidden_fields']) && is_array($this->dataProcessorOutput['configuration']['hidden_fields'])) {
      $hiddenFields = array_merge($hiddenFields, $this->dataProcessorOutput['configuration']['hidden_fields']);
    }
    return $hiddenFields;
  }

  /**
   * Builds the list of tasks or actions that a searcher can perform on a result set.
   *
   * @return array
   */
  public function buildTaskList(): array {
    if (!$this->_taskList) {
      $this->_taskList = CRM_DataprocessorSearch_Task::taskTitles();
    }
    return $this->_taskList;
  }

  /**
   * Build the criteria form
   */
  protected function buildCriteriaForm() {
    parent::buildCriteriaForm();
    $this->buildAggregateForm();
    $this->buildHiddenFieldsForm();
  }

  /**
   * Returns the name of the additional criteria template.
   *
   * @return false|String|array
   */
  protected function getAdditionalCriteriaTemplate():? string {
    $return = [];
    if (isset($this->dataProcessorOutput['configuration']['expose_aggregate']) && $this->dataProcessorOutput['configuration']['expose_aggregate']) {
      $return[] = "CRM/DataprocessorSearch/Form/Criteria/AggregateCriteria.tpl";
    }
    if (isset($this->dataProcessorOutput['configuration']['expose_hidden_fields']) && $this->dataProcessorOutput['configuration']['expose_hidden_fields']) {
      $return[] = "CRM/DataprocessorSearch/Form/Criteria/HiddenFieldsCriteria.tpl";
    }
    if (!empty($return)) {
      return $return;
    }
    return false;
  }

  /**
   * Build the aggregate form
   */
  protected function buildHiddenFieldsForm() {
    if (!isset($this->dataProcessorOutput['configuration']['expose_hidden_fields']) || !$this->dataProcessorOutput['configuration']['expose_hidden_fields']) {
      return;
    }
    $size = $this->getCriteriaElementSize();

    $sizeClass = 'huge';
    $minWidth = 'min-width: 250px;';
    if ($size =='compact') {
      $sizeClass = 'medium';
      $minWidth = '';
    }

    $fields = array();
    $defaults = array();
    try {
      $outputFieldHandlers = $this->dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
      foreach ($outputFieldHandlers as $outputFieldHandler) {
        $fields[$outputFieldHandler->getOutputFieldSpecification()->alias] = $outputFieldHandler->getOutputFieldSpecification()->title;
      }
    } catch (InvalidFlowException $e) {
    }
    if (isset($this->dataProcessorOutput['configuration']['hidden_fields']) && is_array($this->dataProcessorOutput['configuration']['hidden_fields'])) {
      $defaults = $this->dataProcessorOutput['configuration']['hidden_fields'];
    }

    try {
      $this->add('select', "hidden_fields", '', $fields, FALSE, [
        'style' => $minWidth,
        'class' => 'crm-select2 ' . $sizeClass,
        'multiple' => TRUE,
        'placeholder' => E::ts('- Select -'),
      ]);
    } catch (CRM_Core_Exception $e) {
    }

    $this->setDefaults(['hidden_fields' => $defaults]);
  }


  /**
   * Build the aggregate form
   */
  protected function buildAggregateForm() {
    if (!isset($this->dataProcessorOutput['configuration']['expose_aggregate']) || !$this->dataProcessorOutput['configuration']['expose_aggregate']) {
      return;
    }
    $size = $this->getCriteriaElementSize();

    $sizeClass = 'huge';
    $minWidth = 'min-width: 250px;';
    if ($size =='compact') {
      $sizeClass = 'medium';
      $minWidth = '';
    }

    $aggregateFields = array();
    $defaults = array();
    try {
      $outputFieldHandlers = $this->dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
      foreach ($outputFieldHandlers as $outputFieldHandler) {
        if ($outputFieldHandler instanceof OutputHandlerAggregate) {
          $aggregateFields[$outputFieldHandler->getAggregateFieldSpec()->alias] = $outputFieldHandler->getOutputFieldSpecification()->title;
          if ($outputFieldHandler->isAggregateField()) {
            $defaults[] = $outputFieldHandler->getAggregateFieldSpec()->alias;
          }
        }
      }
    } catch (InvalidFlowException $e) {
    }

    try {
      $this->add('select', "aggregateFields", '', $aggregateFields, FALSE, [
        'style' => $minWidth,
        'class' => 'crm-select2 ' . $sizeClass,
        'multiple' => TRUE,
        'placeholder' => E::ts('- Select -'),
      ]);
    } catch (CRM_Core_Exception $e) {
    }

    $this->setDefaults(['aggregateFields' => $defaults]);
  }

  /**
   * Returns whether the search has required filters.
   *
   * @return bool
   */
  protected function hasExposedFilters(): bool {
    $return = parent::hasExposedFilters();
    if (!$return && isset($this->dataProcessorOutput['configuration']['expose_aggregate']) && $this->dataProcessorOutput['configuration']['expose_aggregate']) {
      $return = true;
    }
    if (!$return && isset($this->dataProcessorOutput['configuration']['expose_hidden_fields']) && $this->dataProcessorOutput['configuration']['expose_hidden_fields']) {
      $return = true;
    }
    return $return;
  }

  /**
   * Alter the data processor.
   *
   * Use this function in child classes to add for example additional filters.
   *
   * E.g. The contact summary tab uses this to add additional filtering on the contact id of
   * the displayed contact.
   *
   * @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
   */
  protected function alterDataProcessor(AbstractProcessorType $dataProcessorClass) {
    if ($this->isSubmitted() && isset($this->dataProcessorOutput['configuration']['expose_aggregate']) && $this->dataProcessorOutput['configuration']['expose_aggregate']) {
      $aggregateFields = $this->_formValues['aggregateFields'] ?? [];
      try {
        $outputFieldHandlers = $this->dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
        foreach ($outputFieldHandlers as $outputFieldHandler) {
          if ($outputFieldHandler instanceof OutputHandlerAggregate) {
            $alias = $outputFieldHandler->getAggregateFieldSpec()->alias;
            if (in_array($alias, $aggregateFields) && !$outputFieldHandler->isAggregateField()) {
              $outputFieldHandler->enableAggregation();
            }
            elseif (!in_array($alias, $aggregateFields) && $outputFieldHandler->isAggregateField()) {
              $outputFieldHandler->disableAggregation();
            }
          }
        }
      } catch (InvalidFlowException $e) {
      }
    }
  }

}
