Source of file Cmd.php

Size: 85,412 Bytes - Last Modified: 2020-10-24T02:46:31+00:00

/home/travis/build/NextDom/nextdom-core/src/Model/Entity/Cmd.php

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175
<?php
/* This file is part of NextDom Software.
 *
 * NextDom is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NextDom Software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NextDom Software. If not, see <http://www.gnu.org/licenses/>.
 */

namespace NextDom\Model\Entity;

use NextDom\Com\ComHttp;
use NextDom\Enums\ActionRight;
use NextDom\Enums\CacheKey;
use NextDom\Enums\CmdConfigKey;
use NextDom\Enums\CmdSubType;
use NextDom\Enums\CmdType;
use NextDom\Enums\CmdViewType;
use NextDom\Enums\Common;
use NextDom\Enums\ConfigKey;
use NextDom\Enums\DateFormat;
use NextDom\Enums\EqLogicStatus;
use NextDom\Enums\EventType;
use NextDom\Enums\LogTarget;
use NextDom\Enums\NextDomObj;
use NextDom\Exceptions\CoreException;
use NextDom\Helpers\Api;
use NextDom\Helpers\DBHelper;
use NextDom\Helpers\FileSystemHelper;
use NextDom\Helpers\LogHelper;
use NextDom\Helpers\NetworkHelper;
use NextDom\Helpers\NextDomHelper;
use NextDom\Helpers\TimeLineHelper;
use NextDom\Helpers\Utils;
use NextDom\Managers\CacheManager;
use NextDom\Managers\CmdManager;
use NextDom\Managers\ConfigManager;
use NextDom\Managers\CronManager;
use NextDom\Managers\DataStoreManager;
use NextDom\Managers\EqLogicManager;
use NextDom\Managers\EventManager;
use NextDom\Managers\HistoryManager;
use NextDom\Managers\InteractDefManager;
use NextDom\Managers\JeeObjectManager;
use NextDom\Managers\ListenerManager;
use NextDom\Managers\MessageManager;
use NextDom\Managers\PlanHeaderManager;
use NextDom\Managers\PluginManager;
use NextDom\Managers\ScenarioExpressionManager;
use NextDom\Managers\ScenarioManager;
use NextDom\Managers\ViewDataManager;
use NextDom\Managers\ViewManager;
use NextDom\Managers\WidgetManager;
use NextDom\Model\Entity\Parents\BaseEntity;
use NextDom\Model\Entity\Parents\ConfigurationEntity;
use NextDom\Model\Entity\Parents\DisplayEntity;
use NextDom\Model\Entity\Parents\IsVisibleEntity;
use NextDom\Model\Entity\Parents\LogicalIdEntity;
use NextDom\Model\Entity\Parents\NameEntity;
use NextDom\Model\Entity\Parents\OrderEntity;
use NextDom\Model\Entity\Parents\RefreshEntity;
use NextDom\Model\Entity\Parents\TypeEntity;

/**
 * Cmd
 *
 * ORM\Table(name="cmd", uniqueConstraints={
 *      ORM\UniqueConstraint(name="unique", columns={"eqLogic_id", "name"})}, indexes={
 *          ORM\Index(name="isHistorized", columns={"isHistorized"}),
 *          ORM\Index(name="type", columns={"type"}),
 *          ORM\Index(name="name", columns={"name"}),
 *          ORM\Index(name="subtype", columns={"subType"}),
 *          ORM\Index(name="eqLogic_id", columns={"eqLogic_id"}),
 *          ORM\Index(name="value", columns={"value"}),
 *          ORM\Index(name="order", columns={"order"}),
 *          ORM\Index(name="logicalID", columns={"logicalId"}),
 *          ORM\Index(name="logicalId_eqLogicID", columns={"eqLogic_id", "logicalId"}),
 *          ORM\Index(name="genericType_eqLogicID", columns={"eqLogic_id", "generic_type"})
 *      })
 * ORM\Entity
 */
class Cmd extends BaseEntity
{
    const TABLE_NAME = NextDomObj::CMD;

    use LogicalIdEntity, IsVisibleEntity, OrderEntity, RefreshEntity, TypeEntity;
    use NameEntity {
        setName as basicSetName;
    }
    use ConfigurationEntity {
        setConfiguration as basicSetConfiguration;
    }
    use DisplayEntity {
        setDisplay as basicSetDisplay;
    }

    private static $_templateArray = [];
    public $_collectDate = '';
    public $_valueDate = '';
    public $_eqLogic = null;
    public $_needRefreshWidget;
    public $_needRefreshAlert;

    /**
     * @var string
     *
     * @ORM\Column(name="eqType", type="string", length=127, nullable=true)
     */
    protected $eqType;

    /**
     * @var string
     *
     * @ORM\Column(name="generic_type", type="string", length=255, nullable=true)
     */
    protected $generic_type;

    /**
     * @var string
     *
     * @ORM\Column(name="template", type="text", length=65535, nullable=true)
     */
    protected $template;

    /**
     * @var string
     *
     * @ORM\Column(name="isHistorized", type="string", length=45, nullable=false)
     */
    protected $isHistorized = 0;

    /**
     * @var string
     *
     * @ORM\Column(name="subType", type="string", length=45, nullable=true)
     */
    protected $subType;

    /**
     * @var string
     *
     * @ORM\Column(name="unite", type="string", length=45, nullable=true)
     */
    protected $unite;

    /**
     * @var string
     *
     * @ORM\Column(name="value", type="string", length=255, nullable=true)
     */
    protected $value = null;

    /**
     * @var string
     *
     * @ORM\Column(name="html", type="text", length=16777215, nullable=true)
     */
    protected $html;

    /**
     * @var string
     *
     * @ORM\Column(name="alert", type="text", length=65535, nullable=true)
     */
    protected $alert;

    /**
     * @var EqLogic
     *
     * ORM\ManyToOne(targetEntity="NextDom\Model\Entity\Eqlogic")
     * ORM\JoinColumns({
     *   ORM\JoinColumn(name="eqLogic_id", referencedColumnName="id")
     * })
     */
    protected $eqLogic_id;

    /**
     * @param $_options
     * @throws CoreException
     * @throws \ReflectionException
     */
    public static function duringAlertLevel($_options)
    {
        $cmd = CmdManager::byId($_options[Common::CMD_ID]);
        if (!is_object($cmd)) {
            return;
        }
        if (!$cmd->isType(CmdType::INFO)) {
            return;
        }
        if (!is_object($cmd->getEqLogic()) || !$cmd->getEqLogic()->isEnabled()) {
            return;
        }
        $value = $cmd->execCmd();
        $level = $cmd->checkAlertLevel($value, false, $_options[Common::LEVEL]);
        if ($level != Common::NONE) {
            $cmd->actionAlertLevel($level, $value);
        }
    }

    /**
     * Test type of the command
     *
     * @param string $cmdType Type to test
     *
     * @return bool True on good type
     */
    public function isType(string $cmdType)
    {
        return $this->type === $cmdType;
    }

    /**
     * @return EqLogic
     * @throws \Exception
     */
    public function getEqLogic()
    {
        if ($this->_eqLogic == null) {
            $this->setEqLogic(EqLogicManager::byId($this->eqLogic_id));
        }
        return $this->_eqLogic;
    }

    /**
     * @param $_eqLogic
     * @return $this
     */
    public function setEqLogic($_eqLogic)
    {
        $this->_eqLogic = $_eqLogic;
        return $this;
    }

    /**
     *
     * @param mixed $_options
     * @param mixed $_sendNodeJsEvent
     * @param mixed $_quote
     * @return mixed result
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function execCmd($_options = null, $_sendNodeJsEvent = false, $_quote = false)
    {
        $result = null;
        if ($this->isType(CmdType::INFO)) {
            $state = $this->getCache([CacheKey::COLLECT_DATE, CacheKey::VALUE_DATE, CacheKey::VALUE]);
            if (isset($state[CacheKey::COLLECT_DATE])) {
                $this->setCollectDate($state[CacheKey::COLLECT_DATE]);
            } else {
                $this->setCollectDate(date(DateFormat::FULL));
            }
            if (isset($state[CacheKey::VALUE_DATE])) {
                $this->setValueDate($state[CacheKey::VALUE_DATE]);
            } else {
                $this->setValueDate($this->getCollectDate());
            }
            return $state[CacheKey::VALUE];
        }
        $eqLogic = $this->getEqLogicId();
        if (!is_object($eqLogic) || !$eqLogic->isEnabled()) {
            throw new CoreException(__('Equipement désactivé - impossible d\'exécuter la commande : ') . $this->getHumanName());
        }
        try {
            if ($_options !== null && $_options !== '') {
                $options = CmdManager::cmdToValue($_options);
                if (Utils::isJson($_options)) {
                    $options = json_decode($_options, true);
                }
            } else {
                $options = null;
            }
            if (isset($options[Common::COLOR])) {
                $options[Common::COLOR] = str_replace('"', '', $options[Common::COLOR]);
            }
            if ($this->isSubType(CmdSubType::COLOR) && isset($options[Common::COLOR]) && substr($options[Common::COLOR], 0, 1) != '#') {
                $options[Common::COLOR] = CmdManager::convertColor($options[Common::COLOR]);
            }
            $str_option = '';
            if (is_array($options) && ((count($options) > 1 && isset($options[Common::UID])) || count($options) > 0)) {
                LogHelper::addInfo(LogTarget::EVENT, __('Exécution de la commande ') . $this->getHumanName() . __(' avec les paramètres ') . json_encode($options, true));
            } else {
                LogHelper::addInfo(LogTarget::EVENT, __('Exécution de la commande ') . $this->getHumanName());
            }

            if ($this->getConfiguration(CmdConfigKey::TIMELIME_ENABLE)) {
                // @TODO: Problème Type et Subtype
                TimeLineHelper::addTimelineEvent([Common::TYPE => NextDomObj::CMD, Common::SUBTYPE => Common::ACTION, Common::ID => $this->getId(), Common::NAME => $this->getHumanName(true), Common::DATETIME => date(DateFormat::FULL), Common::OPTIONS => $str_option]);
            }
            $this->preExecCmd($options);
            $result = $this->formatValue($this->execute($options), $_quote);
            $this->postExecCmd($options);
        } catch (\Exception $e) {
            $eqTypeName = $eqLogic->getEqType_name();
            if ($eqLogic->getConfiguration(CmdConfigKey::NEVER_FAIL) != 1) {
                $numberTryWithoutSuccess = $eqLogic->getStatus(EqLogicStatus::NUMBER_TRY_WITHOUT_SUCCESS, 0);
                $eqLogic->setStatus(EqLogicStatus::NUMBER_TRY_WITHOUT_SUCCESS, $numberTryWithoutSuccess);
                if ($numberTryWithoutSuccess >= ConfigManager::byKey(EqLogicStatus::NUMBER_TRY_BEFORE_EQLOGIC_DISABLE)) {
                    $message = 'Désactivation de <a href="' . $eqLogic->getLinkToConfiguration() . '">' . $eqLogic->getName();
                    $message .= '</a> ' . __('car il n\'a pas répondu ou mal répondu lors des 3 derniers essais');
                    MessageManager::add($eqTypeName, $message);
                    $eqLogic->setIsEnable(0);
                    $eqLogic->save();
                }
            }
            LogHelper::addError($eqTypeName, __('Erreur exécution de la commande ') . $this->getHumanName() . ' : ' . $e->getMessage());
            throw $e;
        }
        if ($options !== null && $this->getValue() == '') {
            if (isset($options[CmdSubType::SLIDER])) {
                $this->setConfiguration(CmdConfigKey::LAST_CMD_VALUE, $options[CmdSubType::SLIDER]);
                $this->save();
            }
            if (isset($options[CmdSubType::COLOR])) {
                $this->setConfiguration(CmdConfigKey::LAST_CMD_VALUE, $options[CmdSubType::COLOR]);
                $this->save();
            }
        }
        if ($this->getConfiguration(CmdConfigKey::UPDATE_CMD_ID) != '') {
            $cmd = CmdManager::byId($this->getConfiguration(CmdConfigKey::UPDATE_CMD_ID));
            if (is_object($cmd)) {
                $result = $this->getConfiguration(ConfigKey::UPDATE_CMD_TO_VALUE);
                switch ($this->getSubType()) {
                    case CmdSubType::SLIDER:
                        $result = str_replace('#slider#', $options[CmdSubType::SLIDER], $result);
                        break;
                    case CmdSubType::COLOR:
                        $result = str_replace('#color#', $options[CmdSubType::COLOR], $result);
                        break;
                }
                $cmd->event($result);
            }
        }
        return $result;
    }

    /**
     * @param string $_key
     * @param string $_default
     * @return array|bool|mixed|null|string
     * @throws \Exception
     */
    public function getCache($_key = '', $_default = '')
    {
        $cache = CacheManager::byKey(CmdConfigKey::CMD_CACHE_ATTR . $this->getId())->getValue();
        return Utils::getJsonAttr($cache, $_key, $_default);
    }

