<?php

/*
 * Copyright 2005 - 2025 Centreon (https://www.centreon.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 *
 */

class ItopProvider extends AbstractProvider
{
    public const ITOP_ORGANIZATION_TYPE = 10;
    public const ITOP_CALLER_TYPE = 11;
    public const ITOP_SERVICE_TYPE = 12;
    public const ITOP_SERVICE_SUBCATEGORY_TYPE = 13;
    public const ARG_CONTENT = 1;
    public const ARG_TITLE = 2;
    public const ARG_ORGANIZATION = 3;
    public const ARG_CALLER = 4;
    public const ARG_ORIGIN = 5;
    public const ARG_SERVICE = 6;
    public const ARG_SERVICE_SUBCATEGORY = 7;
    public const ARG_IMPACT = 8;
    public const ARG_URGENCY = 9;

    protected $proxy_enabled = 1;

    protected $close_advanced = 1;

    protected $internal_arg_name = [
        self::ARG_CONTENT => 'content',
        self::ARG_TITLE => 'title',
        self::ARG_ORGANIZATION => 'organization',
        self::ARG_CALLER => 'caller',
        self::ARG_ORIGIN => 'origin',
        self::ARG_SERVICE => 'service',
        self::ARG_SERVICE_SUBCATEGORY => 'service_subcategory',
        self::ARG_IMPACT => 'impact',
        self::ARG_URGENCY => 'urgency',
    ];

    /*
    * checks if all mandatory fields have been filled
    *
    * @return {array} telling us if there is a missing parameter
    */
    public function validateFormatPopup()
    {
        $result = ['code' => 0, 'message' => 'ok'];
        $this->validateFormatPopupLists($result);

        return $result;
    }

