<?php

/**
 * @package     i-doit
 * @subpackage  General
 * @author      Van Quyen Hoang <qhoang@i-doit.org>
 * @version     1.1
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 * @since       0.9.9-9
 */
class isys_ldap_dao_import_active_directory extends isys_ldap_dao_import
{
    /**
     * @var isys_component_template_language_manager
     */
    private $language;

    /**
     * Constructor
     *
     * @param isys_component_database $p_db
     * @param isys_library_ldap       $p_library
     */
    public function __construct(isys_component_database &$p_db, isys_library_ldap $p_library)
    {
        $this->m_library = $p_library;

        parent::__construct($p_db);

        $this->language = isys_application::instance()->container->get('language');
    }

    /**
     * Prepares category ldap dn
     *
     * @param      $p_ldap_dn
     * @param null $p_obj_id
     *
     * @return array
     */
    public function prepare_catg_ldap_dn($p_ldap_dn, $p_obj_id = null)
    {
        $l_ldap_dn = $p_ldap_dn;
        $l_dao = isys_cmdb_dao_category_g_ldap_dn::instance($this->m_db);
        if ($p_obj_id != null) {
            $l_res = $l_dao->get_data(null, $p_obj_id);

            if ($l_res->num_rows() > 0) {
                $l_data = $l_res->__to_array();
                $l_ldap_dn['data_id'] = $l_data['isys_catg_ldap_dn_list__id'];
            }
        }

        return $this->parse_catg_ldap_dn($l_ldap_dn);
    }

    /**
     * Prepares global category
     *
     * @param      $p_global
     * @param null $p_obj_id
     *
     * @return array
     */
    public function prepare_catg_global($p_global, $p_obj_id = null)
    {
        $l_global = $p_global;
        $l_dao = isys_cmdb_dao_category_g_global::instance($this->m_db);
        if ($p_obj_id !== null) {
            $l_res = $l_dao->get_data(null, $p_obj_id);
            if ($l_res->num_rows() > 0) {
                $l_data = $l_res->__to_array();
                $l_global['data_id'] = $l_data['isys_catg_global_list__id'];
            }
        }

        return $this->parse_catg_global($l_global);
    }

    /**
     * @param string $applicationTitle
     *
     * @return array
     * @throws Exception
     */
    private function prepareOperatingSystem(string $applicationTitle, ?string $versionTitle)
    {
        $cmdbDao = isys_application::instance()->container->get('cmdb_dao');
        $objectTypeId = $cmdbDao->getObjectTypeId('C__OBJTYPE__OPERATING_SYSTEM');

        $applicationId = $cmdbDao->get_obj_id_by_title($applicationTitle, $objectTypeId);

        if (!$applicationId) {
            $applicationId = $cmdbDao->insert_new_obj($objectTypeId, false, $applicationTitle, null, C__RECORD_STATUS__NORMAL);
        }

        if ($versionTitle) {
            $versionDao = isys_cmdb_dao_category_g_version::instance(isys_application::instance()->container->get('database'));
            $versionId = $versionDao->get_data(
                null,
                $applicationId,
                ' AND isys_catg_version_list__title = ' . $versionDao->convert_sql_text($versionTitle),
                null,
                C__RECORD_STATUS__NORMAL
            )->get_row_value('isys_catg_version_list__id');

            if (!$versionId) {
                $versionId = $versionDao->create($applicationId, C__RECORD_STATUS__NORMAL, $versionTitle);
            }
        }

        // Take the latest entry ID from 'isys_catg_application_list' and add one.
        $l_last_id = (int)$cmdbDao
            ->retrieve('SELECT MAX(isys_catg_application_list__id) AS id FROM isys_catg_application_list LIMIT 1;')
            ->get_row_value('id');

        $l_last_id ++;

        $sysId = $cmdbDao->get_sysid_by_obj_id($applicationId);

        // @see  ID-7990  Previously this code was sitting in a different method, but only used here. So we simplify!
        return [
            'title'             => $this->language->get('LC__CATG__OPERATING_SYSTEM'),
            'const'             => 'C__CATG__OPERATING_SYSTEM',
            'category_type'     => C__CMDB__CATEGORY__TYPE_GLOBAL,
            'category_entities' => [
                $l_last_id => [
                    'data_id'    => $l_last_id,
                    'properties' => [
                        'application' => [
                            'tag'           => 'application',
                            'value'         => $applicationTitle,
                            'id'            => $applicationId,
                            'connection_id' => null,
                            'type'          => 'C__OBJTYPE__OPERATING_SYSTEM',
                            'sysid'         => $sysId,
                            'lc_title'      => $this->language->get('LC__CMDB__CATG__APPLICATION_OBJ_APPLICATION'),
                            'title'         => 'LC__CMDB__CATG__APPLICATION_OBJ_APPLICATION'
                        ],
                        'assigned_version' => [
                            'id'            => $applicationId,
                            'title'       => $applicationTitle,
                            'sysid'       => $sysId,
                            'type'        => 'C__OBJTYPE__OPERATING_SYSTEM',
                            'ref_title'   => $versionTitle,
                            'ref_type'    => 'C__CATG__VERSION',
                            'servicepack' => null,
                            'hotfix'      => null,
                            'kernel'      => null
                        ]
                    ]
                ]
            ]
        ];
    }

