<?php
namespace Webkul\AdvanceSeoManager\Model;

class PingService
{

    const YANDAX= "http://ping.blogs.yandex.ru";
    const GOOGLE = "http://blogsearch.google.com/ping/RPC2";
    const YAHOO = "http://api.my.yahoo.com/RPC2";
    const FEED_BURNER = "http://ping.feedburner.com";
    const WEB_LOGS = "http://ping.weblogs.se/";
    const PINGOMATIC = "http://pingomatic.com/ping/";
    const ALL = "all";
    const CUSTOM = "custom";

    /**
     * @var Webkul\AdvanceSeoManager\Helper\Data
     */
    protected $_helper;

    /**
     * @var array
     */
    protected $services = [];

    /**
     * @var \Magento\Framework\Xml\Parser
     */
    protected $parser;

    /**
     * @var Webkul\AdvanceSeoManager\Logger\PingLogger
     */
    protected $logger;

    /**
     * Create new instance of Pinger class.
     */
    public function __construct(
        \Webkul\AdvanceSeoManager\Helper\Data $helper,
        \Magento\Framework\Xml\Parser $parser,
        \Magento\Framework\Json\Helper\Data $jsonHelper,
        \Magento\Framework\HTTP\Client\Curl $curl,
        \Webkul\AdvanceSeoManager\Logger\PingLogger $logger
    ) {
    
        $this->_helper = $helper;
        $this->_parser = $parser;
        $this->jsonHelper = $jsonHelper;
        $this->curl = $curl;
        $this->services = $this->_helper->getPingServices();
        $this->logger = $logger;
    }

    /**
     * ping yandex
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function pingYandex($title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        return $this->sendPing(self::YANDAX, $xml);
    }

    /**
     * ping google
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function pingGoogle($title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        return $this->sendPing(self::GOOGLE, $xml);
    }

    /**
     * ping yahoo
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function pingYahoo($title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        return $this->sendPing(self::YAHOO, $xml);
    }

    /**
     * ping feedburner
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function pingFeedburner($title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        return $this->sendPing(self::FEED_BURNER, $xml);
    }

    /**
     * ping weblogs
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function pingWeblogs($title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        return $this->sendPing(self::WEB_LOGS, $xml);
    }

    /**
     * pingomatic ping
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function pingPingOMatic($title, $url, $rss = null, $params = [])
    {
        $entity = [
            'chk_weblogscom'    => 'on',
            'chk_blogs'         => 'on',
            'chk_feedburner'    => 'on',
            'chk_newsgator'     => 'on',
            'chk_myyahoo'       => 'on',
            'chk_pubsubcom'     => 'on',
            'chk_blogdigger'    => 'on',
            'chk_weblogalot'    => 'on',
            'chk_newsisfree'    => 'on',
            'chk_topicexchange' => 'on',
            'chk_google'        => 'on',
            'chk_tailrank'      => 'on',
            'chk_skygrid'       => 'on',
            'chk_collecta'      => 'on',
            'chk_superfeedr'    => 'on',
        ];
        $entity['title'] = urlencode($title);
        $entity['blogurl'] = urlencode($url);
        $entity['rssurl'] = urlencode($rss);
        $queryString = http_build_query(array_merge($entity, $params));
        $serviceUrl = 'http://pingomatic.com/ping/?'.$queryString;
        return $this->sendPing($serviceUrl, $queryString);
    }

    /**
     * send custom ping
     *
     * @param  string $serviceUrl
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return mixed
     */
    public function ping($serviceUrl, $title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        return $this->sendPing($serviceUrl, $xml);
    }

    /**
     * get xml
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return string
     */
    public function pingAll($title, $url, $rss = null)
    {
        $xml = $this->getXml($title, $url, $rss);
        foreach ($this->services as $service) {
            if ($service['value'] == "custom" || $service['value'] == "all") {
                continue;
            }
            $this->sendPing($service['value'], $xml);
        }
        $this->pingPingOMatic($title, $url, $rss);
        return true;
    }

    /**
     * send ping for request
     *
     * @return void
     */
    public function send($serviceData)
    {
        $response = '';
        $responseContent = [];
        $this->logger->debug("Ping Attemted Url: ".$serviceData['url']);
        switch ($serviceData['service']) {
            case self::YANDAX:
                $response = $this->pingYandex($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::GOOGLE:
                $response = $this->pingGoogle($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::YAHOO:
                $response = $this->pingYahoo($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::FEED_BURNER:
                $response = $this->pingFeedburner($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::WEB_LOGS:
                $response = $this->pingWeblogs($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::PINGOMATIC:
                $response = $this->pingPingOMatic($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::ALL:
                $response = $this->pingAll($serviceData['title'], $serviceData['url'], $serviceData['rss_url']);
                break;
            case self::CUSTOM:
                $customUrl = $serviceData['custom_url'];
                $response = $this->ping(
                    $customUrl,
                    $serviceData['title'],
                    $serviceData['url'],
                    $serviceData['rss_url']
                );
                break;
        }
        if ($response == true) {
            $responseContent = [
                'success' => true,
                'error_message' => __("successfully pinged")
            ];
        } elseif ($response) {
            $responseContent = [
                'success' => true,
                'error_message' => $response
            ];
        } else {
            $responseContent = [
                'success' => false,
                'error_message' => __('there is some error in ping service.')
            ];
        }

        return $responseContent;
    }

    /**
     * get xml
     *
     * @param  string $title
     * @param  string $url
     * @param  string $rss
     * @return string
     */
    private function getXml($title, $url, $rss = null)
    {
        $data = [
            'title' => $title,
            'url'   => $url,
        ];
        if (!empty($rss)) {
            $data['rss'] = $rss;
        }
        $xml = "<?xml version=\"1.0\"?>\"
        <methodCall>\"
        <methodName>weblogUpdates.ping</methodName>\"
        <params>\"
        <param>\"
        <value>\"
        <string>".$data['title']."</string>\"
        </value>\"
        </param>\"
        <param>\"
        <value>\"
        <string>".$data['url']."</string>\"
        </value>\"
        </param>\"
        </params>\"
        </methodCall>";
        return $xml;
    }

    /**
     * send ping
     *
     * @param  string $url
     * @param  array  $post
     * @return mixed
     */
    private function sendPing($url, $post)
    {
        $this->curl->setOption(CURLOPT_RETURNTRANSFER, 1);
        $this->curl->setOption(CURLOPT_TIMEOUT, 3);
        $this->curl->setOption(CURLOPT_POST, 1);
        $this->curl->setOption(CURLOPT_USERAGENT, 'Mozilla/5.0');
        $this->curl->addHeader('Content-Type', 'text/xml');
        $this->curl->post($url, $post);
        $response = $this->curl->getBody();
        
        try {
            $response = $this->_parser->loadXML($response)->xmlToArray();
            $this->logger->debug("Ping search engine: ".$url." ".$this->jsonHelper->jsonEncode($response));
            return $response;
        } catch (\Exception $e) {
            if ($response && strpos($response, "Slow down cowboy") !== false) {
                $this->logger->debug("Ping search engine: ".$url." Failed");
                return false;
            } elseif (strpos($response, "Slow down cowboy") === false) {
                $this->logger->debug("Ping search engine: ".$url." success");
                return true;
            }
            $this->logger->debug("Ping search engine: ".$url." Failed");
            return false;
        }

        return $response;
    }
}