    /*
    * test if we can reach Itop webservice with the given Configuration
    *
    * @param {array} $info required information to reach the itop api
    *
    * @return {bool}
    *
    * throw \Exception if there are some missing parameters
    * throw \Exception if the connection failed
    */
    public static function test($info)
    {
        // this is called through our javascript code. Those parameters are already checked in JS code.
        // but since this function is public, we check again because anyone could use this function
        if (
            ! isset($info['address'])
            || ! isset($info['api_version'])
            || ! isset($info['username'])
            || ! isset($info['password'])
            || ! isset($info['protocol'])
        ) {
            throw new Exception('missing arguments', 13);
        }
        // check if php curl is installed
        if (! extension_loaded('curl')) {
            throw new Exception("couldn't find php curl", 10);
        }

        $curl = curl_init();
        $apiAddress = $info['protocol'] . '://' . $info['address'] . '/webservices/rest.php?version='
        . $info['api_version'];

        $data = ['operation' => 'list_operations'];

        $query = ['auth_user' => $info['username'], 'auth_pwd' => $info['password'], 'json_data' => json_encode($data)];

        // initiate our curl options
        curl_setopt($curl, CURLOPT_URL, $apiAddress);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, $info['timeout']);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($query));
        // execute curl and get status information
        $curlResult = json_decode(curl_exec($curl), true);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);

        if ($httpCode >= 400) {
            // return false;
            throw new Exception('curl result: ' . $curlResult . '|| HTTP return code: ' . $httpCode, 1);
        }

        if ($curlResult['code'] !== 0) {
            throw new Exception($curlResult['message']);
        }

        return true;
    }

    /*
    * get callers from itop
    *
    * $param {array} $data selected organization and ITOP_CALLER_TYPE group data
    *
    * @return {array} $listCallers list of callers
    *
    * throw \Exception if we can't get callers data
    */
    public function getCallers($data)
    {
        $key = "SELECT Person WHERE status='active'";

        if (preg_match('/(.*?)___(.*)/', $data['organization_value'], $matches)) {
            $key .= " AND org_id='" . $matches[1] . "'";
        } else {
            throw new Exception('No organization found', 1);
        }

        $filter = $data['groups']['itop_caller']['filter'];
        if (isset($filter) && $filter != '') {
            $key .= " AND friendlyname LIKE '%" . $filter . "%'";
        }

        $data = ['operation' => 'core/get', 'class' => 'Person', 'key' => $key, 'output_fields' => 'friendlyname'];

        try {
            $listCallers = $this->getCache('itop_caller_' . $matches[1]);
            if (is_null($listCallers)) {
                // if no callers were found in cache, get them from itop and put them in cache for 8 hours
                $listCallers = $this->curlQuery($data);
                $this->setCache('itop_caller_' . $matches[1], $listCallers, 8 * 3600);
            }
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }

        return $listCallers;
    }

    /*
    * get services from itop
    *
    * $param {array} $data selected organization and ITOP_SERVICE_TYPE group data
    *
    * @return {array} $listServices list of services
    *
    * throw \Exception if we can't get services data
    */
    public function getServices($data)
    {
        $key = 'SELECT Service';

        if (preg_match('/(.*?)___(.*)/', $data['organization_value'], $matches)) {
            $key .= " WHERE org_id='" . $matches[1] . "'";
        } else {
            throw new Exception('No organization found', 1);
        }

        $filter = $data['groups']['itop_service']['filter'];
        if (isset($filter) && $filter != '') {
            $key .= " AND friendlyname LIKE '%" . $filter . "%'";
        }

        $data = ['operation' => 'core/get', 'class' => 'Service', 'key' => $key, 'output_fields' => 'friendlyname'];

        try {
            $listServices = $this->getCache('itop_service_' . $matches[1]);
            if (is_null($listServices)) {
                // if no callers were found in cache, get them from itop and put them in cache for 8 hours
                $listServices = $this->curlQuery($data);
                $this->setCache('itop_service_' . $matches[1], $listServices, 8 * 3600);
            }
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }

        return $listServices;
    }

    /*
    * get service subcategories from itop
    *
    * $param {array} $data selected service and ITOP_SERVICE_SUBCATEGORY_TYPE group data
    *
    * @return {array} $listServiceSubcategories list of service subcategories
    *
    * throw \Exception if we can't get service subcategories data
    */
    public function getServiceSubcategories($data)
    {
        $key = 'SELECT ServiceSubcategory';

        if (preg_match('/(.*?)___(.*)/', $data['service_value'], $matches)) {
            $key .= " WHERE service_id='" . $matches[1] . "'";
        } else {
            throw new Exception('No service found', 1);
        }

        $filter = $data['groups']['itop_service_subcategory']['filter'];
        if (isset($filter) && $filter != '') {
            $key .= " AND friendlyname LIKE '%" . $filter . "%'";
        }

        $data = ['operation' => 'core/get', 'class' => 'ServiceSubcategory', 'key' => $key, 'output_fields' => 'friendlyname'];

        try {
            $listServiceSubcategories = $this->getCache('itop_service_subcategory_' . $matches[1]);
            if (is_null($listServiceSubcategories)) {
                // if no callers were found in cache, get them from itop and put them in cache for 8 hours
                $listServiceSubcategories = $this->curlQuery($data);
                $this->setCache('itop_service_subcategory_' . $matches[1], $listServiceSubcategories, 8 * 3600);
            }
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }

        return $listServiceSubcategories;
    }

    /*
    * check if the close option is enabled, if so, try to close every selected ticket
    *
    * @param {array} $tickets
    *
    * @return void
    */
    public function closeTicket(&$tickets): void
    {
        if ($this->doCloseTicket()) {
            foreach ($tickets as $k => $v) {
                try {
                    $this->closeTicketItop($k);
                    $tickets[$k]['status'] = 2;
                } catch (Exception $e) {
                    $tickets[$k]['status'] = -1;
                    $tickets[$k]['msg_error'] = $e->getMessage();
                }
            }
        } else {
            parent::closeTicket($tickets);
        }
    }

    // Set default values for our rule form options
    protected function setDefaultValueExtra()
    {
        $this->default_data['address'] = '10.30.2.22/itop/web';
        $this->default_data['api_version'] = '1.4';
        $this->default_data['username'] = '';
        $this->default_data['password'] = '';
        $this->default_data['protocol'] = 'https';
        $this->default_data['timeout'] = 60;

        $this->default_data['clones']['mappingTicket'] = [['Arg' => self::ARG_CONTENT, 'Value' => '{$body}'], ['Arg' => self::ARG_TITLE, 'Value' => 'Issue {include file="file:$centreon_open_tickets_path/providers'
            . '/Abstract/templates/display_title.ihtml"}'], ['Arg' => self::ARG_ORGANIZATION, 'Value' => '{$select.itop_organization.id}'], ['Arg' => self::ARG_CALLER, 'Value' => '{$select.itop_caller.id}'], ['Arg' => self::ARG_ORIGIN, 'Value' => '{$select.itop_origin.value}'], ['Arg' => self::ARG_SERVICE, 'Value' => '{$select.itop_service.id}'], ['Arg' => self::ARG_SERVICE_SUBCATEGORY, 'Value' => '{$select.itop_service_subcategory.id}'], ['Arg' => self::ARG_IMPACT, 'Value' => '{$select.itop_impact.value}'], ['Arg' => self::ARG_URGENCY, 'Value' => '{$select.itop_urgency.value}']];
    }

    /*
    * Set default values for the widget popup when opening a ticket
    *
    * @return void
    */
    protected function setDefaultValueMain($body_html = 0)
    {
        parent::setDefaultValueMain($body_html = 0);

        $this->default_data['url'] = '{$protocol}://{$address}/pages/UI.php?operation=details'
            . '&class=UserRequest&id={$ticket_id}';

        $this->default_data['format_popup'] = '
<table class="table">
<tr>
    <td class="FormHeader" colspan="2"><h3 style="color: #00bfb3;">{$title}</h3></td>
</tr>
<tr>
    <td class="FormRowField" style="padding-left:15px;">{$custom_message.label}</td>
    <td class="FormRowValue" style="padding-left:15px;">
        <textarea id="custom_message" name="custom_message" cols="50" rows="6"></textarea>
    </td>
</tr>
{include file="file:$centreon_open_tickets_path/providers/Abstract/templates/groups.ihtml"}
{include file="file:$centreon_open_tickets_path/providers/Itop/templates/format_popup_requiredFields.ihtml"}
</table>
';

        $this->default_data['clones']['groupList'] = [['Id' => 'itop_organization', 'Label' => _('Organization'), 'Type' => self::ITOP_ORGANIZATION_TYPE, 'Filter' => '', 'Mandatory' => ''], ['Id' => 'itop_caller', 'Label' => _('Caller'), 'Type' => self::ITOP_CALLER_TYPE, 'Filter' => '', 'Mandatory' => ''], ['Id' => 'itop_service', 'Label' => _('Service'), 'Type' => self::ITOP_SERVICE_TYPE, 'Filter' => '', 'Mandatory' => ''], ['Id' => 'itop_service_subcategory', 'Label' => _('Service Subcategory'), 'Type' => self::ITOP_SERVICE_SUBCATEGORY_TYPE, 'Filter' => '', 'Mandatory' => ''], ['Id' => 'itop_origin', 'Label' => _('Origin'), 'Type' => self::CUSTOM_TYPE, 'Filter' => '', 'Mandatory' => ''], ['Id' => 'itop_urgency', 'Label' => _('Urgency'), 'Type' => self::CUSTOM_TYPE, 'Filter' => '', 'Mandatory' => ''], ['Id' => 'itop_impact', 'Label' => _('Impact'), 'Type' => self::CUSTOM_TYPE, 'Filter' => '', 'Mandatory' => '']];

        $this->default_data['clones']['customList'] = [['Id' => 'itop_origin', 'Value' => 'mail', 'Label' => 'email', 'Default' => ''], ['Id' => 'itop_origin', 'Value' => 'monitoring', 'Label' => 'monitoring', 'Default' => ''], ['Id' => 'itop_origin', 'Value' => 'phone', 'Label' => 'phone', 'Default' => ''], ['Id' => 'itop_origin', 'Value' => 'portal', 'Label' => 'portal', 'Default' => ''], ['Id' => 'itop_origin', 'Value' => 'mail', 'Label' => 'email', 'Default' => ''], ['Id' => 'itop_impact', 'Value' => '1', 'Label' => 'A department', 'Default' => ''], ['Id' => 'itop_impact', 'Value' => '2', 'Label' => 'A service', 'Default' => ''], ['Id' => 'itop_impact', 'Value' => '3', 'Label' => 'A person', 'Default' => ''], ['Id' => 'itop_urgency', 'Value' => '1', 'Label' => 'critical', 'Default' => ''], ['Id' => 'itop_urgency', 'Value' => '2', 'Label' => 'high', 'Default' => ''], ['Id' => 'itop_urgency', 'Value' => '3', 'Label' => 'medium', 'Default' => ''], ['Id' => 'itop_urgency', 'Value' => '4', 'Label' => 'low', 'Default' => '']];
    }

    /*
    * Verify if every mandatory form field is filled with data
    *
    * @throw \Exception when a form field is not set
    */
    protected function checkConfigForm()
    {
        $this->check_error_message = '';
        $this->check_error_message_append = '';

        $this->checkFormValue('address', 'Please set the "Address" value');
        $this->checkFormValue('api_version', 'Please set the "API version" value');
        $this->checkFormValue('username', 'Please set the "Username" value');
        $this->checkFormValue('password', 'Please set the "Password" value');
        $this->checkFormValue('protocol', 'Please set the "Protocol" value');
        $this->checkFormInteger('timeout', '"Timeout" must be an integer');

        $this->checkLists();

        if ($this->check_error_message != '') {
            throw new Exception($this->check_error_message);
        }
    }

    // Initiate your html configuration and lets Smarty display it in the rule form
    protected function getConfigContainer1Extra()
    {
        // Smarty template initialization
        $tpl = SmartyBC::createSmartyTemplate($this->centreon_open_tickets_path, 'providers/Itop/templates');

        $tpl->assign('centreon_open_tickets_path', $this->centreon_open_tickets_path);
        $tpl->assign('img_brick', './modules/centreon-open-tickets/images/brick.png');
        $tpl->assign('header', ['Itop' => _('Itop Rest Api')]);
        $tpl->assign('webServiceUrl', './api/internal.php');

        // we create the html that is going to be displayed
        $address_html = '<input size="50" name="address" type="text" value="'
            . $this->getFormValue('address') . '" />';
        $username_html = '<input size="50" name="username" type="text" value="'
            . $this->getFormValue('username') . '" />';
        $password_html = '<input size="50" name="password" type="password" value="'
            . $this->getFormValue('password') . '" />';
        $api_version_html = '<input size="50" name="api_version" type="text" value ="'
            . $this->getFormValue('api_version') . '" />';
        $protocol_html = '<input size="2" name="protocol" type="text" value="'
            . $this->getFormValue('protocol') . '" />';
        $timeout_html = '<input size="2" name="timeout" type="text" value="'
            . $this->getFormValue('timeout') . '" />';

        // this array is here to link a label with the html code that we've wrote above
        $array_form = ['address' => ['label' => _('Address') . $this->required_field, 'html' => $address_html], 'username' => ['label' => _('Username') . $this->required_field, 'html' => $username_html], 'password' => ['label' => _('Password') . $this->required_field, 'html' => $password_html], 'api_version' => ['label' => _('API version') . $this->required_field, 'html' => $api_version_html], 'protocol' => ['label' => _('Protocol'), 'html' => $protocol_html], 'timeout' => ['label' => _('Timeout'), 'html' => $timeout_html], 'mappingticket' => ['label' => _('Mapping ticket arguments')]];

        // html code for a dropdown list where we will be able to select something from the following list
        $mappingTicketValue_html = '<input id="mappingTicketValue_#index#" '
            . 'name="mappingTicketValue[#index#]" size="20" type="text" />';
        $mappingTicketArg_html = '<select id="mappingTicketArg_#index#" '
            . 'name="mappingTicketArg[#index#]" type="select-one">'
            . '<option value="' . self::ARG_CONTENT . '">' . _('Content') . '</options>'
            . '<option value="' . self::ARG_TITLE . '">' . _('Title') . '</options>'
            . '<option value="' . self::ARG_ORGANIZATION . '">' . _('Organization') . '</options>'
            . '<option value="' . self::ARG_SERVICE . '">' . _('Service') . '</options>'
            . '<option value="' . self::ARG_SERVICE_SUBCATEGORY . '">' . _('Service Subcategory') . '</options>'
            . '<option value="' . self::ARG_ORIGIN . '">' . _('Origin') . '</options>'
            . '<option value="' . self::ARG_IMPACT . '">' . _('Impact') . '</options>'
            . '<option value="' . self::ARG_URGENCY . '">' . _('Urgency') . '</options>'
            . '<option value="' . self::ARG_CALLER . '">' . _('Caller') . '</options>'
            . '</select>';

        $array_form['mappingTicket'] = [['label' => _('Argument'), 'html' => $mappingTicketArg_html], ['label' => _('Value'), 'html' => $mappingTicketValue_html]];

        $tpl->assign('form', $array_form);
        $this->config['container1_html'] .= $tpl->fetch('conf_container1extra.ihtml');
        $this->config['clones']['mappingTicket'] = $this->getCloneValue('mappingTicket');
    }

    protected function getConfigContainer2Extra()
    {
    }

    // Saves the rule form in the database
    protected function saveConfigExtra()
    {
        $this->save_config['simple']['address'] = $this->submitted_config['address'];
        $this->save_config['simple']['username'] = $this->submitted_config['username'];
        $this->save_config['simple']['password'] = $this->submitted_config['password'];
        $this->save_config['simple']['api_version'] = $this->submitted_config['api_version'];
        $this->save_config['simple']['protocol'] = $this->submitted_config['protocol'];
        $this->save_config['simple']['timeout'] = $this->submitted_config['timeout'];
        $this->save_config['clones']['mappingTicket'] = $this->getCloneSubmitted(
            'mappingTicket',
            ['Arg', 'Value']
        );
    }

    /*
    * Adds new types to the list of types
    *
    * @return {string} $str html code that add an option to a select
    */
    protected function getGroupListOptions()
    {
        return '<option value="' . self::ITOP_SERVICE_TYPE . '">Service</option>'
            . '<option value="' . self::ITOP_CALLER_TYPE . '">Caller</option>'
            . '<option value="' . self::ITOP_ORGANIZATION_TYPE . '">Organization</option>'
            . '<option value="' . self::ITOP_SERVICE_SUBCATEGORY_TYPE . '">Service subcategory</option>';
    }

    /*
    * configure variables with the data provided by the itop api
    *
    * @param {array} $entry ticket argument configuration information
    * @param {array} $groups_order order of the ticket arguments
    * @param {array} $groups store the data gathered from itop
    *
    * @return void
    */
    protected function assignOthers($entry, &$groups_order, &$groups)
    {
        if ($entry['Type'] == self::ITOP_ORGANIZATION_TYPE) {
            $this->assignItopOrganizations($entry, $groups_order, $groups);
        } elseif (
            $entry['Type'] == self::ITOP_CALLER_TYPE
            || $entry['Type'] == self::ITOP_SERVICE_TYPE
            || $entry['Type'] == self::ITOP_SERVICE_SUBCATEGORY_TYPE
        ) {
            $this->assignItopAjax($entry, $groups_order, $groups);
        }
    }

    /*
    * handle gathered organizations
    *
    * @param {array} $entry ticket argument configuration information
    * @param {array} $groups_order order of the ticket arguments
    * @param {array} $groups store the data gathered from itop
    *
    * @return void
    *
    * throw \Exception if we can't get organizations from itop
    */
    protected function assignItopOrganizations($entry, &$groups_order, &$groups)
    {
        // add a label to our entry and activate sorting or not.
        $groups[$entry['Id']] = ['label' => _($entry['Label'])
            . (isset($entry['Mandatory']) && $entry['Mandatory'] == 1 ? $this->required_field : ''), 'sort' => (isset($entry['Sort']) && $entry['Sort'] == 1 ? 1 : 0)];

        $groups_order[] = $entry['Id'];

        try {
            $listOrganizations = $this->getCache($entry['Id']);
            if (is_null($listOrganizations)) {
                // if no organizations were found in cache, get them from itop and put them in cache for 8 hours
                $listOrganizations = $this->getOrganizations();
                $this->setCache($entry['Id'], $listOrganizations, 8 * 3600);
            }
        } catch (Exception $e) {
            $groups[$entry['Id']]['code'] = -1;
            $groups[$entry['Id']]['msg_error'] = $e->getMessage();
        }
        $result = [];

        foreach ($listOrganizations['objects'] ?? [] as $organization) {
            // foreach organization found, if we don't have any filter configured,
            // we just put the id and the name of the organization inside the result array
            if (! isset($entry['Filter']) || is_null($entry['Filter']) || $entry['Filter'] == '') {
                $result[$organization['key']] = $this->to_utf8($organization['fields']['name']);
                continue;
            }

            // if we do have have a filter, we make sure that the match the filter, if so, we put the name and the id
            // of the organization inside the result array
            if (preg_match('/' . $entry['Filter'] . '/', $organization['fields']['name'])) {
                $result[$organization['key']] = $this->to_utf8($organization['fields']['name']);
            }
        }

        $groups[$entry['Id']]['values'] = $result;
    }

    /*
    * initiate information for dynamic (ajax) fields like callers, services or service subcategories
    *
    * @param {array} $entry ticket argument configuration information
    * @param {array} $groups_order order of the ticket arguments
    * @param {array} $groups store the data gathered from itop
    *
    * @return void
    */
    protected function assignItopAjax($entry, &$groups_order, &$groups)
    {
        // add a label to our entry and activate sorting or not.
        $groups[$entry['Id']] = ['label' => _($entry['Label'])
            . (isset($entry['Mandatory']) && $entry['Mandatory'] == 1 ? $this->required_field : ''), 'sort' => (isset($entry['Sort']) && $entry['Sort'] == 1 ? 1 : 0), 'filter' => $entry['Filter']];

        $groups_order[] = $entry['Id'];

        $groups[$entry['Id']]['values'] = '';
    }

    /*
    * brings all parameters together in order to build the ticket arguments and save
    * ticket data in the database
    *
    * @param {object} $db_storage centreon storage database informations
    * @param {array} $contact centreon contact informations
    * @param {array} $host_problems centreon host information
    * @param {array} $service_problems centreon service information
    * @param {array} $extraTicketArguments
    *
    * @return {array} $result will tell us if the submit ticket action resulted in a ticket being opened
    */
    protected function doSubmit($db_storage, $contact, $host_problems, $service_problems, $extraTicketArguments = [])
    {
        // initiate a result array
        $result = ['ticket_id' => null, 'ticket_error_message' => null, 'ticket_is_ok' => 0, 'ticket_time' => time()];
        $tpl = $this->initSmartyTemplate();
        $tpl->assign('centreon_open_tickets_path', $this->centreon_open_tickets_path);
        $tpl->assign('user', $contact);
        $tpl->assign('host_selected', $host_problems);
        $tpl->assign('service_selected', $service_problems);
        // assign submitted values from the widget to the template
        $this->assignSubmittedValues($tpl);
        $ticketArguments = $extraTicketArguments;

        if (isset($this->rule_data['clones']['mappingTicket'])) {
            // for each ticket argument in the rule form, we retrieve its value
            foreach ($this->rule_data['clones']['mappingTicket'] as $value) {
                $tpl->assign('string', $value['Value']);
                $resultString = $tpl->fetch('eval.ihtml');
                if ($resultString == '') {
                    $resultstring = null;
                }
                $ticketArguments[$this->internal_arg_name[$value['Arg']]] = $resultString;
            }
        }
        // we try to open the ticket
        try {
            $ticketId = $this->createTicket($ticketArguments);
        } catch (Exception $e) {
            $result['ticket_error_message'] = $e->getMessage();

            return $result;
        }
        // we save ticket data in our database
        $this->saveHistory($db_storage, $result, ['contact' => $contact, 'host_problems' => $host_problems, 'service_problems' => $service_problems, 'ticket_value' => $ticketId, 'subject' => $ticketArguments[self::ARG_TITLE], 'data_type' => self::DATA_TYPE_JSON, 'data' => json_encode($ticketArguments)]);

        return $result;
    }

    /*
    * handle every query that we need to do
    *
    * @param {array} $info required information to reach the itop api
    *
    * @return {array} $curlResult the json decoded data gathered from itop
    *
    * throw \Exception 10 if php-curl is not installed
    * throw \Exception 11 if itop api fails
    */
    protected function curlQuery($data)
    {
        // check if php curl is installed
        if (! extension_loaded('curl')) {
            throw new Exception("couldn't find php curl", 10);
        }

        $query = ['auth_user' => $this->getFormValue('username'), 'auth_pwd' => $this->getFormValue('password'), 'json_data' => json_encode($data)];

        $curl = curl_init();
        $apiAddress = $this->getFormValue('protocol') . '://' . $this->getFormValue('address')
        . '/webservices/rest.php?version=' . $this->getFormValue('api_version');
        // initiate our curl options
        curl_setopt($curl, CURLOPT_URL, $apiAddress);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($query));
        curl_setopt($curl, CURLOPT_TIMEOUT, $this->getFormValue('timeout'));

        // if proxy is set, we add it to curl
        if (
            $this->getFormValue('proxy_address') != ''
            && $this->getFormValue('proxy_port') != ''
        ) {
            curl_setopt(
                $curl,
                CURLOPT_PROXY,
                $this->getFormValue('proxy_address') . ':' . $this->getFormValue('proxy_port')
            );
            // if proxy authentication configuration is set, we add it to curl
            if (
                $this->getFormValue('proxy_username') != ''
                && $this->getFormValue('proxy_password') != ''
            ) {
                curl_setopt(
                    $curl,
                    CURLOPT_PROXYUSERPWD,
                    $this->getFormValue('proxy_username') . ':' . $this->getFormValue('proxy_password')
                );
            }
        }
        // execute curl and get status information
        $curlResult = json_decode(curl_exec($curl), true);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);

        if ($httpCode >= 400) {
            throw new Exception('ERROR: ' . $curlResult . ' || HTTP ERROR: ' . $httpCode, 11);
        }

        if ($curlResult['code'] !== 0) {
            throw new Exception($curlResult['message'], $curlResult['code']);
        }

        return $curlResult;
    }

    /*
    * get organizations from itop
    *
    * @return {array} $organizations list of organizations
    *
    * throw \Exception if we can't get organizations data
    */
    protected function getOrganizations()
    {
        $key = "SELECT Organization WHERE status='active'";

        $data = ['operation' => 'core/get', 'class' => 'Organization', 'key' => $key, 'output_fields' => 'name'];

        try {
            $organizations = $this->curlQuery($data);
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }

        return $organizations;
    }

    /**
     * @param array $ticketArguments
     * @return mixed
     */
    protected function createTicket($ticketArguments)
    {
        $data = ['operation' => 'core/create', 'class' => 'UserRequest', 'output_fields' => 'id', 'comment' => 'Opened from Centreon', 'fields' => ['description' => $ticketArguments['content'], 'title' => $ticketArguments['title']]];

        if (isset($ticketArguments['organization'])
            && $ticketArguments['organization'] != ''
            && $ticketArguments['organization'] != -1) {
            $data['fields']['org_id'] = $ticketArguments['organization'];
        }

        if (isset($ticketArguments['service'])
            && $ticketArguments['service'] != ''
            && $ticketArguments['service'] != -1) {
            $data['fields']['service_id'] = $ticketArguments['service'];
        }

        if (isset($ticketArguments['service_subcategory'])
            && $ticketArguments['service_subcategory'] != ''
            && $ticketArguments['service_subcategory'] != -1) {
            $data['fields']['servicesubcategory_id'] = $ticketArguments['service_subcategory'];
        }

        if (isset($ticketArguments['caller'])
            && $ticketArguments['caller'] != ''
            && $ticketArguments['caller'] != -1) {
            $data['fields']['caller_id'] = $ticketArguments['caller'];
        }

        if (isset($ticketArguments['urgency'])
            && $ticketArguments['urgency'] != '') {
            $data['fields']['urgency'] = $ticketArguments['urgency'];
        }

        if (isset($ticketArguments['origin'])
            && $ticketArguments['origin'] != '') {
            $data['fields']['origin'] = $ticketArguments['origin'];
        }

        if (isset($ticketArguments['impact'])
            && $ticketArguments['impact'] != '') {
            $data['fields']['impact'] = $ticketArguments['impact'];
        }
        $result = $this->curlQuery($data);

        foreach ($result['objects'] as $ticket) {
            $ticketId = $ticket['fields']['id'];
        }

        return $ticketId ?? null;
    }

    /*
    * close a ticket in Itop
    *
    * @params {string} $ticketId the ticket id
    *
    * @return {bool}
    *
    * throw \Exception if it can't close the ticket
    */
    protected function closeTicketItop($ticketId)
    {

        $data = ['operation' => 'core/update', 'class' => 'UserRequest', 'comment' => 'Closing ticket from Centreon', 'key' => $ticketId, 'fields' => ['status' => 'closed']];

        try {
            $result = $this->curlQuery($data);
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }

        return 0;
    }
}