    /**
     * @return string
     */
    public function getCollectDate()
    {
        return $this->_collectDate;
    }

    /**
     * @param $_collectDate
     * @return $this
     */
    public function setCollectDate($_collectDate)
    {
        $this->_collectDate = $_collectDate;
        return $this;
    }

    /**
     * @param bool $useTag
     * @param bool $prettify
     * @return string
     * @throws \Exception
     */
    public function getHumanName($useTag = false, $prettify = false)
    {
        $humanName = '';
        $eqLogic = $this->getEqLogicId();
        if (is_object($eqLogic)) {
            $humanName .= $eqLogic->getHumanName($useTag, $prettify);
        }
        if ($useTag) {
            $humanName .= ' - ' . $this->getName();
        } else {
            $humanName .= '[' . $this->getName() . ']';
        }
        return $humanName;
    }

    /**
     * @param $_name
     * @return $this
     */
    public function setName($name)
    {
        $name = Utils::cleanComponentName($name);
        return $this->basicSetName($name);
    }

    /**
     * Test sub type of the command
     *
     * @param string $cmdSubType Subype to test
     *
     * @return bool True on good type
     */
    public function isSubType(string $cmdSubType)
    {
        return $this->subType === $cmdSubType;
    }

    /**
     * Save configuration
     * @param $configKey
     * @param $configValue
     * @return $this
     */
    public function setConfiguration($configKey, $configValue)
    {
        if ($configKey == CmdConfigKey::ACTION_CODE_ACCESS && $configValue != ''
            && !Utils::isSha1($configValue) && !Utils::isSha512($configValue)) {
            $configValue = Utils::sha512($configValue);
        }
        return $this->basicSetConfiguration($configKey, $configValue);
    }

    /**
     * Execute before command execution
     *
     * @param array $_values
     *
     * @throws \Exception
     */
    public function preExecCmd($_values = [])
    {
        if (!is_array($this->getConfiguration(CmdConfigKey::NEXTDOM_PRE_EXEC_CMD)) || count($this->getConfiguration(CmdConfigKey::NEXTDOM_PRE_EXEC_CMD)) == 0) {
            return;
        }
        foreach ($this->getConfiguration(CmdConfigKey::NEXTDOM_PRE_EXEC_CMD) as $action) {
            try {
                $options = [];
                if (isset($action[Common::OPTIONS])) {
                    $options = $action[Common::OPTIONS];
                }
                if (is_array($_values) && count($_values) > 0) {
                    foreach ($_values as $key => $value) {
                        foreach ($options as &$option) {
                            if (!is_array($option)) {
                                $option = str_replace('#' . $key . '#', $value, $option);
                            }
                        }
                    }
                }
                ScenarioExpressionManager::createAndExec('action', $action[NextDomObj::CMD], $options);
            } catch (\Exception $e) {
                LogHelper::addError(LogTarget::CMD, __('Erreur lors de l\'exécution de ') . $action[NextDomObj::CMD] . __('. Sur preExec de la commande') . $this->getHumanName() . __('. Détails : ') . $e->getMessage());
            }
        }
    }

    /**
     * @param $_value
     * @param bool $_quote
     * @return float|mixed|string
     */
    public function formatValue($_value, $_quote = false)
    {
        if (is_array($_value)) {
            return '';
        }
        if (trim($_value) == '' && $_value !== false && $_value !== 0) {
            return '';
        }
        $_value = trim(trim($_value), '"');
        if (@strpos(strtolower($_value), 'error::') !== false) {
            return $_value;
        }
        if ($this->isType(CmdType::INFO)) {
            switch ($this->getSubType()) {
                case CmdSubType::OTHER:
                case CmdSubType::STRING:
                    if ($_quote) {
                        return '"' . $_value . '"';
                    }
                    return $_value;
                case CmdSubType::BINARY:
                    $calculValueOffset = $this->getConfiguration(CmdConfigKey::CALCUL_VALUE_OFFSET);
                    if ($calculValueOffset != '') {
                        try {
                            if (preg_match("/[a-zA-Z#]/", $_value)) {
                                $_value = NextDomHelper::evaluateExpression(str_replace('#value#', '"' . $_value . '"', str_replace('\'#value#\'', '#value#', str_replace('"#value#"', '#value#', $calculValueOffset))));
                            } else {
                                $_value = NextDomHelper::evaluateExpression(str_replace('#value#', $_value, $calculValueOffset));
                            }
                        } catch (\Exception $ex) {

                        }
                    }
                    $parsedBinary = strtolower($_value);
                    if ($parsedBinary == 'on' || $parsedBinary == 'high' || $parsedBinary == 'true' || $parsedBinary === true) {
                        return 1;
                    }
                    if ($parsedBinary == 'off' || $parsedBinary == 'low' || $parsedBinary == 'false' || $parsedBinary === false) {
                        return 0;
                    }
                    if ((is_numeric(intval($_value)) && intval($_value) > 1) || $_value === true || $_value == 1) {
                        return 1;
                    }
                    return 0;
                case CmdSubType::NUMERIC:
                    $_value = floatval(str_replace(',', '.', $_value));
                    $calculValueOffset = $this->getConfiguration(CmdConfigKey::CALCUL_VALUE_OFFSET);
                    if ($calculValueOffset != '') {
                        try {
                            if (preg_match("/[a-zA-Z#]/", $_value)) {
                                $_value = NextDomHelper::evaluateExpression(str_replace('#value#', '"' . $_value . '"', str_replace('\'#value#\'', '#value#', str_replace('"#value#"', '#value#', $calculValueOffset))));
                            } else {
                                $_value = NextDomHelper::evaluateExpression(str_replace('#value#', $_value, $calculValueOffset));
                            }
                        } catch (\Exception $ex) {

                        }
                    }
                    if ($this->getConfiguration(CmdConfigKey::HISTORIZE_ROUND) !== '' && is_numeric($this->getConfiguration(CmdConfigKey::HISTORIZE_ROUND)) && $this->getConfiguration(CmdConfigKey::HISTORIZE_ROUND) >= 0) {
                        $_value = round($_value, $this->getConfiguration(CmdConfigKey::HISTORIZE_ROUND));
                    }
                    if ($_value > $this->getConfiguration(CmdConfigKey::MAX_VALUE, $_value) && $this->getConfiguration(CmdConfigKey::MAX_VALUE_REPLACE) == 1) {
                        $_value = $this->getConfiguration(CmdConfigKey::MAX_VALUE, $_value);
                    }
                    if ($_value < $this->getConfiguration(CmdConfigKey::MIN_VALUE, $_value) && $this->getConfiguration(CmdConfigKey::MIN_VALUE_REPLACE) == 1) {
                        $_value = $this->getConfiguration(CmdConfigKey::MIN_VALUE, $_value);
                    }
                    return floatval($_value);
            }
        }
        return $_value;
    }

    /**
     * Execute command overrided by plugins
     *
     * @param array $options Execute options
     *
     * @return bool Always false if not overrided
     */
    public function execute($options = null)
    {
        return false;
    }

