<?php

namespace PriaxSync;

use PriaxSync\Entity\Entry;

class Priax
{
    const RETRY = 5;

    /**
     * @var \SoapClient
     */
    private $client = null;

    /**
     * Query to retrieve all KPIs for a specific IC
     *
     * @var array
     */
    private $KPIQuery = array(
        'Node' => array(
            'attributes' => array(
                'entry' => array('key' => 'OpMon\ACTIVE', 'value' => 'yes')
            ),
            'id' => 0,
        ),
        'ReturnAttribute'=>array(
            'OpMon\OpMonKpiID',
            'OpMon\CheckInterval',
            'OpMon\ServiceName',
            'OpMon\AffectAvailability',
            'OpMon\RetryCheckInterval',
            'OpMon\OpMonCommand',
            'OpMon\MaximumChecksAttemps',
            'OpMon\OpMonTemplate'
        )
    );

    /**
     * Query to retrieve all Actrive ICs on Priax
     *
     * @var array
     */
    private $ICsQuery = array(
        'arg0' => array(
            'attributes'=>array(
                'entry'=> array(
                    array('key'=>'OpMon\OpMonActive','value' => 'Yes'),
                )
            )
        )
    );

    /**
     * Constructor
     */
    public static function newInstance($wsdl, $isTraceEnabled = false, \SoapClient $client = null)
    {
        return new self($wsdl, $isTraceEnabled, $client);
    }

    /**
     * Constructor
     *
     * @param string $wsdl
     * @param bool $isTraceEnabled Enable trace for SoapClient default:false
     * @param \SoapClient $client Optional
     */
    public function __construct($wsdl, $isTraceEnabled = false, \SoapClient $client = null)
    {
        if (is_null($client) && empty($wsdl)) {
            throw new \InvalidArgumentException('Provide at least a wsdl url');
        }

        ini_set("soap.wsdl_cache_enabled", "0");
        ini_set('default_socket_timeout', 5000);

        $this->client = $client ?: new \SoapClient($wsdl, array(
            'trace' => $isTraceEnabled,
            'connection_timeout' => 5000,
            'cache_wsdl' => WSDL_CACHE_NONE,
            'keep_alive' => false
        ));
    }

    public function getActiveICs()
    {
        $result = $this->getListIdNamesForNodes($this->ICsQuery);
        return $this->returnArray($result->node);
    }

    public function getICsByIds(array $id = array(), array $attributes = array())
    {
        $query = $this->getCustomQuery($id, $attributes);
        $result = $this->getAttributesNodesByQuery($query);
        return $this->returnArray($result->Node);
    }

    public function getIcById($id, array $attributes = array())
    {
        $query = $this->getCustomQuery(array($id), $attributes);
        $result = $this->getAttributesNodesByQuery($query);
        return $result->Node;
    }

    protected function getCustomQuery(array $id, array $attributes)
    {
        $defaultAttr = array(
            'OpMon\OpMonCIName',
            'Basic\NAME',
            'DN',
            'OpMon\OpMonDescription',
            'OpMon\OpMonMonitoringAddress',
            'OpMon\OpMonID',
            'OpMon\OpmonCITemplate',
            'OpMon\OpMonCIIcon',
            'OpMon\OpMonCIActionsPage',
            'OpMon\OpMonCatalogName',
            'OpMon\OpMonCatalogID',
            'OpMon\OpMonCatalog',
        );

        return array(
            'queryNodeObject' => array(
                'query' => 'id(e) in ' . json_encode($id),
                'result' => join(',e.', empty($attributes) ? $defaultAttr : $attributes)
            ),
        );
    }

    public function getKPIsByPriaxID($id, $retry = 0)
    {

        $this->KPIQuery['Node']['id'] = $id;
        try {
            $result =$this->getFormattedKpisByNode($this->KPIQuery);
        } catch (\Exception $e) {
            $retry++;
            return $this->handleException(__FUNCTION__, $e, $retry, array($id, $retry));
        }
        return $this->returnArray($result->KpiNode);
    }

    private function handleException($fn, $exception, $retry, $params = array())
    {
        if (self::RETRY <= $retry) {
            throw $exception;
        }

        return call_user_func_array(array($this, $fn), $params);
    }

    /**
     * Set attributes on Priax Server
     *
     * @param int $itemId Priax Object Node ID
     * @param Entry[] $attributes
     * @return bool
     */
    public function setAttributes($itemId, array $attributes, $opmonId)
    {

        //$tmp = array('key'=>'OpMon\OpMonID','value'=> '');
        /* $param = array(
            'arg0' => array(
                'queryNode' => array('attributes' => array('entry' => $tmp), 'id' => $itemId),
                'resultNode' => array(
                    'attributes' => array(
                        'entry' => $attributes
                    )
                )
            )
        ); */
        //$this->setNodeAs($param);
 
       $param = array(
                'arg0'=>array(
                        'queryNode'=>array('attributes'=>array(
                                        'entry'=>array(
                                                'key'=>'OpMon\OpMonID',
                                                'value'=> ''
                                        )
                                ), 'id'=>$itemId),
                        'resultNode'=>array('attributes'=>array(
                                        'entry'=>array(
                                                'key'=>'OpMon\OpMonID',
                                                'value'=> $opmonId
                                        )
                                )
                        )
                )
        );

        $this->setOpmonIdAndCreateKpis($param);
        return true;
    }

