<?php
/**
 * i-doit - Documentation and CMDB solution for IT environments
 *
 * This file is part of the i-doit framework. Modify at your own risk.
 *
 * Please visit http://www.i-doit.com/license for a full copyright and license information.
 *
 * @version     1.10
 * @package     i-doit
 * @author      synetics GmbH
 * @copyright   synetics GmbH
 * @url         http://www.i-doit.com
 * @license     http://www.i-doit.com/license
 */
namespace idoit\Module\Cmdb\Model\Summary;

use idoit\Component\Provider\DiInjectable;
use idoit\Component\Provider\Singleton;
use idoit\Module\Cmdb\Model\Ci\Lists\ConfigurationSignals;
use isys_application;
use isys_cmdb_dao_category;
use isys_component_signalcollection as SignalCollection;

/**
 * i-doit
 *
 * Signal manager for search index signals
 *
 * @package     i-doit
 * @subpackage  Cmdb
 * @author      Dennis Stücken <dstuecken@i-doit.com>
 * @version     1.7
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 */
class SummarySignals
{
    use Singleton, DiInjectable;

    /**
     * @var ObjectTypeSummary
     */
    private $objectTypeSummary;

    /**
     * @var GlobalCategorySummary
     */
    private $globalCategorySummary;

    /**
     * @var SpecificCategorySummary
     */
    private $specificCategorySummary;

    /**
     * @var ConfigurationSignals
     */
    private $listConfigurationSignals;

    /**
     * Summary default signals
     *
     * @var array
     */
    private $summarySignals = [
        'mod.cmdb.afterObjectTypeCreated'   => 'onAfterObjectTypeCreated',
        'mod.cmdb.afterObjectTypeDeleted'   => 'onAfterObjectTypeDeleted',
        'mod.cmdb.afterCategoryEntrySave'   => 'onAfterCategoryEntrySave',
        'mod.cmdb.beforeCategoryEntrySave'  => 'beforeCategoryEntrySave',
        'mod.cmdb.objectDeleted'            => 'onObjectDeleted',
        'mod.cmdb.beforeRankRecord'         => 'onBeforeRankRecord',
        'mod.cmdb.beforeObjectStatusChange' => 'onBeforeObjectStatusChanged',
        'mod.cmdb.afterLegacyImport'        => 'onPostImport'
    ];

    /**
     * Initialize summary for a new object type
     *
     * @param $objTypeID
     * @param $title
     * @param $const
     * @param $cats
     * @param $selfdefined
     * @param $container
     * @param $img_name
     * @param $icon
     * @param $sort
     * @param $status
     * @param $sysid_prefix
     * @param $show_in_tree
     */
    public function onAfterObjectTypeCreated($objTypeID, $title, $const, $cats, $selfdefined, $container, $img_name, $icon, $sort, $status, $sysid_prefix, $show_in_tree)
    {
        $this->objectTypeSummary->objectTypeCreated($objTypeID);
    }

    /**
     * @param $objTypeID
     * @param $objTypeRow
     */
    public function onAfterObjectTypeDeleted($objTypeID, $objTypeRow)
    {
        $this->objectTypeSummary->objectTypeDeleted($objTypeID);
    }

    /**
     * Update summary count for possibly changed object status
     *
     * @param \isys_cmdb_dao_category $dao
     * @param                         $categoryID
     * @param                         $objectID
     * @param                         $posts
     * @param                         $changes
     */
    public function onBeforeCategoryEntrySave(\isys_cmdb_dao_category $dao, $categoryID, $objectID, $posts, $changes)
    {
        if ($dao->get_category_type() == C__CMDB__CATEGORY__TYPE_GLOBAL && $dao->get_category_id() == C__CATG__GLOBAL)
        {
            $this->objectTypeSummary->objectStatusChanged($objectID, $posts['C__OBJ__STATUS']);
        }
    }

    /**
     * Update summary counts for categories
     *
     * @param \isys_cmdb_dao_category $dao
     * @param                         $categoryID
     * @param                         $saveSuccess
     * @param                         $objectID
     * @param                         $posts
     * @param                         $changes
     */
    public function onAfterCategoryEntrySave(\isys_cmdb_dao_category $dao, $categoryID, $saveSuccess, $objectID, $posts, $changes)
    {
        if ($dao->get_category_type() == C__CMDB__CATEGORY__TYPE_GLOBAL)
        {
            $this->globalCategorySummary->summarize(
                $objectID,
                $dao->get_category_id()
            );
        }
        else
        {
            if ($dao->get_category_type() == C__CMDB__CATEGORY__TYPE_SPECIFIC)
            {
                $this->specificCategorySummary->summarize(
                    $objectID,
                    $dao->get_category_id()
                );
            }
        }
    }