    /**
     * Executed after execution
     *
     * @param array $_values
     *
     * @throws \Exception
     */
    public function postExecCmd($_values = [])
    {
        if (!is_array($this->getConfiguration(CmdConfigKey::NEXTDOM_POST_EXEC_CMD))) {
            return;
        }
        foreach ($this->getConfiguration(CmdConfigKey::NEXTDOM_POST_EXEC_CMD) as $action) {
            try {
                $options = [];
                if (isset($action[Common::OPTIONS])) {
                    $options = $action[Common::OPTIONS];
                }
                if (count($_values) > 0) {
                    foreach ($_values as $key => $value) {
                        foreach ($options as &$option) {
                            if (!is_array($option)) {
                                $option = str_replace('#' . $key . '#', $value, $option);
                            }
                        }
                    }
                }
                ScenarioExpressionManager::createAndExec('action', $action[NextDomObj::CMD], $options);
            } catch (\Exception $e) {
                LogHelper::addError(NextDomObj::CMD, __('Erreur lors de l\'exécution de ') . $action[NextDomObj::CMD] . __('. Sur preExec de la commande') . $this->getHumanName() . __('. Détails : ') . $e->getMessage());
            }
        }
    }

    /**
     * @return string
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @param $_value
     * @return $this
     */
    public function setValue($_value)
    {
        $this->updateChangeState($this->value, $_value);
        $this->value = $_value;
        return $this;
    }

    /**
     * @return bool
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function save()
    {
        if (empty($this->getName())) {
            throw new CoreException(__('Le nom de la commande ne peut pas être vide :') . print_r($this, true));
        }
        if (empty($this->getType())) {
            throw new CoreException($this->getHumanName() . ' ' . __('Le type de la commande ne peut pas être vide :') . print_r($this, true));
        }
        if (empty($this->getSubType())) {
            throw new CoreException($this->getHumanName() . ' ' . __('Le sous-type de la commande ne peut pas être vide :') . print_r($this, true));
        }
        if (empty($this->getEqLogic_id())) {
            throw new CoreException($this->getHumanName() . ' ' . __('Vous ne pouvez pas créer une commande sans la rattacher à un équipement'));
        }
        if ($this->getConfiguration(CmdConfigKey::MAX_VALUE) != '' && $this->getConfiguration(CmdConfigKey::MIN_VALUE) != '' && $this->getConfiguration(CmdConfigKey::MIN_VALUE) > $this->getConfiguration(CmdConfigKey::MAX_VALUE)) {
            throw new CoreException($this->getHumanName() . ' ' . __('La valeur minimum de la commande ne peut etre supérieure à la valeur maximum'));
        }
        if ($this->getEqType() == '') {
            $this->setEqType($this->getEqLogicId()->getEqType_name());
        }
        if ($this->getDisplay(Common::GENERIC_TYPE) != '' && $this->getGeneric_type() == '') {
            $this->setGeneric_type($this->getDisplay(Common::GENERIC_TYPE));
            $this->setDisplay(Common::GENERIC_TYPE, null);
        }
        if ($this->isType(CmdType::ACTION) && $this->getIsHistorized() == 1) {
            $this->setIsHistorized(0);
        }
        DBHelper::save($this);
        if ($this->_needRefreshWidget) {
            $this->_needRefreshWidget = false;
            $this->getEqLogicId()->refreshWidget();
        }
        if ($this->_needRefreshAlert && $this->isType(CmdType::INFO)) {
            $execCmdValue = $this->execCmd();
            $level = $this->checkAlertLevel($execCmdValue);
            if ($level != $this->getCache(CacheKey::ALERT_LEVEL)) {
                $this->actionAlertLevel($level, $execCmdValue);
            }
        }
        return true;
    }

    /**
     *
     * @return mixed
     */
    public function getEqLogic_Id()
    {
        return $this->eqLogic_id;
    }

    /**
     * @return EqLogic|null
     * @throws \Exception
     */
    public function getEqLogicId()
    {
        if ($this->_eqLogic == null) {
            $this->setEqLogicId(EqLogicManager::byId($this->eqLogic_id));
        }
        return $this->_eqLogic;
    }

    /**
     *
     * @param $_eqLogic_id
     * @return $this
     */
    public function setEqLogic_id($_eqLogic_id)
    {
        $this->updateChangeState($this->eqLogic_id, $_eqLogic_id);
        $this->eqLogic_id = $_eqLogic_id;
        return $this;
    }

    /**
     * @param $_eqLogic
     * @return $this
     */
    public function setEqLogicId($_eqLogic)
    {
        $this->_eqLogic = $_eqLogic;
        return $this;
    }

    /**
     * @return string
     */
    public function getEqType()
    {
        return $this->eqType;
    }

    /**
     * @param $_eqType
     * @return $this
     */
    public function setEqType($_eqType)
    {
        $this->updateChangeState($this->eqType, $_eqType);
        $this->eqType = $_eqType;
        return $this;
    }

    /**
     * @param $_key
     * @param $_value
     * @return $this
     */
    public function setDisplay($_key, $_value)
    {
        if ($this->getDisplay($_key) != $_value) {
            $this->_needRefreshWidget = true;
            $this->_changed = true;
        }
        return $this->basicSetDisplay($_key, $_value);
    }

    /**
     * @return string
     */
    public function getGeneric_type()
    {
        return $this->generic_type;
    }

    /**
     * @param $generic_type
     * @return $this
     */
    public function setGeneric_type($generic_type)
    {
        $this->updateChangeState($this->generic_type, $generic_type);
        $this->generic_type = $generic_type;
        return $this;
    }

    /**
     * Get historic command status
     * @return bool
     */
    public function isHistorized()
    {
        return $this->isHistorized == 1;
    }

    /**
     * @return string
     */
    public function getIsHistorized()
    {
        return $this->isHistorized;
    }

    /**
     * @param $_isHistorized
     * @return $this
     */
    public function setIsHistorized($_isHistorized)
    {
        $this->updateChangeState($this->isHistorized, $_isHistorized);
        $this->isHistorized = $_isHistorized;
        return $this;
    }

    /**
     * @param $_value
     * @param bool $_allowDuring
     * @param string $_checkLevel
     * @return int|string
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function checkAlertLevel($_value, $_allowDuring = true, $_checkLevel = 'none')
    {
        if (!$this->isType(CmdType::INFO) || ($this->getAlert('warningif') == '' && $this->getAlert('dangerif') == '')) {
            return 'none';
        }
        global $NEXTDOM_INTERNAL_CONFIG;
        $returnLevel = 'none';
        foreach ($NEXTDOM_INTERNAL_CONFIG['alerts'] as $level => $value) {
            if ($this->getAlert($level . 'if') != '') {
                $check = NextDomHelper::evaluateExpression(str_replace('#value#', $_value, $this->getAlert($level . 'if')));
                if ($check == 1 || $check || $check == '1') {
                    $currentLevel = $level;
                    if ($_allowDuring && $currentLevel != 'none' && $this->getAlert($currentLevel . 'during') != '' && $this->getAlert($currentLevel . 'during') > 0) {
                        $cron = CronManager::byClassAndFunction(NextDomObj::CMD, 'duringAlertLevel', [Common::CMD_ID => intval($this->getId()), 'level' => $currentLevel]);
                        $next = strtotime('+ ' . $this->getAlert($currentLevel . 'during', 1) . ' minutes ' . date(DateFormat::FULL));
                        if ($currentLevel != $this->getCache('alertLevel')) {
                            if (!is_object($cron)) {
                                if (!($currentLevel == 'warning' && $this->getCache('alertLevel') == 'danger')) {
                                    $cron = new Cron();
                                    $cron->setClass(NextDomObj::CMD);
                                    $cron->setFunction('duringAlertLevel');
                                    $cron->setOnce(1);
                                    $cron->setOption([Common::CMD_ID => intval($this->getId()), 'level' => $currentLevel]);
                                    $cron->setSchedule(CronManager::convertDateToCron($next));
                                    $cron->setLastRun(date(DateFormat::FULL));
                                    $cron->save();
                                } else { //je suis en condition de warning et le cron n'existe pas mais j'etais en danger, je suppose que le cron a expiré
                                    $returnLevel = $currentLevel;
                                }
                            }
                        } else { // il n'y a pas de cron mais j'etais deja dans ce niveau, j'y reste
                            $returnLevel = $this->getCache('alertLevel');
                        }
                    }
                    if (!($_allowDuring && $this->getAlert($currentLevel . 'during') != '' && $this->getAlert($currentLevel . 'during') > 0)) { //je suis en alerte sans delai ou en execution de cron
                        if ($_checkLevel == $currentLevel || $_checkLevel == 'none') { //si c'etait un cron, je ne teste que le niveau demandé
                            if (!($_checkLevel == 'warning' && $this->getCache('alertLevel') == 'danger')) {
                                $returnLevel = $currentLevel;
                            } else { // le cron me demande de passer en warning mais je suis deja en danger, je reste en danger
                                $returnLevel = $this->getCache('alertLevel');
                            }
                        }
                    }
                } else { // je ne suis pas dans la condition, je supprime le cron
                    $cron = CronManager::byClassAndFunction(NextDomObj::CMD, 'duringAlertLevel', [Common::CMD_ID => intval($this->getId()), 'level' => $level]);
                    if (is_object($cron)) {
                        $cron->remove(false);
                    }
                }
            }
        }
        return $returnLevel;
    }

    /**
     * @param string $_key
     * @param string $_default
     * @return array|bool|mixed|null|string
     */
    public function getAlert($_key = '', $_default = '')
    {
        return Utils::getJsonAttr($this->alert, $_key, $_default);
    }

    /**
     * @param $_key
     * @param $_value
     * @return $this
     */
    public function setAlert($_key, $_value)
    {
        $alert = Utils::setJsonAttr($this->alert, $_key, $_value);
        $this->updateChangeState($this->alert, $alert);
        $this->alert = $alert;
        $this->_needRefreshAlert = true;
        return $this;
    }

