<?php

namespace idoit\Module\QCW\Model;

use idoit\Model\Dao\Base;
use idoit\Module\Cmdb\Model\CiTypeCategoryAssigner;
use idoit\Module\QCW\Provider\CRUDCount;
use isys_application;

/**
 * i-doit QCW object type group Model.
 *
 * @package     Modules
 * @subpackage  QCW
 * @author      Leonard Fischer <lfischer@i-doit.com>
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 */
class ObjectType extends Base
{
    use CRUDCount;

    /**
     * @param  mixed   $idConst         May be the ID or constant.
     * @param  boolean $withObjectCount Defines if the objects of each type should be counted.
     *
     * @return \isys_component_dao_result
     * @throws \isys_exception_database
     */
    public function load($idConst = null, $withObjectCount = false)
    {
        if ($idConst !== null) {
            if (is_numeric($idConst)) {
                $condition = 'AND isys_obj_type__id = ' . $this->convert_sql_id($idConst);
            } else {
                $condition = 'AND isys_obj_type__const = ' . $this->convert_sql_text($idConst);
            }
        } else {
            $condition = 'AND isys_obj_type__id ' . $this->prepare_in_condition(\isys_quick_configuration_wizard_dao::get_skipped_objecttypes(), true);
        }

        $counterAddition = '';

        if ($withObjectCount) {
            $counterAddition = ', (SELECT COUNT(isys_obj__id) FROM isys_obj WHERE isys_obj__isys_obj_type__id = isys_obj_type__id AND isys_obj__status = ' .
                $this->convert_sql_int(C__RECORD_STATUS__NORMAL) . ') AS count';
        }

        return $this->retrieve('SELECT * ' . $counterAddition . '
            FROM isys_obj_type
            LEFT JOIN isys_obj_type_group ON isys_obj_type_group__id = isys_obj_type__isys_obj_type_group__id
            WHERE isys_obj_type__status = ' . $this->convert_sql_int(C__RECORD_STATUS__NORMAL) . '
            ' . $condition . '
            ORDER BY isys_obj_type__sort');
    }

    /**
     * @param  integer $specificCategoryID
     * @param  integer $limit
     *
     * @return \isys_component_dao_result
     * @throws \isys_exception_database
     */
    public function loadObjectTypesBySpecificCategory($specificCategoryID, $limit = null)
    {
        if ($limit !== null) {
            $limit = 'LIMIT ' . $this->convert_sql_int($limit);
        }

        return $this->retrieve('SELECT *
            FROM isys_obj_type
            WHERE isys_obj_type__isysgui_cats__id = ' . $this->convert_sql_id($specificCategoryID) . '
            AND isys_obj_type__status = ' . $this->convert_sql_int(C__RECORD_STATUS__NORMAL) . '
            ' . $limit . ';');
    }

    /**
     * Save method for a single object type group.
     *
     * @param  mixed $idConst May be the ID or constant.
     * @param  array $data
     *
     * @return bool
     */
    public function save($idConst = null, array $data)
    {
        if ($idConst === null) {
            $this->incrementCreate();

            // Use the standard way to create a new object type!
            return \isys_cmdb_dao::instance($this->m_db)
                ->insert_new_objtype((int)$data['objectTypeGroup'], // @todo  It is not possible to create a new object type without this assignment. Fix that.
                    $data['title'], $data['const'], 1, (int)$data['container'], null, null, 65535, C__RECORD_STATUS__NORMAL, (int)$data['cats'], (int)$data['visible'], null,
                    $data['template'], $data['insertion'], $data['color']);
        }

        $sqlData = [];

        // This is necessary to prevent the user from (accidentally) overwriting language constants.
        if (isset($data['titleOrig'])) {
            if ($data['title'] != $data['titleOrig'] && $data['title'] != isys_application::instance()->container->get('language')
                    ->get($data['titleOrig'])) {
                $sqlData[] = 'isys_obj_type__title = ' . $this->convert_sql_text($data['title']);
            }
        } else {
            $sqlData[] = 'isys_obj_type__title = ' . $this->convert_sql_text($data['title']);
        }

        if (isset($data['visible'])) {
            if ($data['visible']) {
                $sqlData[] = 'isys_obj_type__show_in_tree = 1';
            } else {
                $sqlData[] = 'isys_obj_type__isys_obj_type_group__id = null';
                $sqlData[] = 'isys_obj_type__show_in_tree = 0';
            }
        }

        if (isset($data['selfdefined'])) {
            $sqlData[] = 'isys_obj_type__selfdefined = ' . $this->convert_sql_boolean($data['selfdefined']);
        }

        if (isset($data['objectTypeGroup'])) {
            $sqlData[] = 'isys_obj_type__isys_obj_type_group__id = ' . $this->convert_sql_id($data['objectTypeGroup']);
        }

        if (isset($data['cats'])) {
            $sqlData[] = 'isys_obj_type__isysgui_cats__id = ' . $this->convert_sql_id($data['cats']);
        }

        if (isset($data['template'])) {
            $sqlData[] = 'isys_obj_type__default_template = ' . $this->convert_sql_id($data['template']);
        }

        if (isset($data['color'])) {
            $sqlData[] = 'isys_obj_type__color = ' . $this->convert_sql_text($data['color']);
        }

        if (isset($data['container'])) {
            $sqlData[] = 'isys_obj_type__container = ' . $this->convert_sql_boolean($data['container']);
        }

        if (isset($data['insertion'])) {
            $sqlData[] = 'isys_obj_type__show_in_rack = ' . $this->convert_sql_boolean($data['insertion']);
        }

        $sql = 'UPDATE isys_obj_type SET ' . implode(', ', $sqlData);

        if (is_numeric($idConst)) {
            $sql .= ' WHERE isys_obj_type__id = ' . $this->convert_sql_id($idConst);
        } else {
            $sql .= ' WHERE isys_obj_type__const = ' . $this->convert_sql_text($idConst);
        }

        $this->incrementUpdate();

        return $this->update($sql . ';');
    }

    /**
     * @param   array $data
     *
     * @return  array
     */
    public function saveMultiple(array $data)
    {
        foreach ($data as $index => &$objType) {
            try {
                $objType['sort'] = $index;

                $objectTypeId = (($objType['id'] > 0) ? $objType['id'] : null);

                $objType = $this->save($objectTypeId, $objType);

                CiTypeCategoryAssigner::instance(\isys_application::instance()->database)
                    ->setDefaultCategories()
                    ->setCiTypes([$objectTypeId ?: $this->get_last_insert_id()])
                    ->assign();
            } catch (\Exception $e) {
                $objType = $e->getMessage();
            }
        }

        return $data;
    }

    /**
     * @param   mixed $idConst
     *
     * @return  boolean
     * @throws  \isys_exception_dao
     */
    public function delete($idConst)
    {
        if (empty($idConst)) {
            return true;
        }

        $sql = 'DELETE FROM isys_obj_type ';

        if (is_numeric($idConst)) {
            $sql .= 'WHERE isys_obj_type__id = ' . $this->convert_sql_id($idConst) . ';';
        } else {
            $sql .= 'WHERE isys_obj_type__const = ' . $this->convert_sql_text($idConst) . ';';
        }

        $this->incrementDelete();

        return $this->update($sql);
    }

    /**
     *
     * @param   array $data
     *
     * @return  array
     */
    public function deleteMultiple(array $data)
    {
        $data = array_filter($data);

        foreach ($data as &$objType) {
            try {
                if ($objType['id'] > 0) {
                    $objType = $this->delete($objType['id']);
                }
            } catch (\Exception $e) {
                $objType = $e->getMessage();
            }
        }

        return $data;
    }

    /**
     * Retrieve an array of all assigned global categories to a given object type.
     *
     * @param   integer $objectTypeID
     *
     * @return  array
     * @throws  \isys_exception_database
     */
    public function getAssignedGlobalCategoriesByObjectType($objectTypeID)
    {
        $categoryIDs = [];
        $result = $this->retrieve('SELECT 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 = ' . $this->convert_sql_id($objectTypeID) . ';');

        while ($row = $result->get_row()) {
            $categoryIDs[] = $row['isys_obj_type_2_isysgui_catg__isysgui_catg__id'];
        }

        return $categoryIDs;
    }

    /**
     * Retrieve an array of all assigned custom categories to a given object type.
     *
     * @param   integer $objectTypeID
     *
     * @return  array
     * @throws  \isys_exception_database
     */
    public function getAssignedCustomCategoriesByObjectType($objectTypeID)
    {
        $categoryIDs = [];
        $result = $this->retrieve('SELECT isys_obj_type_2_isysgui_catg_custom__isysgui_catg_custom__id
            FROM isys_obj_type_2_isysgui_catg_custom
            WHERE isys_obj_type_2_isysgui_catg_custom__isys_obj_type__id = ' . $this->convert_sql_id($objectTypeID) . ';');

        while ($row = $result->get_row()) {
            $categoryIDs[] = $row['isys_obj_type_2_isysgui_catg_custom__isysgui_catg_custom__id'];
        }

        return $categoryIDs;
    } // function,

    /**
     * This method will remove all assigned global categories of a given object type.
     *
     * @param   array   $categories
     * @param   integer $objectTypeID
     *
     * @return  bool
     * @throws  \isys_exception_dao
     */
    public function dismissGlobalCategoriesFromObjectType(array $categories, $objectTypeID)
    {
        return $this->update('DELETE
            FROM isys_obj_type_2_isysgui_catg
            WHERE isys_obj_type_2_isysgui_catg__isys_obj_type__id = ' . $this->convert_sql_id($objectTypeID) . '
            AND isys_obj_type_2_isysgui_catg__isysgui_catg__id ' . $this->prepare_in_condition($categories) . ';');
    }

    /**
     * This method will remove all assigned custom categories of a given object type.
     *
     * @param   array   $categories
     * @param   integer $objectTypeID
     *
     * @return  bool
     * @throws  \isys_exception_dao
     */
    public function dismissCustomCategoriesFromObjectType(array $categories, $objectTypeID)
    {
        return $this->update('DELETE
            FROM isys_obj_type_2_isysgui_catg_custom
            WHERE isys_obj_type_2_isysgui_catg_custom__isys_obj_type__id = ' . $this->convert_sql_id($objectTypeID) . '
            AND isys_obj_type_2_isysgui_catg_custom__isysgui_catg_custom__id ' . $this->prepare_in_condition($categories) . ';');
    }
}