    /**
     * @param int   $importStartTime
     * @param array $importedGlobalCategories
     * @param array $importedSpecifcCategories
     */
    public function onPostImport($importStartTime, $importedGlobalCategories = null, $importedSpecifcCategories = null /*, $importType = '', $rawData = []*/)
    {
        if ($importStartTime > 0)
        {
            $changedObjects = $l_changed_object_types = [];
            $l_objects              = \isys_cmdb_dao_nexgen::instance(\isys_application::instance()->database)
                ->get_objects(
                    [
                        'changed_after' => date(
                            'Y-m-d H:i:s',
                            $importStartTime - 180
                        )
                    ]
                );

            while ($l_row = $l_objects->get_row())
            {
                $l_changed_object_types[$l_row['isys_obj__isys_obj_type__id']] = true;
                if (!in_array($l_row['isys_obj__isys_obj_type__id'], [C__OBJTYPE__RELATION, C__OBJTYPE__PARALLEL_RELATION]))
                {
                    $changedObjects[] = $l_row['isys_obj__id'];
                } // if
            }

            foreach ($l_changed_object_types as $objectTypeId)
            {
                $this->objectTypeSummary->summarize($objectTypeId, C__RECORD_STATUS__NORMAL);
                $this->objectTypeSummary->summarize($objectTypeId, C__RECORD_STATUS__ARCHIVED);
                $this->objectTypeSummary->summarize($objectTypeId, C__RECORD_STATUS__DELETED);
            }

            $globalCategorySummary = $this->globalCategorySummary;
            $specificCategorySummary = $this->specificCategorySummary;

            if (empty($importedGlobalCategories) && empty($importedSpecifcCategories))
            {
                return;
            }

            if (count($changedObjects))
            {
                foreach($changedObjects AS $objectID)
                {
                    if (is_array($importedGlobalCategories) && count($importedGlobalCategories))
                    {
                        foreach ($importedGlobalCategories AS $categoryID)
                        {
                            $globalCategorySummary->summarize($objectID, $categoryID);
                        } // foreach
                    } // if
                    if (is_array($importedSpecifcCategories) && count($importedSpecifcCategories))
                    {
                        foreach ($importedSpecifcCategories AS $categoryID)
                        {
                            $specificCategorySummary->summarize($objectID, $categoryID);
                        } // foreach
                    } // if
                } // foreach
            } // if
        }
    }

    /**
     * @param int            $objectID
     * @param \isys_cmdb_dao $dao
     */
    public function onObjectDeleted($objectID, $dao)
    {
        $this->objectTypeSummary->objectDeleted($objectID);
    }

    /**
     * @param int            $objectID
     * @param int            $status
     * @param bool           $result
     * @param \isys_cmdb_dao $dao
     */
    public function onBeforeObjectStatusChanged($objectID, $status, $result = null, $dao = null)
    {
        $this->objectTypeSummary->objectStatusChanged($objectID, $status);
    }

    /**
     * @param \isys_cmdb_dao_category $dao
     * @param                         $p_objectID
     */
    public function onBeforeRankRecord(\isys_cmdb_dao $dao, $objectID, $categoryID = null, $title, $row, $table, $currentStatus, $newStatus, $categoryType, $direction)
    {
        if($table == 'isys_obj')
        {
            if($newStatus !== C__RECORD_STATUS__PURGE)
            {
                $this->objectTypeSummary->objectStatusChanged($objectID, $newStatus);
            } // if
        }
        else if($currentStatus == C__RECORD_STATUS__NORMAL || $newStatus == C__RECORD_STATUS__NORMAL)
        {
            if($categoryType == C__CMDB__CATEGORY__TYPE_GLOBAL)
            {
                $catSummary = $this->globalCategorySummary;
            }
            else
            {
                $catSummary = $this->specificCategorySummary;
            } // if

            if($direction == C__CMDB__RANK__DIRECTION_DELETE)
            {
                $catSummary->decrement($catSummary->concat($objectID, $dao->get_category_id(), C__RECORD_STATUS__NORMAL));
            }
            else
            {
                $catSummary->increment($catSummary->concat($objectID, $dao->get_category_id(), C__RECORD_STATUS__NORMAL));
            }
        }
    }

    /**
     * Disconnect signal(s)
     *
     * @param array $p_signal
     *
     * @author   Van Quyen Hoang <qhoang@i-doit.com>
     */
    public function disconnect($p_signal = [])
    {
        $disconnectSignals = array_keys($this->summarySignals);
        if (count($p_signal))
        {
            $disconnectSignals = $p_signal;
        } // if

        foreach($disconnectSignals AS $signal)
        {
            if(!isset($this->summarySignals[$signal])) continue;

            SignalCollection::get_instance()->disconnect(
                $signal,
                [
                    $this,
                    $this->summarySignals[$signal]
                ]
            );
        } // foreach
    } // function

    /**
     * Connect all signals
     */
    public function connect()
    {
        $this->setDi(\isys_application::instance()->container);

        $this->globalCategorySummary   = new GlobalCategorySummary($this->getDi());
        $this->specificCategorySummary = new SpecificCategorySummary($this->getDi());
        $this->objectTypeSummary       = new ObjectTypeSummary($this->getDi());
        $this->listConfigurationSignals = new ConfigurationSignals();

        // Iterate through the default default signals
        foreach($this->summarySignals AS $signal => $method)
        {
            SignalCollection::get_instance()
                ->connect($signal,
                    [
                        $this,
                        $method
                    ]
                );
        } // foreach

        SignalCollection::get_instance()
            ->connect(
                'mod.cmdb.refreshTableConfigurations',
                [
                    $this->listConfigurationSignals,
                    'onRefreshTableConfigurations'
                ]
            );
    }
}