    /**
     * @param                   $ldapDnString
     *
     * @return isys_ldap_dao_import_active_directory
     * @throws isys_exception_ldap
     */
    public function setEntries($ldapDnString)
    {
        $entries = [];
        try {
            $cookie = '';
            do {
                $searchResource = $this->m_library->search(
                    $ldapDnString,
                    '(objectcategory=computer)',
                    [],
                    0,
                    null,
                    null,
                    null,
                    C__LDAP_SCOPE__RECURSIVE,
                    [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'value' => ['size' => 2, 'cookie' => $cookie]]]
                );
                $entries = array_merge($entries, $this->m_library->get_entries($searchResource));

                ldap_parse_result($this->m_library->get_connection(), $searchResource, $errcode, $matcheddn, $errmsg, $referrals, $controls);
                if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) {
                    // You need to pass the cookie from the last call to the next one
                    $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'];
                } else {
                    $cookie = '';
                }
            } while (!empty($cookie));
        } catch (Exception $e) {
            isys_notify::error('Something went wrong while retrieving the entries. ' . $e->getMessage());
        }

        $this->m_data = $entries;
        return $this;
    }

    /**
     * Get entries from m_data
     *
     * @return array
     */
    public function getEntriesFromData()
    {
        $return = [];
        try {
            $dao = isys_application::instance()->container->get('cmdb_dao');

            $server = $this->language->get($dao->get_object_types('C__OBJTYPE__SERVER')->get_row_value('isys_obj_type__title'));
            $client = $this->language->get($dao->get_object_types('C__OBJTYPE__CLIENT')->get_row_value('isys_obj_type__title'));

            if ($this->m_data && is_array($this->m_data)) {
                foreach ($this->m_data as $key => $value) {
                    if (is_numeric($key)) {
                        if (strtolower($value['distinguishedname'][0]) == trim(strtolower($this->m_root_dn))) {
                            continue;
                        }

                        $return[] = [
                            'id'    => $value['distinguishedname'][0],
                            'title' => $value['name'][0],
                            'type'  => (strpos($value['operatingsystem'][0], 'Server') || !isset($value['operatingsystem'][0]))
                                ? $server
                                : $client,
                        ];
                    }
                }
            }
        } catch (isys_exception_ldap $e) {
        }

        return $return;
    }

    /**
     * Prepare function which builds an import conformed array
     * @param array $p_entries
     * @return    isys_ldap_dao_import_active_directory
     * @author    Van Quyen Hoang <qhoang@i-doit.org>
     */
    public function prepare($p_entries = [])
    {
        isys_module_ldap::debug('Starting data preparation...');
        
        global $g_comp_session;

        if (!empty($p_entries)) {
            $l_arr = $p_entries;
        } else {
            $l_arr = $this->m_library->get_entries($this->m_resource);
        }
        if (!is_countable($l_arr)) {
            return $this;
        }

        isys_module_ldap::debug('Found ' . count($l_arr) . ' entries!');

        $l_dao = new isys_cmdb_dao($this->get_database_component());

        if (!defined('C__OBJTYPE__SERVER') || !defined('C__OBJTYPE__CLIENT')) {
            return $this;
        }
        $l_objtypes[C__OBJTYPE__SERVER] = $l_dao->get_object_types(C__OBJTYPE__SERVER)
            ->get_row();
        $l_objtypes[C__OBJTYPE__CLIENT] = $l_dao->get_object_types(C__OBJTYPE__CLIENT)
            ->get_row();

        foreach ($l_arr as $l_key => $l_value) {
            if (is_numeric($l_key)) {
                if (strtolower($l_value['distinguishedname'][0]) == trim(strtolower($this->m_root_dn)) ||
                    (is_array($this->m_dn_data) && !in_array($l_value['distinguishedname'][0], $this->m_dn_data))) {
                    continue;
                }

                $l_obj_info = $this->get_object_by_ldap_dn($l_value['distinguishedname'][0]);
                if ($l_obj_info) {
                    $l_obj_id = $l_obj_info['isys_obj__id'];
                    $l_created = strtotime($l_obj_info['isys_obj__created']);
                    $l_sysid = $l_obj_info['isys_obj__sysid'];
                    $l_description = $l_obj_info['isys_obj__description'];
                } else {
                    $l_obj_id = null;
                    $l_created = time();
                    $l_sysid = null;
                    $l_description = '';
                }

                if (strpos($l_value['operatingsystem'][0], 'Server') || !isset($l_value['operatingsystem'][0])) {
                    $l_obj_group = $l_dao->get_object_group_by_id($l_objtypes[C__OBJTYPE__SERVER]['isys_obj_type__isys_obj_type_group__id'])
                        ->get_row();
                    $l_obj_type = [
                        'value'        => $this->language->get($l_objtypes[C__OBJTYPE__SERVER]['isys_obj_type__title']),
                        'id'           => $l_objtypes[C__OBJTYPE__SERVER]['isys_obj_type__id'],
                        'const'        => $l_objtypes[C__OBJTYPE__SERVER]['isys_obj_type__const'],
                        'title_lang'   => $l_objtypes[C__OBJTYPE__SERVER]['isys_obj_type__title'],
                        'group'        => $l_obj_group['isys_obj_type_group__const'],
                        'sysid_prefix' => $l_objtypes[C__OBJTYPE__SERVER]['isys_obj_type__sysid_prefix']
                    ];
                } else {
                    $l_obj_group = $l_dao->get_object_group_by_id($l_objtypes[C__OBJTYPE__CLIENT]['isys_obj_type__isys_obj_type_group__id'])
                        ->get_row();
                    $l_obj_type = [
                        'value'        => $this->language->get($l_objtypes[C__OBJTYPE__CLIENT]['isys_obj_type__title']),
                        'id'           => $l_objtypes[C__OBJTYPE__CLIENT]['isys_obj_type__id'],
                        'const'        => $l_objtypes[C__OBJTYPE__CLIENT]['isys_obj_type__const'],
                        'title_lang'   => $l_objtypes[C__OBJTYPE__CLIENT]['isys_obj_type__title'],
                        'group'        => $l_obj_group['isys_obj_type_group__const'],
                        'sysid_prefix' => $l_objtypes[C__OBJTYPE__CLIENT]['isys_obj_type__sysid_prefix']
                    ];
                }

                $globalCategories = [];
                if (defined('C__CATG__GLOBAL')) {
                    $globalCategories[C__CATG__GLOBAL] = $this->prepare_catg_global([
                        'name'        => $l_value['name'][0],
                        'description' => $l_value['description'][0]
                    ], $l_obj_id);
                }

                if (defined('C__CATG__OPERATING_SYSTEM') && isset($l_value['operatingsystem'][0]) && !empty($l_value['operatingsystem'][0])) {
                    try {
                        // @see  ID-7990  Simplyfiying the way the operation system gets prepared.
                        $globalCategories[C__CATG__OPERATING_SYSTEM] = $this->prepareOperatingSystem((string)$l_value['operatingsystem'][0], (string)$l_value['operatingsystemversion'][0]);
                    } catch (Exception $e) {
                        isys_module_ldap::debug('Operating system could not be prepared: ' . $e->getMessage());
                    }
                }

                if (defined('C__CATG__LDAP_DN')) {
                    $globalCategories[C__CATG__LDAP_DN] = $this->prepare_catg_ldap_dn([
                        'title' => $l_value['distinguishedname'][0]
                    ], $l_obj_id);
                }

                $data[] = [
                    C__DATA__TITLE   => $l_value['name'][0],
                    'id'             => $l_obj_id,
                    'created'        => $l_created,
                    'created_by'     => $g_comp_session->get_current_username(),
                    'updated'        => time(),
                    'updated_by'     => $g_comp_session->get_current_username(),
                    'type'           => $l_obj_type,
                    'sysid'          => $l_sysid,
                    'status'         => C__RECORD_STATUS__NORMAL,
                    'cmdb_status'    => defined_or_default('C__CMDB_STATUS__IN_OPERATION'),
                    'description'    => $l_description,
                    'category_types' => [
                        C__CMDB__CATEGORY__TYPE_GLOBAL   => $globalCategories,
                        C__CMDB__CATEGORY__TYPE_SPECIFIC => []
                    ]
                ];
            }
        }

        $lastId = ((int)$l_dao->get_last_obj_id_from_type());
        foreach ($data as $object) {
            if ($object['id']) {
                $this->m_data[$object['id']] = $object;
            } else {
                $lastId++;
                $object['id'] = $lastId;
                $this->m_data[$lastId] = $object;
            }
        }

        return $this;
    }
}