    /**
     * @param $_level
     * @param $_value
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function actionAlertLevel($_level, $_value)
    {
        if (!$this->isType(CmdType::INFO)) {
            return;
        }
        if ($_level == $this->getCache('alertLevel')) {
            return;
        }
        global $NEXTDOM_INTERNAL_CONFIG;
        $this->setCache('alertLevel', $_level);
        $eqLogic = $this->getEqLogic();
        if (!$eqLogic->isEnabled()) {
            return;
        }
        $maxAlert = $eqLogic->getMaxCmdAlert();
        $prevAlert = $eqLogic->getAlert();
        if (!$_value) {
            $_value = $this->execCmd();
        }
        if ($_level != 'none') {
            $message = __('Alert sur la commande ') . $this->getHumanName() . __(' niveau ') . $_level . __(' valeur : ') . $_value . trim(' ' . $this->getUnite());
            if ($this->getAlert($_level . 'during') != '' && $this->getAlert($_level . 'during') > 0) {
                $message .= ' ' . __('pendant plus de ') . $this->getAlert($_level . 'during') . __(' minute(s)');
            }
            $message .= ' => ' . NextDomHelper::toHumanReadable(str_replace('#value#', $_value, $this->getAlert($_level . 'if')));
            LogHelper::addInfo(LogTarget::EVENT, $message);
            $eqLogic = $this->getEqLogicId();
            if (ConfigManager::byKey('alert::addMessageOn' . ucfirst($_level)) == 1) {
                MessageManager::add($eqLogic->getEqType_name(), $message);
            }
            $cmds = explode(('&&'), ConfigManager::byKey('alert::' . $_level . 'Cmd'));
            if (count($cmds) > 0 && trim(ConfigManager::byKey('alert::' . $_level . 'Cmd')) != '') {
                foreach ($cmds as $id) {
                    $cmd = CmdManager::byId(str_replace('#', '', $id));
                    if (is_object($cmd)) {
                        $cmd->execCmd([
                            'title' => __('[' . ConfigManager::byKey(Common::NAME, 'core', 'NEXTDOM') . '] ') . $message,
                            'message' => ConfigManager::byKey(Common::NAME, 'core', 'NEXTDOM') . ' : ' . $message,
                        ]);
                    }
                }
            }
        }

        if ($prevAlert != $maxAlert) {
            $status = [
                'warning' => 0,
                'danger' => 0,
            ];
            if ($maxAlert != 'none' && isset($NEXTDOM_INTERNAL_CONFIG['alerts'][$maxAlert])) {
                $status[$maxAlert] = 1;
            }
            $eqLogic->setStatus($status);
            $eqLogic->refreshWidget();
        }
    }

    /**
     * @param $_key
     * @param null $_value
     * @return $this
     * @throws \Exception
     */
    public function setCache($_key, $_value = null)
    {
        CacheManager::set(CmdConfigKey::CMD_CACHE_ATTR . $this->getId(), Utils::setJsonAttr(CacheManager::byKey(CmdConfigKey::CMD_CACHE_ATTR . $this->getId())->getValue(), $_key, $_value));
        return $this;
    }

    /**
     * @return string
     */
    public function getUnite()
    {
        return $this->unite;
    }

    /**
     * @param $_unite
     * @return $this
     */
    public function setUnite($_unite)
    {
        $this->updateChangeState($this->unite, $_unite);
        $this->unite = $_unite;
        return $this;
    }

