<?php

/**
 * Steps Index
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is protected by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2015 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\Component\IdentifyServiceBundle\Api\Request;

use JMS\Serializer\SerializerInterface;
use Sso\Component\IdentifyServiceBundle\Node\Request as RequestNode;
use Sso\Component\IdentifyServiceBundle\Node\Manager as NodeManager;
use JMS\Serializer\DeserializationContext;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

/**
 * Steps Index
 *
 * @copyright  Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */
class Index
{

    /**
     *
     * @var SerializerInterface
     */
    private $serializer;

    /**
     *
     * @var NodeManager
     */
    private $nodeManager;

    /**
     *
     * @var RequestNode
     */
    private $currentRequest;

    /**
     *
     * @param SerializerInterface $serializer
     */
    public function __construct(SerializerInterface $serializer, NodeManager $nodeManager)
    {
        $this->serializer = $serializer;
        $this->nodeManager = $nodeManager;
    }

    /**
     * Create a new request
     *
     * @return Index
     */
    public function create()
    {
        $this->currentRequest = $this->nodeManager->factory()->request();

        return $this;
    }

    /**
     *
     * @param string $xml
     * @param string $controllerName
     * @param string $actionName
     *
     * @return ResponseNode
     */
    public function read($xml, $controllerName, $actionName)
    {
        $context = DeserializationContext::create()->setGroups('Request::' . $controllerName . '::' . $actionName);
        return $this->currentRequest = $this->serializer->deserialize($xml, 'Sso\Component\IdentifyServiceBundle\Node\Request', 'xml', $context);
    }

    /**
     * Set request credentials
     *
     * @param string $username
     * @param string $userIdentifier
     * @param string $serviceToken
     * @param string $serviceName
     * @param string $countryCode
     * @return Index
     */
    public function setCredentials($username = null, $userIdentifier = null, $serviceToken = null, $serviceName = null, $countryCode = null)
    {
        $credentials = $this->nodeManager->request()->credentials()->factory()->credentials();

        if (null !== $countryCode) {
            $serviceCountry = $this->nodeManager->request()->credentials()->factory()->serviceCountry($credentials);
            $serviceCountry->setCode($countryCode);
        }

        if (null !== $serviceName || null !== $serviceToken) {
            $serviceProvider = $this->nodeManager->request()->credentials()->factory()->serviceProvider($credentials);
            $serviceProvider->setServiceName($serviceName)
                    ->setServiceToken($serviceToken);
        }

        if (null !== $userIdentifier || null !== $username) {
            $serviceTrigger = $this->nodeManager->request()->credentials()->factory()->serviceTrigger($credentials);
            $serviceTrigger->setUserIdentifier($userIdentifier)
                    ->setUsername($username);
        }

        $this->currentRequest()->setCredentials($credentials);

        return $this;
    }

    /**
     * Add user-identifier get action
     *
     * @param string $username
     * @param string $password
     * @return Index
     */
    public function addGetAction($username, $password)
    {
        if (!$this->currentRequest()->getController()) {
            $userIdentifierController = $this->nodeManager->request()->controller()->factory()->userIdentifierController();
            $this->currentRequest()->setUserIdentifierController($userIdentifierController);
        }

        $userType = $this->nodeManager->factory()->userType()
                ->setUsername($username)
                ->setPassword($password);

        $userKey = $this->nodeManager->factory()->userKey()
                ->setUserType($userType);

        $getAction = $this->nodeManager->request()->controller()->userIdentifierController()->factory()->getAction()
                ->setUserKey($userKey);

        $this->currentRequest()->getController()
                ->addGetAction($getAction);

        return $this;
    }

    /**
     * Add user-identifier validate action
     *
     * @param string $username
     * @param string $userIdentifier
     * @return Index
     */
    public function addValidateAction($username, $userIdentifier)
    {
        if (!$this->currentRequest()->getController()) {
            $userIdentifierController = $this->nodeManager->request()->controller()->factory()->userIdentifierController();
            $this->currentRequest()->setUserIdentifierController($userIdentifierController);
        }
        $userType = $this->nodeManager->factory()->userType()
                ->setUsername($username)
                ->setUserIdentifier($userIdentifier);

        $userKey = $this->nodeManager->factory()->userKey()
                ->setUserType($userType);

        $validateAction = $this->nodeManager->request()->controller()->userIdentifierController()->factory()->validateAction()
                ->setUserKey($userKey);

        $this->currentRequest()->getController()
                ->addValidateAction($validateAction);

        return $this;
    }

    /**
     * Send request
     *
     * @param string $url
     * @return string Response
     */
    public function send($url)
    {
        $options = array(
            'headers' => array(
                'API-VERSION' => '1',
                'API-CONTROLLER' => $this->currentRequest->getController()->getName(),
                'API-ACTION' => $this->currentRequest->getController()->getCurrentAction()->getName(),
                'Content-Type' => 'text/xml; charset=UTF-8'
            ),
            'body' => $this->buildXml()
        );
        $client = new Client();
        $request = $client->createRequest('POST', $url, $options);
        try {
            $response = $client->send($request);
        } catch (RequestException $exception) {
            return null;
        }
        return 0 === strpos($response->getHeader('Content-Type'), 'text/xml') ? $response->getBody() : null;
    }

    /**
     * Get current controller name
     *
     * @return string
     */
    public function getControllerName()
    {
        return $this->currentRequest->getController()->getName();
    }

    /**
     * Get current action name
     *
     * @return string
     */
    public function getActionName()
    {
        return $this->currentRequest->getController()->getCurrentAction()->getName();
    }

    /**
     *
     * @return string
     */
    public function buildXml()
    {
        return $this->serializer->serialize($this->currentRequest(), 'xml', $this->currentRequest()->getSerializationContext());
    }

    /**
     *
     * @return RequestNode
     */
    private function currentRequest()
    {
        if (null === $this->currentRequest) {
            $this->create();
        }
        return $this->currentRequest;
    }

}