    public function setICOpmonID($id, $opmonId)
    {
    
        // return $this->setAttributes($id, array(new Entry('OpMon\OpMonID', $opmonId)), $opmonId);
        $param = array(
                'arg0'=>array(
                        'queryNode'=>array('attributes'=>array(
                                        'entry'=>array(
                                                'key'=>'OpMon\OpMonID',
                                                'value'=> ''
                                        )
                                ), 'id'=>$id),
                        'resultNode'=>array('attributes'=>array(
                                        'entry'=>array(
                                                'key'=>'OpMon\OpMonID',
                                                'value'=> $opmonId
                                        )
                                )
                        )
                )
        );

        $this->setOpmonIdAndCreateKpis($param);
        return true;
    }

    public function setKPIOpmonID($id, $opmonId)
    {
        //return $this->setAttributes($id, array(new Entry('OpMon\OpMonKpiID', $opmonId)), $opmonId);
        $attributes = array(new Entry('OpMon\OpMonKpiID', $opmonId));
        $param = array(
            'arg0' => array(
                'queryNode' => array('attributes' => $attributes, 'id' => $id),
                'resultNode' => array(
                    'attributes' => array(
                        'entry' => $attributes
                    )
                )
            )
        );
        $this->setNodeAs($param);
        return true;
    }

    public function __call($method, $params)
    {
        return $this->client->__soapCall($method, $params);
    }

    public function getLastRequest()
    {
        return $this->client->__getLastRequest();
    }

    public function getLastResponse()
    {
        return $this->client->__getLastResponse();
    }

    protected function returnArray($item)
    {
        return is_array($item) || empty($item) ?  $item : array($item);
    }

    public function getAllICs(array $filter = array(), array $attributes = array())
    {
        if (empty($filter)) {
            $filter = array(
                'attributes' => array('key'=>'OpMon\OpMonActive','value' => 'Yes') // ,
                //'id' => 190711
            );
        }

        if (empty($attributes)) {
            $attributes = array('attributes'=> '');
        }

        $param = array(
            'queryNodeObject' => array(
                'queryNode' => $filter,
                'resultNode' => $attributes
            )
        );

        return $this->getFormattedNodes($param);
    }

    public function getLastChangeLogId()
    {
        $result = $this->getLastChangeId();
        return $result->return;
    }

    public function getChangesBlockById($id)
    {
        $result = $this->getChangeLogBlockById(array('arg0' => $id));
        return $this->returnArray($result->ChangeLogs);
    }

    public function getParentByOpMonId($id)
    {
        $result = $this->getOpmonParent(array('arg0' => array($id)));
        return $result->NodeRelated->parentOpmonId;
    }

    public function getParentByOpMonIds(array $ids)
    {
        $result = $this->getOpmonParent(array('arg0' => $ids));
        return $this->returnArray($result->NodeRelated);
    }

    public function getIcByKpiId($id, $returnAttributes = null)
    {
        $defaultAttr = array(
            'OpMon\OpMonCIName',
            'OpMon\OpMonDescription',
            'OpMon\OpMonMonitoringAddress',
            'OpMon\OpmonCITemplate',
            'OpMon\OpMonID',
            'OpMon\OpMonActive',
            'OpMon\OpMonCIIcon',
            'OpMon\OpMonCIActionsPage',
            'OpMon\OpMonCatalogName',
            'OpMon\OpMonCatalogID',
            'Basic\NAME',
            'OpMon\OpMonCatalog',
            'DN',
            'OpMonAgentConfiguration\SNMPComunity',
            'OpMonAgentConfiguration\SNMPPort',
            'OpMonAgentConfiguration\SNMPVersion',
            'OpMonAgentConfiguration\SNMPCommunityID',
            'OpMonAgentConfiguration\SNMPUser',
            'OpMonAgentConfiguration\SNMPPass'
        );

        $param = array(
            'KpiNode'=>array('attributes'=>'', 'id' => $id),
            'ReturnAttribute'=> $returnAttributes ?: $defaultAttr
        );

        $result = $this->getNodeRelatedToByKpi($param);
        return $result->Node;
    }

    public function getIcOpMonIdbyKpiId($id)
    {
        $result = $this->getIcByKpiId($id, array('OpMon\OpMonID', 'OpMon\OpMonActive'));
        $result = array_reduce($result->attributes->entry, function ($carr, $item) {
            if ($item->key == 'OpMon\OpMonActive' && $item->value == 'Yes') {
                $carr['isActived'] = true;
            }

            if ($item->key == 'OpMon\OpMonID') {
                $carr['id'] = $item->value;
            }

            return $carr;
        }, array());

        return $result['isActived'] ? $result['id'] : 0;
    }

    public function getKpiById($id)
    {
        $param = array(
            'queryNodeObject'=>array(
                'queryNode'=>array('attributes'=>'', 'id'=>$id),
                'resultNode'=> ''
            )
        );

        $result = $this->getFormattedNodes($param);
        return $result->Node;
    }
}