    /**
     * @param $eventValue
     * @param null $_datetime
     * @param int $eventLoop
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function event($eventValue, $_datetime = null, $eventLoop = 1)
    {
        if ($eventLoop > 4 || !$this->isType(CmdType::INFO)) {
            return;
        }
        $eqLogic = $this->getEqLogicId();
        if (!is_object($eqLogic) || $eqLogic->getIsEnable() == 0) {
            return;
        }
        $eventValue = $this->formatValue($eventValue);
        if ($this->isSubType(CmdSubType::NUMERIC) && ($eventValue > $this->getConfiguration(CmdConfigKey::MAX_VALUE, $eventValue) || $eventValue < $this->getConfiguration(CmdConfigKey::MIN_VALUE, $eventValue)) && strpos($eventValue, 'error') === false) {
            LogHelper::addInfo(LogTarget::CMD, __('La commande n\'est pas dans la plage de valeur autorisée : ') . $this->getHumanName() . ' => ' . $eventValue);
            return;
        }
        if ($this->getConfiguration(CmdConfigKey::DENY_VALUES) != '' && in_array($eventValue, explode(';', $this->getConfiguration(CmdConfigKey::DENY_VALUES)))) {
            return;
        }
        $oldValue = $this->execCmd();
        $repeat = ($oldValue == $eventValue && $oldValue !== '' && $oldValue !== null);
        $this->setCollectDate(($_datetime != null) ? $_datetime : date(DateFormat::FULL));
        $this->setCache(CacheKey::COLLECT_DATE, $this->getCollectDate());
        $this->setValueDate(($repeat) ? $this->getValueDate() : $this->getCollectDate());
        $eqLogic->setStatus([EqLogicStatus::LAST_COMMUNICATION => $this->getCollectDate(), Common::TIMEOUT => 0]);
        $display_value = $eventValue;
        if (method_exists($this, 'formatValueWidget')) {
            $display_value = $this->formatValueWidget($eventValue);
        } elseif ($this->isSubType(CmdSubType::BINARY) && $this->getDisplay(Common::INVERSE_BINARY) == 1) {
            $display_value = ($eventValue == 1) ? 0 : 1;
        } elseif ($this->isSubType(CmdSubType::NUMERIC) && trim($eventValue) == '') {
            $display_value = 0;
        } elseif ($this->isSubType(CmdSubType::BINARY) && trim($eventValue) == '') {
            $display_value = 0;
        }
        if ($repeat && $this->getConfiguration(CmdConfigKey::REPEAT_EVENT_MGMT, 'auto') == 'never') {
            $this->addHistoryValue($eventValue, $this->getCollectDate());
            $eqLogic->emptyCacheWidget();
            EventManager::adds(EventType::CMD_UPDATE, [[Common::CMD_ID => $this->getId(), Common::VALUE => $eventValue, Common::DISPLAY_VALUE => $display_value, CacheKey::VALUE_DATE => $this->getValueDate(), CacheKey::COLLECT_DATE => $this->getCollectDate()]]);
            return;
        }
        $eventLoop++;
        if ($repeat && ($this->getConfiguration(CmdConfigKey::REPEAT_EVENT_MGMT, Common::AUTO) == Common::ALWAYS || $this->isSubType(CmdSubType::BINARY))) {
            $repeat = false;
        }
        $message = __('Evènement sur la commande ') . $this->getHumanName() . __(' valeur : ') . $eventValue;
        if ($repeat) {
            $message .= ' (répétition)';
        }
        LogHelper::addInfo(LogTarget::EVENT, $message);
        $events = [];
        if (!$repeat) {
            $this->setCache([Common::VALUE => $eventValue, CacheKey::VALUE_DATE => $this->getValueDate()]);
            ScenarioManager::check($this);
            $eqLogic->emptyCacheWidget();
            $level = $this->checkAlertLevel($eventValue);
            $events[] = [Common::CMD_ID => $this->getId(), Common::VALUE => $eventValue, Common::DISPLAY_VALUE => $display_value, CacheKey::VALUE_DATE => $this->getValueDate(), CacheKey::COLLECT_DATE => $this->getCollectDate(), 'alertLevel' => $level];
            $foundInfo = false;
            $cmds = CmdManager::byValue($this->getId(), null, true);
            if (is_array($cmds) && count($cmds) > 0) {
                /** @var Cmd $cmd */
                foreach ($cmds as $cmd) {
                    if ($cmd->isType(CmdType::ACTION)) {
                        if (!$repeat) {
                            $events[] = [Common::CMD_ID => $cmd->getId(), Common::VALUE => $eventValue, Common::DISPLAY_VALUE => $display_value, CacheKey::VALUE_DATE => $this->getValueDate(), CacheKey::COLLECT_DATE => $this->getCollectDate()];
                        }
                    } else {
                        if ($eventLoop > 1) {
                            $cmd->event($cmd->execute(), null, $eventLoop);
                        } else {
                            $foundInfo = true;
                        }
                    }
                }
            }
            if ($foundInfo) {
                ListenerManager::backgroundCalculDependencyCmd($this->getId());
            }
        } else {
            $events[] = [Common::CMD_ID => $this->getId(), Common::VALUE => $eventValue, Common::DISPLAY_VALUE => $display_value, CacheKey::VALUE_DATE => $this->getValueDate(), CacheKey::COLLECT_DATE => $this->getCollectDate()];
        }
        if (count($events) > 0) {
            EventManager::adds(EventType::CMD_UPDATE, $events);
        }
        if (!$repeat) {
            ListenerManager::check($this->getId(), $eventValue, $this->getCollectDate());
            JeeObjectManager::checkSummaryUpdate($this->getId());
        }
        $this->addHistoryValue($eventValue, $this->getCollectDate());
        $this->checkReturnState($eventValue);
        if (!$repeat) {
            $this->checkCmdAlert($eventValue);
            if (isset($level) && $level != $this->getCache('alertLevel')) {
                $this->actionAlertLevel($level, $eventValue);
            }
            if ($this->getConfiguration(CmdConfigKey::TIMELIME_ENABLE)) {
                // @TODO: Il doit y avoir un problème avec les Types et SubType
                TimeLineHelper::addTimelineEvent(['type' => NextDomObj::CMD, 'subtype' => 'info', 'cmdType' => $this->getSubType(), Common::ID => $this->getId(), Common::NAME => $this->getHumanName(true), 'datetime' => $this->getValueDate(), Common::VALUE => $eventValue . $this->getUnite()]);
            }
            $this->influxDb($eventValue);
            $this->pushUrl($eventValue);
        }
    }

    /**
     * @return string
     */
    public function getValueDate()
    {
        return $this->_valueDate;
    }

    /**
     * @param $_valueDate
     * @return $this
     */
    public function setValueDate($_valueDate)
    {
        $this->_valueDate = $_valueDate;
        return $this;
    }

    /**
     * @param $_value
     * @param string $_datetime
     *
     * @throws CoreException
     */
    public function addHistoryValue($_value, $_datetime = '')
    {
        if ($this->getIsHistorized() == 1 && ($_value == null || ($_value !== '' && $this->isType(CmdType::INFO) && $_value <= $this->getConfiguration(CmdConfigKey::MAX_VALUE, $_value) && $_value >= $this->getConfiguration(CmdConfigKey::MIN_VALUE, $_value)))) {
            $history = new History();
            $history->setCmd_id($this->getId());
            $history->setValue($_value);
            $history->setDatetime($_datetime);
            $history->save($this);
        }
    }

    /**
     * @param $_value
     * @throws \Exception
     */
    public function checkReturnState($_value)
    {
        if (is_numeric($this->getConfiguration(CmdConfigKey::RETURN_STATE_TIME))
            && $this->getConfiguration(CmdConfigKey::RETURN_STATE_TIME) > 0
            && $_value != $this->getConfiguration(CmdConfigKey::RETURN_STATE_VALUE)
            && trim($this->getConfiguration(CmdConfigKey::RETURN_STATE_VALUE)) != '') {
            $cron = CronManager::byClassAndFunction(NextDomObj::CMD, 'returnState', [Common::CMD_ID => intval($this->getId())]);
            if (!is_object($cron)) {
                $cron = new cron();
            }
            $cron->setClass(NextDomObj::CMD);
            $cron->setFunction('returnState');
            $cron->setOnce(1);
            $cron->setOption([Common::CMD_ID => intval($this->getId())]);
            $next = strtotime('+ ' . ($this->getConfiguration(CmdConfigKey::RETURN_STATE_TIME) + 1) . ' minutes ' . date(DateFormat::FULL));
            $cron->setSchedule(CronManager::convertDateToCron($next));
            $cron->setLastRun(date(DateFormat::FULL));
            $cron->save();
        }
    }

    /**
     * @param $_value
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function checkCmdAlert($_value)
    {
        if ($this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_OPERATOR) == '' || $this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_TEST) == '' || is_nan($this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_TIME, 0))) {
            return;
        }
        $check = NextDomHelper::evaluateExpression($_value . $this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_OPERATOR) . $this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_TEST));
        if ($check == 1 || $check || $check == '1') {
            if ($this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_TIME, 0) == 0) {
                $this->executeAlertCmdAction();
                return;
            }
            $next = strtotime('+ ' . ($this->getConfiguration(CmdConfigKey::NEXTDOM_CHECK_CMD_TIME) + 1) . ' minutes ' . date(DateFormat::FULL));
            $cron = CronManager::byClassAndFunction(NextDomObj::CMD, 'cmdAlert', [Common::CMD_ID => intval($this->getId())]);
            if (!is_object($cron)) {
                $cron = new cron();
            } else {
                $nextRun = $cron->getNextRunDate();
                if ($nextRun !== false && $next > strtotime($nextRun) && strtotime($nextRun) > strtotime('now')) {
                    return;
                }
            }
            $cron->setClass(NextDomObj::CMD);
            $cron->setFunction('cmdAlert');
            $cron->setOnce(1);
            $cron->setOption([Common::CMD_ID => intval($this->getId())]);
            $cron->setSchedule(CronManager::convertDateToCron($next));
            $cron->setLastRun(date(DateFormat::FULL));
            $cron->save();
        } else {
            $cron = CronManager::byClassAndFunction(NextDomObj::CMD, 'cmdAlert', [Common::CMD_ID => intval($this->getId())]);
            if (is_object($cron)) {
                $cron->remove();
            }
        }
    }

    /**
     * @throws \Exception
     */
    public function executeAlertCmdAction()
    {
        if (!is_array($this->getConfiguration(CmdConfigKey::ACTION_CHECK_CMD))) {
            return;
        }
        foreach ($this->getConfiguration(CmdConfigKey::ACTION_CHECK_CMD) as $action) {
            try {
                $options = [];
                if (isset($action[Common::OPTIONS])) {
                    $options = $action[Common::OPTIONS];
                }
                ScenarioExpressionManager::createAndExec('action', $action[NextDomObj::CMD], $options);
            } catch (\Exception $e) {
                LogHelper::addError(NextDomObj::CMD, __('Erreur lors de l\'exécution de ') . $action[NextDomObj::CMD] . __('. Détails : ') . $e->getMessage());
            }
        }
    }

    /**
     * @param $_value
     * @throws \Exception
     */
    public function pushUrl($_value)
    {
        $url = $this->getConfiguration(CmdConfigKey::NEXTDOM_PUSH_URL);
        if ($url == '') {
            $url = ConfigManager::byKey(ConfigKey::CMD_PUSH_URL);
        }
        if ($url == '') {
            return;
        }
        $replace = [
            '#value#' => urlencode($_value),
            '#cmd_name#' => urlencode($this->getName()),
            '#cmd_id#' => $this->getId(),
            '#humanname#' => urlencode($this->getHumanName()),
            '#eq_name#' => urlencode($this->getEqLogicId()->getName()),
            '"' => ''
        ];
        $url = str_replace(array_keys($replace), $replace, $url);
        LogHelper::addInfo(LogTarget::EVENT, __('Appels de l\'URL de push pour la commande ') . $this->getHumanName() . ' : ' . $url);
        $http = new ComHttp($url);
        $http->setLogError(false);
        try {
            $http->exec();
        } catch (\Exception $e) {
            LogHelper::addError(NextDomObj::CMD, __('Erreur push sur : ') . $url . ' => ' . $e->getMessage());
        }
    }

    /**
     * @param $valueToSend
     * @throws \Exception
     */
    public function influxDb($valueToSend)
    {
        $influxDbConf = ConfigManager::byKeys(['influxDbIp', 'influxDbPort', 'influxDbDatabase', 'influxDbLogin', 'influxDbPassword']);
        if ($influxDbConf['influxDbIp'] !== '') {
            if (empty($this->getUnite())) {
                $unite = 'state';
            } else {
                $unite = $this->getUnite();
            }

            if ($this->isType(CmdType::INFO)
                && ($this->isSubType(CmdSubType::NUMERIC) || $this->isSubType(CmdSubType::BINARY))
                && (isset($valueToSend))) {
                $influxDbDatabase = \InfluxDB\Client::fromDSN(sprintf('influxdb://%s:%s@%s:%s/%s', urlencode($influxDbConf['influxDbLogin']), urlencode($influxDbConf['influxDbPassword']), $influxDbConf['influxDbIp'], $influxDbConf['influxDbPort'], $influxDbConf['influxDbDatabase']));

                $points = [
                    new \InfluxDB\Point(
                        $unite,
                        floatval($valueToSend),
                        ['equipment' => $this->getHumanName()]
                    ),
                ];

                $influxDbDatabase->writePoints($points);
            }
        }
    }

    /**
     * @return string
     */
    public function getEqType_name()
    {
        @trigger_error('This method is deprecated. Use getEqType', E_USER_DEPRECATED);
        return $this->eqType;
    }

    /**
     * @param $order
     * @return $this
     */
    public function setOrder($order)
    {
        if ($this->order != $order) {
            $this->_needRefreshWidget = true;
            $this->_changed = true;
        }
        $this->order = $order;
        return $this;
    }

    /**
     * @param $isVisible
     * @return $this
     */
    public function setIsVisible($isVisible)
    {
        if ($this->isVisible != $isVisible) {
            $this->_needRefreshWidget = true;
            $this->_changed = true;
        }
        $this->isVisible = $isVisible;
        return $this;
    }

    /**
     * @param string $_key
     * @param string $_default
     * @return array|bool|mixed|null|string
     */
    public function getHtml($_key = '', $_default = '')
    {
        return Utils::getJsonAttr($this->html, $_key, $_default);
    }

    /**
     * @param $_key
     * @param $_value
     * @return $this
     * @throws \Exception
     */
    public function setHtml($_key, $_value)
    {
        if (in_array($_key, [CmdViewType::DASHBOARD, CmdViewType::DVIEW, CmdViewType::MVIEW, CmdViewType::DPLAN]) && $this->getWidgetTemplateCode($_key, true) == $_value) {
            $_value = '';
        }
        if ($this->getHtml($_key) != $_value) {
            $this->_needRefreshWidget = true;
            $this->_changed = true;
        }
        $this->html = Utils::setJsonAttr($this->html, $_key, $_value);
        return $this;
    }

    /**
     * TODO: Déplacer dans CmdManager ???
     *
     * @param string $viewVersion
     * @param bool $_noCustom
     * @return array|bool|mixed|null|string
     * @throws \Exception
     */
    public function getWidgetTemplateCode($viewVersion = CmdViewType::DASHBOARD)
    {
        global $NEXTDOM_INTERNAL_CONFIG;
        $templateVersion = NextDomHelper::versionAlias($viewVersion);
        $replace = null;
        $widgetTemplate = $NEXTDOM_INTERNAL_CONFIG[NextDomObj::CMD][NextDomObj::WIDGET];
        $widgetName = $this->getTemplate($templateVersion, Common::DEFAULT);
        $templateNamePrefix = 'cmd.' . $this->getType() . '.' . $this->getSubType() . '.';
        if (strpos($this->getTemplate($templateVersion, Common::DEFAULT), '::') !== false) {
            $name = explode('::', $this->getTemplate($templateVersion, Common::DEFAULT));
            $templateType = $name[0];
            $widgetName = $name[1];
            switch ($templateType) {
                case Common::CUSTOM:
                    $widget = WidgetManager::byTypeSubtypeAndName($this->getType(), $this->getSubType(), $widgetName);
                    if (is_object($widget)) {
                        $widgetTemplate = [
                            $this->getType() => [
                                $this->getSubType() => [
                                    $widgetName => [
                                        Common::REPLACE => json_decode($widget->getReplace(), true),
                                        Common::TEST => json_decode($widget->getTest(), true),
                                        Common::TEMPLATE => $widget->getTemplate()
                                    ]
                                ]
                            ]
                        ];
                    }
                    break;
                case 'customtemp':
                    $file = __DIR__ . '/../../data/customTemplates/' . $templateVersion . '/' . $templateNamePrefix . $widgetName . '.html';
                    if (file_exists($file)) {
                        return file_get_contents($file);
                    }
                    break;
                case 'core':
                    if (method_exists($templateType, 'templateWidget')) {
                        $widgetTemplate = $templateType::templateWidget();
                    }
                    break;
            }
        }
        $templateName = $templateNamePrefix . $widgetName;
        if (isset($widgetTemplate[$this->getType()]) && isset($widgetTemplate[$this->getType()][$this->getSubType()]) && isset($widgetTemplate[$this->getType()][$this->getSubType()][$widgetName])) {
            $templateConf = $widgetTemplate[$this->getType()][$this->getSubType()][$widgetName];
            $templateName = $templateNamePrefix . $templateConf[Common::TEMPLATE];
            if (isset($templateConf[Common::REPLACE]) && is_array($templateConf[Common::REPLACE]) && count($templateConf[Common::REPLACE]) > 0) {
                $replace = $templateConf[Common::REPLACE];
                foreach ($replace as &$value) {
                    $value = str_replace('#value#', '"+_options.display_value+"', str_replace('"', "'", $value));
                }
            } else {
                $replace = [];
            }
            $replace['#test#'] = '';
            $replace['#change_theme#'] = '';
            if (isset($templateConf[Common::TEST]) && is_array($templateConf[Common::TEST]) && count($templateConf[Common::TEST]) > 0) {
                $i = 0;
                foreach ($templateConf[Common::TEST] as &$test) {
                    if (!isset($test['operation'])) {
                        continue;
                    }
                    if (!isset($test['state_light'])) {
                        $test['state_light'] = '';
                    }
                    if (!isset($test['state_dark'])) {
                        $test['state_dark'] = '';
                    }
                    $test['state_light'] = str_replace('#value#', '"+_options.display_value+"', str_replace('"', "'", $test['state_light']));
                    $test['state_dark'] = str_replace('#value#', '"+_options.display_value+"', str_replace('"', "'", $test['state_dark']));
                    $test['operation'] = str_replace('"', "'", str_replace('#value#', '_options.display_value', $test['operation']));
                    $replace['#test#'] .= 'if(' . $test['operation'] . '){cmd.attr("data-state",' . $i . ');state=nextdom.widget.getThemeImg("' . $test['state_light'] . '","' . $test['state_dark'] . '")}';
                    $replace['#change_theme#'] .= 'if(cmd.attr("data-state") == ' . $i . '){state=nextdom.widget.getThemeImg("' . $test['state_light'] . '","' . $test['state_dark'] . '")}';
                    $i++;
                }
            }
        }
        $templateCode = '';
        if (!isset(self::$_templateArray[$templateVersion . '::' . $templateName])) {
            $templateCode = FileSystemHelper::getCoreTemplateFileContent($templateVersion, $templateName);
            if (empty($templateCode)) {
                if (ConfigManager::byKey('active', 'widget') == 1) {
                    $templateCode = FileSystemHelper::getCoreTemplateFileContent($templateVersion, $templateName, 'widget');
                }
                if (empty($templateCode)) {
                    foreach (PluginManager::listPlugin(true) as $plugin) {
                        $templateCode = FileSystemHelper::getCoreTemplateFileContent($templateVersion, $templateName, $plugin->getId());
                        if (!empty($templateCode)) {
                            break;
                        }
                    }
                }
                if (empty($templateCode)) {
                    $templateName = $templateNamePrefix . 'default';
                    $templateCode = FileSystemHelper::getCoreTemplateFileContent($templateVersion, $templateName);
                }
            }
            self::$_templateArray[$templateVersion . '::' . $templateName] = $templateCode;
        } else {
            $templateCode = self::$_templateArray[$templateVersion . '::' . $templateName];
        }
        if (is_array($replace)) {
            $templateCode = str_replace(array_keys($replace), $replace, $templateCode);
        }
        return $templateCode;
    }

    /**
     * @param string $_key
     * @param string $_default
     * @return array|bool|mixed|null|string
     */
    public function getTemplate($_key = '', $_default = '')
    {
        return Utils::getJsonAttr($this->template, $_key, $_default);
    }

    /**
     * @param $_key
     * @param $_value
     * @return $this
     */
    public function setTemplate($_key, $_value)
    {
        if ($this->getTemplate($_key) != $_value) {
            $this->_needRefreshWidget = true;
            $this->_changed = true;
        }
        $this->template = Utils::setJsonAttr($this->template, $_key, $_value);
        return $this;
    }

    /**
     * @return int
     */
    public function getEventOnly()
    {
        return 1;
    }

    public function setEventOnly()
    {
        trigger_error('This method is deprecated', E_USER_DEPRECATED);
    }

    /**
     * @return bool
     */
    public function dontRemoveCmd()
    {
        return false;
    }

    /**
     * @return bool
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function remove()
    {
        ViewDataManager::removeByTypeLinkId(NextDomObj::CMD, $this->getId());
        DataStoreManager::removeByTypeLinkId(NextDomObj::CMD, $this->getId());
        $this->getEqLogicId()->emptyCacheWidget();
        $this->emptyHistory();
        CacheManager::delete(CmdConfigKey::CMD_CACHE_ATTR . $this->getId());
        CacheManager::delete(NextDomObj::CMD . $this->getId());
        NextDomHelper::addRemoveHistory([Common::ID => $this->getId(), Common::NAME => $this->getHumanName(), 'date' => date(DateFormat::FULL), 'type' => NextDomObj::CMD]);
        return parent::remove();
    }

    /**
     * @param string $_date
     * @return array|mixed|null
     * @throws CoreException
     */
    public function emptyHistory($_date = '')
    {
        return HistoryManager::emptyHistory($this->getId(), $_date);
    }

    /**
     * @param string $viewVersion
     * @param string $_options
     * @param null $_cmdColor
     * @return mixed|string
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function toHtml($viewVersion = CmdViewType::DASHBOARD, $_options = '', $_cmdColor = null)
    {
        $version2 = NextDomHelper::versionAlias($viewVersion, false);
        if ($this->getDisplay('showOn' . $version2, 1) == 0) {
            return '';
        }
        $version = NextDomHelper::versionAlias($viewVersion);
        $htmlRender = '';
        $htmlData = [
            '#id#' => $this->getId(),
            '#name#' => $this->getName(),
            '#name_display#' => ($this->getDisplay('icon') != '') ? $this->getDisplay('icon') : $this->getName(),
            '#history#' => '',
            '#hide_history#' => 'hidden',
            '#displayHistory#' => 'display : none;',
            '#unite#' => $this->getUnite(),
            '#minValue#' => $this->getConfiguration(CmdConfigKey::MIN_VALUE, 0),
            '#maxValue#' => $this->getConfiguration(CmdConfigKey::MAX_VALUE, 100),
            '#logicalId#' => $this->getLogicalId(),
            '#uid#' => NextDomObj::CMD . $this->getId() . EqLogic::UIDDELIMITER . mt_rand() . EqLogic::UIDDELIMITER,
            '#version#' => $viewVersion,
            '#eqLogic_id#' => $this->getEqLogic_id(),
            '#generic_type#' => $this->getGeneric_type(),
            '#hide_name#' => '',
            '#value_history#' => ''
        ];
        if ($this->getConfiguration(CmdConfigKey::LIST_VALUE, '') != '') {
            $listOption = '';
            $elements = explode(';', $this->getConfiguration(CmdConfigKey::LIST_VALUE, ''));
            $cmdValue = $this->getCmdValue();
            $isObjectOfTypeInfo = false;
            if (!$cmdValue) {
                $listOption = '<option value="">' . __('Aucun') . '</option>' . $listOption;
            } else {
                $isObjectOfTypeInfo = is_object($cmdValue) && $cmdValue->isType(CmdType::INFO);
            }
            foreach ($elements as $element) {
                $coupleArray = explode('|', $element);
                if ($isObjectOfTypeInfo && ($cmdValue->execCmd() == $coupleArray[0])) {
                    $selected = " selected";
                } else {
                    $selected = "";
                }
                $listOption .= '<option value="' . $coupleArray[0] . '"' . $selected . '>' . $coupleArray[1] . '</option>';
            }
            $htmlData['#listValue#'] = $listOption;
        }
        if ($this->getDisplay('showNameOn' . $version2, 1) == 0) {
            $htmlData['#hide_name#'] = 'hidden';
        }
        if ($this->getDisplay('showIconAndName' . $version2, 0) == 1) {
            $htmlData['#name_display#'] = $this->getDisplay('icon') . ' ' . $this->getName();
        }
        $templateCode = $this->getWidgetTemplateCode($viewVersion);
        if ($_cmdColor == null && $version != 'scenario') {
            $eqLogic = $this->getEqLogicId();
            if ($eqLogic->getPrimaryCategory() == '') {
                $htmlData['#cmdColor#'] = NextDomHelper::getConfiguration('eqLogic:category:default:cmdColor');
            } else {
                $htmlData['#cmdColor#'] = NextDomHelper::getConfiguration('eqLogic:category:' . $eqLogic->getPrimaryCategory() . ':cmdColor');
            }
        } else {
            $htmlData['#cmdColor#'] = $_cmdColor;
        }
        if ($this->isType(CmdType::INFO)) {
            $this->addDataForInfoCmdRender($htmlData, $version, $version2, $templateCode);
            return Utils::templateReplace($htmlData, $templateCode);
        } else {
            $htmlRender = $this->addDataForOthersCmdRender($htmlData, $htmlRender, $_options, $templateCode);
            return Utils::templateReplace($htmlData, $htmlRender);
        }
    }

    /**
     * @return Cmd|bool
     * @throws \Exception
     */
    public function getCmdValue()
    {
        $cmd = CmdManager::byId(str_replace('#', '', $this->getValue()));
        if (is_object($cmd)) {
            return $cmd;
        }
        return false;
    }

    private function addDataForInfoCmdRender(&$htmlData, $version, $version2, $templateCode)
    {
        $htmlData['#state#'] = '';
        $htmlData['#tendance#'] = '';
        if (!$this->getEqLogicId()->isEnabled()) {
            $templateCode = FileSystemHelper::getCoreTemplateFileContent($version, 'cmd.error', '');
            $htmlData['#state#'] = 'N/A';
        } else {
            $htmlData['#state#'] = $this->execCmd();
            if (strpos($htmlData['#state#'], 'error::') !== false) {
                $templateCode = FileSystemHelper::getCoreTemplateFileContent($version, 'cmd.error', '');
                $htmlData['#state#'] = str_replace('error::', '', $htmlData['#state#']);
            } else {
                if ($this->isSubType(CmdSubType::BINARY) && $this->getDisplay('invertBinary') == 1) {
                    $htmlData['#state#'] = ($htmlData['#state#'] == 1) ? 0 : 1;
                }
                if ($this->isSubType(CmdSubType::NUMERIC) && trim($htmlData['#state#']) == '') {
                    $htmlData['#state#'] = 0;
                }
            }
            if (method_exists($this, 'formatValueWidget')) {
                $htmlData['#state#'] = $this->formatValueWidget($htmlData['#state#']);
            }
        }

        $htmlData['#state#'] = str_replace(["\'", "'"], ["'", "\'"], $htmlData['#state#']);
        $htmlData['#collectDate#'] = $this->getCollectDate();
        $htmlData['#valueDate#'] = $this->getValueDate();
        $htmlData['#alertLevel#'] = $this->getCache('alertLevel', 'none');
        if ($this->getIsHistorized() == 1) {
            $htmlData['#history#'] = 'history cursor';
            if (ConfigManager::byKey('displayStatsWidget') == 1
                && strpos($templateCode, '#displayHistory#') !== false
                && $this->getDisplay('showStatsOn' . $version2, 1) == 1) {
                $startHist = date(DateFormat::FULL, strtotime(date(DateFormat::FULL) . ' -' . ConfigManager::byKey('historyCalculPeriod') . ' hour'));
                $htmlData['#displayHistory#'] = '';
                $historyStatistique = $this->getStatistique($startHist, date(DateFormat::FULL));
                if ($historyStatistique['avg'] == 0 && $historyStatistique['min'] == 0 && $historyStatistique['max'] == 0) {
                    $htmlData['#averageHistoryValue#'] = round($htmlData['#state#'], 1);
                    $htmlData['#minHistoryValue#'] = round($htmlData['#state#'], 1);
                    $htmlData['#maxHistoryValue#'] = round($htmlData['#state#'], 1);
                } else {
                    $htmlData['#averageHistoryValue#'] = round($historyStatistique['avg'], 1);
                    $htmlData['#minHistoryValue#'] = round($historyStatistique['min'], 1);
                    $htmlData['#maxHistoryValue#'] = round($historyStatistique['max'], 1);
                }
                $startHist = date(DateFormat::FULL, strtotime(date(DateFormat::FULL) . ' -' . ConfigManager::byKey('historyCalculTendance') . ' hour'));
                $tendance = $this->getTendance($startHist, date(DateFormat::FULL));
                if ($tendance > ConfigManager::byKey('historyCalculTendanceThresholddMax')) {
                    $htmlData['#tendance#'] = 'fa fa-arrow-up';
                } else if ($tendance < ConfigManager::byKey('historyCalculTendanceThresholddMin')) {
                    $htmlData['#tendance#'] = 'fa fa-arrow-down';
                } else {
                    $htmlData['#tendance#'] = 'fa fa-minus';
                }
            }
        }
        $parameters = $this->getDisplay('parameters');
        if (is_array($parameters)) {
            foreach ($parameters as $key => $value) {
                $htmlData['#' . $key . '#'] = $value;
            }
        }
    }

    /**
     * @param $_startTime
     * @param $_endTime
     * @return array
     * @throws CoreException
     */
    public function getStatistique($_startTime, $_endTime)
    {
        if (!$this->isType(CmdType::INFO) || $this->isType(CmdType::STRING)) {
            return [];
        }
        return HistoryManager::getStatistics($this->getId(), $_startTime, $_endTime);
    }

    /**
     * @param $_startTime
     * @param $_endTime
     * @return float|int
     * @throws \Exception
     */
    public function getTendance($_startTime, $_endTime)
    {
        return HistoryManager::getTendance($this->getId(), $_startTime, $_endTime);
    }

    private function addDataForOthersCmdRender(&$htmlData, $htmlRender, $_options, $templateCode)
    {
        $cmdValue = $this->getCmdValue();
        if (is_object($cmdValue) && $cmdValue->isType(CmdType::INFO)) {
            $htmlData['#value_id#'] = $cmdValue->getId();
            $htmlData['#state#'] = $cmdValue->execCmd();
            $htmlData['#valueName#'] = $cmdValue->getName();
            $htmlData['#unite#'] = $cmdValue->getUnite();
            $htmlData['#valueDate#'] = $cmdValue->getValueDate();
            $htmlData['#collectDate#'] = $cmdValue->getCollectDate();
            $replace['#valueDate#'] = $cmdValue->getValueDate();
            $replace['#value_history#'] = ($cmdValue->getIsHistorized() == 1) ? 'history cursor' : '';
            $htmlData['#alertLevel#'] = $cmdValue->getCache('alertLevel', 'none');
            if (trim($htmlData['#state#']) == '' && ($cmdValue->getSubType() == CmdSubType::BINARY || $cmdValue->getSubType() == CmdSubType::NUMERIC)) {
                $htmlData['#state#'] = 0;
            }
            if ($cmdValue->getSubType() == CmdSubType::BINARY && $cmdValue->getDisplay('invertBinary') == 1) {
                $htmlData['#state#'] = ($htmlData['#state#'] == 1) ? 0 : 1;
            }
        } else {
            $htmlData['#state#'] = ($this->getLastValue() !== null) ? $this->getLastValue() : '';
            $htmlData['#valueName#'] = $this->getName();
            $htmlData['#unite#'] = $this->getUnite();
        }
        $htmlData['#state#'] = str_replace(["\'", "'"], ["'", "\'"], $htmlData['#state#']);
        $parameters = $this->getDisplay('parameters');
        if (is_array($parameters)) {
            foreach ($parameters as $key => $value) {
                $htmlData['#' . $key . '#'] = $value;
            }
        }

        $htmlRender .= Utils::templateReplace($htmlData, $templateCode);
        if (trim($htmlRender) == '') {
            return $htmlRender;
        }
        if ($_options != '') {
            $options = NextDomHelper::toHumanReadable($_options);
            $options = Utils::isJson($options, $options);
            if (is_array($options)) {
                foreach ($options as $key => $value) {
                    $htmlData['#' . $key . '#'] = $value;
                }
            }
        }
        if (!isset($htmlData['#title#'])) {
            $htmlData['#title#'] = '';
        }
        if (!isset($htmlData['#message#'])) {
            $htmlData['#message#'] = '';
        }
        if (!isset($htmlData['#slider#'])) {
            $htmlData['#slider#'] = '';
        }
        if (!isset($htmlData['#color#'])) {
            $htmlData['#color#'] = '';
        }
        $htmlData['#title_placeholder#'] = $this->getDisplay('title_placeholder', __('Titre'));
        $htmlData['#message_placeholder#'] = $this->getDisplay('message_placeholder', __('Message'));
        $htmlData['#message_cmd_type#'] = $this->getDisplay('message_cmd_type', 'info');
        $htmlData['#message_cmd_subtype#'] = $this->getDisplay('message_cmd_subtype', '');
        $htmlData['#message_disable#'] = $this->getDisplay('message_disable', 0);
        $htmlData['#title_disable#'] = $this->getDisplay('title_disable', 0);
        $htmlData['#title_color#'] = $this->getDisplay('title_color', 0);
        $htmlData['#title_possibility_list#'] = str_replace("'", "\'", $this->getDisplay('title_possibility_list', ''));
        $htmlData['#slider_placeholder#'] = $this->getDisplay('slider_placeholder', __('Valeur'));
        $htmlData['#other_tooltips#'] = ($htmlData['#name#'] != $this->getName()) ? $this->getName() : '';
        return $htmlRender;
    }

    /**
     * @return array|bool|mixed|null|string
     */
    public function getLastValue()
    {
        return $this->getConfiguration(CmdConfigKey::LAST_CMD_VALUE, null);
    }

    /**
     * @param $_response
     * @param string $_plugin
     * @param string $_network
     * @return string
     * @throws \Exception
     */
    public function generateAskResponseLink($_response, $_plugin = 'core', $_network = 'external')
    {
        $token = $this->getCache('ask::token', ConfigManager::genKey());
        $this->setCache(['ask::count' => 0, 'ask::token' => $token]);
        $result = NetworkHelper::getNetworkAccess($_network) . '/src/Api/jeeApi.php?';
        $result .= 'type=ask';
        $result .= '&plugin=' . $_plugin;
        $result .= '&apikey=' . Api::getApiKey($_plugin);
        $result .= '&token=' . $token;
        $result .= '&response=' . urlencode($_response);
        return $result . '&cmd_id=' . $this->getId();
    }

    /**
     * @param $_response
     * @return bool
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function askResponse($_response)
    {
        if ($this->getCache('ask::variable', 'none') == 'none') {
            return false;
        }
        $askEndTime = $this->getCache('ask::endtime', null);
        if ($askEndTime == null || $askEndTime < strtotime('now')) {
            return false;
        }
        $dataStore = new DataStore();
        $dataStore->setType(NextDomObj::SCENARIO);
        $dataStore->setKey($this->getCache('ask::variable', 'none'));
        $dataStore->setValue($_response);
        $dataStore->setLink_id(-1);
        $dataStore->save();
        $this->setCache(['ask::variable' => 'none', 'ask::count' => 0, 'ask::token' => null, 'ask::endtime' => null]);
        return true;
    }

    /**
     * @param $_startTime
     * @param $_endTime
     * @return array|float|int|null
     * @throws \Exception
     */
    public function getTemporalAvg($_startTime, $_endTime)
    {
        if (!$this->isType(CmdType::INFO) || $this->isType(CmdType::STRING)) {
            return [];
        }
        return HistoryManager::getTemporalAvg($this->getId(), $_startTime, $_endTime);
    }

    /**
     * @param null $_dateStart
     * @param null $_dateEnd
     * @return History[]
     * @throws \Exception
     */
    public function getHistory($_dateStart = null, $_dateEnd = null)
    {
        return HistoryManager::all($this->id, $_dateStart, $_dateEnd);
    }

    /**
     * @param null $_dateStart
     * @param null $_dateEnd
     * @param string $_period
     * @param int $_offset
     * @return array|mixed|null
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function getPluralityHistory($_dateStart = null, $_dateEnd = null, $_period = 'day', $_offset = 0)
    {
        return HistoryManager::getPlurality($this->id, $_dateStart, $_dateEnd, $_period, $_offset);
    }

    /**
     * @param string $_key
     * @param bool $_default
     * @return array|bool|mixed
     * @throws \ReflectionException
     */
    public function widgetPossibility($_key = '', $_default = true)
    {
        $reflectedClass = new \ReflectionClass($this->getEqType());
        $method_toHtml = $reflectedClass->getMethod('toHtml');
        $result = [];
        $result[Common::CUSTOM] = $method_toHtml->class == EqLogic::class;
        $reflectedClass = new \ReflectionClass($this->getEqType() . 'Cmd');
        $method_toHtml = $reflectedClass->getMethod('toHtml');
        $result[Common::CUSTOM] = $method_toHtml->class == Cmd::class;
        $reflectedClass = $this->getEqType() . 'Cmd';
        if (property_exists($reflectedClass, '_widgetPossibility')) {
            /** @noinspection PhpUndefinedFieldInspection */
            $result = $reflectedClass::$_widgetPossibility;
            if ($_key != '') {
                $keys = explode('::', $_key);
                foreach ($keys as $k) {
                    if (!isset($result[$k])) {
                        return false;
                    }
                    if (is_array($result[$k])) {
                        $result = $result[$k];
                    } else {
                        return $result[$k];
                    }
                }
                if (is_array($result)) {
                    return $_default;
                }
                return $result;
            }
        }

        if ($_key != '') {
            if (isset($result[Common::CUSTOM]) && !isset($result[$_key])) {
                return $result[Common::CUSTOM];
            }
            return (isset($result[$_key])) ? $result[$_key] : $_default;
        }
        return $result;
    }

    /**
     * @return array
     * @throws \ReflectionException
     */
    public function export()
    {
        $cmd = clone $this;
        $cmd->setId('');
        $cmd->setOrder('');
        $cmd->setEqLogic_id('');
        $cmd->setDisplay('graphType', '');
        $cmdValue = $cmd->getCmdValue();
        if (is_object($cmdValue)) {
            $cmd->setValue($cmdValue->getName());
        } else {
            $cmd->setValue('');
        }
        $result = Utils::o2a($cmd);
        foreach ($result as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $key2 => $value2) {
                    if ($value2 == '') {
                        unset($result[$key][$key2]);
                    }
                }
            } else {
                if ($value == '') {
                    unset($result[$key]);
                }
            }
        }
        if (isset($result[Common::CONFIGURATION]) && count($result[Common::CONFIGURATION]) == 0) {
            unset($result[Common::CONFIGURATION]);
        }
        if (isset($result[Common::DISPLAY]) && count($result[Common::DISPLAY]) == 0) {
            unset($result[Common::DISPLAY]);
        }
        return $result;
    }

    /**
     * @return string
     * @throws \Exception
     */
    public function getDirectUrlAccess()
    {
        $url = '/src/Api/jeeApi.php?apikey=' . ConfigManager::byKey('api') . '&type=cmd&id=' . $this->getId();
        if ($this->isType(CmdType::ACTION)) {
            switch ($this->getSubType()) {
                case CmdSubType::SLIDER:
                    $url .= '&slider=50';
                    break;
                case CmdSubType::COLOR:
                    $url .= '&color=#123456';
                    break;
                case CmdSubType::MESSAGE:
                    $url .= '&title=montitre&message=monmessage';
                    break;
                case CmdSubType::SELECT:
                    $url .= '&select=value';
                    break;
            }
        }
        return NetworkHelper::getNetworkAccess('external') . $url;
    }

    /**
     * @param $accessCode
     * @return bool
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function checkAccessCode($accessCode)
    {
        if (!$this->isType(CmdType::ACTION) || trim($this->getConfiguration(CmdConfigKey::ACTION_CODE_ACCESS)) == '') {
            return true;
        }
        if (sha1($accessCode) == $this->getConfiguration(CmdConfigKey::ACTION_CODE_ACCESS)) {
            $this->setConfiguration(CmdConfigKey::ACTION_CODE_ACCESS, Utils::sha512($accessCode));
            $this->save();
            return true;
        }
        if (Utils::sha512($accessCode) == $this->getConfiguration(CmdConfigKey::ACTION_CODE_ACCESS)) {
            return true;
        }
        return false;
    }

    /**
     * @return array
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function exportApi()
    {
        $result = Utils::o2a($this);
        $result['currentValue'] = (!$this->isType(CmdType::ACTION)) ? $this->execCmd(null, 2) : $this->getConfiguration(CmdConfigKey::LAST_CMD_VALUE, null);
        return $result;
    }

    /**
     * @param array $_data
     * @param int $_level
     * @param null $_drill
     * @return array|null
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function getLinkData(&$_data = ['node' => [], 'link' => []], $_level = 0, $_drill = null)
    {
        if ($_drill == null) {
            $_drill = ConfigManager::byKey('graphlink::cmd::drill');
        }
        if (isset($_data['node'][NextDomObj::CMD . $this->getId()])) {
            return null;
        }
        $_level++;
        if ($_level > $_drill) {
            return $_data;
        }
        $icon = ($this->isType(CmdType::INFO)) ? Utils::findCodeIcon('fa-eye') : Utils::findCodeIcon('fa-hand-paper-o');
        $_data['node'][NextDomObj::CMD . $this->getId()] = [
            Common::ID => NextDomObj::CMD . $this->getId(),
            Common::NAME => $this->getName(),
            'icon' => $icon['icon'],
            'fontfamily' => $icon['fontfamily'],
            'fontsize' => '1.5em',
            'texty' => -14,
            'textx' => 0,
            'fontweight' => ($_level == 1) ? 'bold' : 'normal',
            'title' => $this->getHumanName(),
            'url' => $this->getEqLogicId()->getLinkToConfiguration(),
        ];
        $usedBy = $this->getUsedBy();
        $use = $this->getUse();
        Utils::addGraphLink($this, NextDomObj::CMD, $usedBy[NextDomObj::SCENARIO], NextDomObj::SCENARIO, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $usedBy[NextDomObj::EQLOGIC], NextDomObj::EQLOGIC, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $usedBy[NextDomObj::CMD], NextDomObj::CMD, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $usedBy[NextDomObj::INTERACT_DEF], NextDomObj::INTERACT_DEF, $_data, $_level, $_drill, [Common::DASH_VALUE => '2,6', Common::LENGTH_FACTOR => 0.6]);
        Utils::addGraphLink($this, NextDomObj::CMD, $usedBy[NextDomObj::PLAN], NextDomObj::PLAN, $_data, $_level, $_drill, [Common::DASH_VALUE => '2,6', Common::LENGTH_FACTOR => 0.6]);
        Utils::addGraphLink($this, NextDomObj::CMD, $usedBy[NextDomObj::VIEW], NextDomObj::VIEW, $_data, $_level, $_drill, [Common::DASH_VALUE => '2,6', Common::LENGTH_FACTOR => 0.6]);
        Utils::addGraphLink($this, NextDomObj::CMD, $use[NextDomObj::SCENARIO], NextDomObj::SCENARIO, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $use[NextDomObj::EQLOGIC], NextDomObj::EQLOGIC, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $use[NextDomObj::CMD], NextDomObj::CMD, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $use[NextDomObj::DATASTORE], NextDomObj::DATASTORE, $_data, $_level, $_drill);
        Utils::addGraphLink($this, NextDomObj::CMD, $this->getEqLogicId(), NextDomObj::EQLOGIC, $_data, $_level, $_drill, [Common::DASH_VALUE => '1,0', Common::LENGTH_FACTOR => 0.6]);
        return $_data;
    }

    /**
     * @param bool $resultHasArray
     * @return array
     * @throws CoreException
     * @throws \ReflectionException
     */
    public function getUsedBy($resultHasArray = false)
    {
        $result = [
            NextDomObj::CMD => [],
            NextDomObj::EQLOGIC => [],
            NextDomObj::SCENARIO => [],
            NextDomObj::PLAN => [],
            NextDomObj::VIEW => []
        ];
        $result[NextDomObj::CMD] = CmdManager::searchConfiguration('#' . $this->getId() . '#');
        $result[NextDomObj::EQLOGIC] = EqLogicManager::searchConfiguration('#' . $this->getId() . '#');
        $result[NextDomObj::SCENARIO] = ScenarioManager::searchByUse([[Common::ACTION => '#' . $this->getId() . '#']]);
        $result[NextDomObj::INTERACT_DEF] = InteractDefManager::searchByUse('#' . $this->getId() . '#');
        $result[NextDomObj::VIEW] = ViewManager::searchByUse(NextDomObj::CMD, $this->getId());
        $result[NextDomObj::PLAN] = PlanHeaderManager::searchByUse(NextDomObj::CMD, $this->getId());
        if ($resultHasArray) {
            foreach ($result as &$usage) {
                $usage = Utils::o2a($usage);
            }
        }
        return $result;
    }

    /**
     * @return array
     * @throws \ReflectionException
     */
    public function getUse()
    {
        $json = NextDomHelper::fromHumanReadable(json_encode(Utils::o2a($this)));
        return NextDomHelper::getTypeUse($json);
    }

    /**
     * Check if user have right to execute the action.
     *
     * @param User $user User to test
     *
     * @return bool True if user can execute
     *
     * @throws \Exception
     */
    public function hasRight($user = null)
    {
        if ($this->isType(CmdType::ACTION)) {
            return $this->getEqLogicId()->hasRight(ActionRight::EXECUTE, $user);
        } else {
            return $this->getEqLogicId()->hasRight(ActionRight::READ, $user);
        }
    }

    /**
     * Cast this object from a source command
     *
     * @param Cmd $srcCmd
     *
     * @return $this
     */
    public function castFromCmd(Cmd $srcCmd)
    {
        $attributes = $srcCmd->getAllAttributes();
        foreach ($attributes as $name => $value) {
            $this->$name = $value;
        }
        return $this;
    }

    public function getSubType()
    {
        return $this->subType;
    }

    public function setSubType($_subType)
    {
        if ($this->subType != $_subType) {
            $this->_needRefreshWidget = true;
            $this->_changed = true;
        }
        $this->subType = $_subType;
        return $this;
    }

    /**
     * Get all attributes of the Cmd class
     *
     * @return array List of attributes
     */
    public function getAllAttributes()
    {
        return [
            '_collectDate' => $this->_collectDate,
            '_valueDate' => $this->_valueDate,
            '_eqLogic' => $this->_eqLogic,
            '_needRefreshWidget' => $this->_needRefreshWidget,
            '_needRefreshAlert' => $this->_needRefreshAlert,
            '_changed' => $this->_changed,
            'eqType' => $this->eqType,
            'logicalId' => $this->logicalId,
            'generic_type' => $this->generic_type,
            'order' => $this->order,
            Common::NAME => $this->name,
            'configuration' => $this->configuration,
            Common::TEMPLATE => $this->template,
            'isHistorized' => $this->isHistorized,
            'type' => $this->type,
            'subType' => $this->subType,
            'unite' => $this->unite,
            'display' => $this->display,
            'isVisible' => $this->isVisible,
            Common::VALUE => $this->value,
            'html' => $this->html,
            'alert' => $this->alert,
            Common::ID => $this->id,
            'eqLogic_id' => $this->eqLogic_id
        ];
    }
}