<?php
namespace idoit\Module\Forms\Model\CategoryTypes;

use idoit\Module\Multiedit\Component\Multiedit\Exception\CategoryDataException;
use idoit\Module\Multiedit\Model\GlobalCategories as CategoryModel;
use isys_component_database;
use isys_application;
use isys_cmdb_dao_category;

/**
 * Can be removed after 1.18.
 */
class GlobalCategories extends CategoryModel
{
  /**
   * @return GlobalCategories
   * @throws \isys_exception_database
   */
  public function setData(): GlobalCategories
  {
    $blockListAsString = implode(',', $this->getBlacklist());
    $supportedCategoriesAsString = implode(',', $this->getSupportedCategoryTypes());
    $container = isys_application::instance()->container;
    $language = $container->get('language');
    $categoryFilterCondition = '';
    $conditionFirstPart = $conditionSecondPart = [];

    try {
      $query = "SELECT *, (SELECT isysgui_catg__title FROM isysgui_catg WHERE isysgui_catg__id = main.isysgui_catg__parent) AS parent FROM isysgui_catg main
                INNER JOIN isys_property_2_cat propCat ON propCat.isys_property_2_cat__isysgui_catg__id = main.isysgui_catg__id
                WHERE main.isysgui_catg__type IN ({$supportedCategoriesAsString}) AND main.isysgui_catg__id NOT IN ({$blockListAsString}) AND
                !LOCATE('_ROOT', main.isysgui_catg__const) AND !LOCATE('_NAGIOS', main.isysgui_catg__const) %s
                UNION SELECT *, (SELECT isysgui_catg__title FROM isysgui_catg WHERE isysgui_catg__id = main.isysgui_catg__parent) AS parent FROM isysgui_catg main
                LEFT JOIN isys_property_2_cat propCat ON propCat.isys_property_2_cat__isysgui_catg__id = main.isysgui_catg__id
                WHERE main.isysgui_catg__parent IN (SELECT DISTINCT isysgui_catg__parent FROM isysgui_catg) AND main.isysgui_catg__id NOT IN ({$blockListAsString}) %s";

      $filter = $this->getFilter();

      if (!empty($filter->getObjects())) {
        $conditionFirstPart[] = ' main.isysgui_catg__id IN (
                    SELECT DISTINCT isys_obj_type_2_isysgui_catg__isysgui_catg__id FROM isys_obj_type_2_isysgui_catg WHERE isys_obj_type_2_isysgui_catg__isys_obj_type__id IN (
                        SELECT DISTINCT isys_obj__isys_obj_type__id FROM isys_obj WHERE isys_obj__id IN (' . implode(',', $filter->getObjects()) . ')
                    )
                )';
        $conditionSecondPart[] = ' main.isysgui_catg__parent IN (
                    SELECT DISTINCT isys_obj_type_2_isysgui_catg__isysgui_catg__id FROM isys_obj_type_2_isysgui_catg WHERE isys_obj_type_2_isysgui_catg__isys_obj_type__id
                    IN (
                        SELECT DISTINCT isys_obj__isys_obj_type__id FROM isys_obj WHERE isys_obj__id IN (' . implode(',', $filter->getObjects()) . ')
                    )
                )';
      }

      if (empty($filter->getObjects()) && !empty($filter->getObjectTypes())) {
        $objectTypes = $filter->getObjectTypes();
        $objectTypes = array_filter($objectTypes, 'defined');

        if (!empty($objectTypes)) {
          $objectTypes = array_map('defined_or_default', $objectTypes);

          $conditionFirstPart[] = ' main.isysgui_catg__id IN (
                        SELECT DISTINCT isys_obj_type_2_isysgui_catg__isysgui_catg__id FROM isys_obj_type_2_isysgui_catg WHERE isys_obj_type_2_isysgui_catg__isys_obj_type__id IN (
                            ' . implode(',', $objectTypes) . '
                        ))';
          $conditionSecondPart[] = ' main.isysgui_catg__parent IN (
                        SELECT DISTINCT isys_obj_type_2_isysgui_catg__isysgui_catg__id FROM isys_obj_type_2_isysgui_catg WHERE isys_obj_type_2_isysgui_catg__isys_obj_type__id
                        IN (
                            ' . implode(',', $objectTypes) . '
                        ))';
        }
      }

      $categories = $filter->getCategories();

      if (!empty($categories) && !in_array('*', $categories)) {
        $categoryFilterCondition = ' main.isysgui_catg__const IN (\'' . implode('\',\'', $categories) . '\')';
        if (is_numeric($categories[0])) {
          $categoryFilterCondition = ' main.isysgui_catg__id IN (' . implode(',', $categories) . ')';
        }
        $conditionFirstPart[] = $categoryFilterCondition;
        $conditionSecondPart[] = $categoryFilterCondition;
      }

      $result = $this->retrieve(rtrim(sprintf($query, (!empty($conditionFirstPart) ? ' AND ' . implode(' AND ', $conditionFirstPart) : ''), (!empty($conditionSecondPart) ? ' AND ' . implode(' AND ', $conditionSecondPart) : '')), 'AND'));
      while ($row = $result->get_row()) {
        // @see  ID-6622  This should prevent errors after categories have been removed.
        if (!class_exists($row['isysgui_catg__class_name'])) {
          continue;
        }

        $this->data[$this->getType() . '_' . $row['isysgui_catg__id'] . ':' . $row['isysgui_catg__class_name']] =
            $language->get($row['isysgui_catg__title']);
        $this->increment();

        $checkSql = 'SELECT isys_property_2_cat__prop_key FROM isys_property_2_cat
            WHERE isys_property_2_cat__cat_const = ' . $this->convert_sql_text($row['isysgui_catg__const']) . '
            AND isys_property_2_cat__prop_type = ' . $this->convert_sql_int(C__PROPERTY_TYPE__STATIC) . '
            AND isys_property_2_cat__prop_key != ' . $this->convert_sql_text('description') . '
            AND isys_property_2_cat__prop_provides & ' . $this->convert_sql_int(C__PROPERTY__PROVIDES__MULTIEDIT);

        $checkResult = $this->retrieve($checkSql);
        $numProperties = $checkResult->num_rows();

        if ($numProperties === 1) {
          $propKey = $checkResult->get_row_value('isys_property_2_cat__prop_key');
          $catDao = $row['isysgui_catg__class_name']::instance($container->get('database'));
          $properties = $catDao->get_properties();
          $property = $properties[$propKey];

          if ((int)$property[C__PROPERTY__INFO][C__PROPERTY__INFO__TYPE] === C__PROPERTY__INFO__TYPE__OBJECT_BROWSER ||
            (int)$property[C__PROPERTY__INFO][C__PROPERTY__INFO__TYPE] === C__PROPERTY__INFO__TYPE__N2M) {
            continue;
          }
        } elseif ($numProperties === 0) {
          // Remove category from list, because there are no properties which are usable for the multiedit list
          unset($this->data[$this->getType() . '_' . $row['isysgui_catg__id'] . ':' . $row['isysgui_catg__class_name']]);
          $this->decrement();
          continue;
        }

        if ($row['isysgui_catg__list_multi_value'] > 0) {
          $this->addToMultivalueCategories($row['isysgui_catg__id']);
        }
      }

      return $this;
    } catch (\Exception $e) {
      throw new CategoryDataException('Collecting global categories failed in File : ' . $e->getFile() . ' on Line: ' . $e->getLine() . ' with Message: ' . $e->getMessage());
    }
  }
}
