<?php

/**
 *
 * @class BaseController
 * @author sb
 *
 * 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
 * @version    $Id:$
 * @link       http://www.life-style.de
 *
 */

namespace Sso\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sso\ApiBundle\Api;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type as FormType;

/**
 * Class BaseController
 * @package Sso\DemoBundle\Controller
 */
abstract class BaseController extends Controller
{

    /**
     * Link to profiler from last webservice-request
     *
     * @var string
     */
    protected $urlProfiler;

    /**
     * Form default values
     *
     * @return array
     */
    protected function _getFormDefaults(Request $request)
    {
        return array(
            'UserUsername' => $this->_getUserUsername($request),
            'UserIdentifier' => $this->_getUserIdentifier($request),
            'ServiceToken' => $this->_getServiceToken($request),
            'ServiceCountry' => $this->_getServiceCountry($request)
        );
    }

    /**
     * Get user name string
     *
     * @return string
     */
    protected function _getUserUsername(Request $request)
    {
        if (null === ($userUsername = $this->sessionVariable('UserUsername'))) {
            $userUsername = $request->get('UserUsername', 'username');
            $this->sessionVariable('UserUsername', $userUsername);
        }
        return $userUsername;
    }

    /**
     * Get user identifier string
     *
     * @return string
     */
    protected function _getUserIdentifier(Request $request)
    {
        if (null === ($userIdentifier = $this->sessionVariable('UserIdentifier'))) {
            $userIdentifier = $request->get('UserIdentifier',
                '5e211de5c4aa76564fc5e3657a7946aab3e2dbe60a773117568b3e67a2223a2c6878e5d25ee70588b19728f010417388f590128beced60402c7b8036b725ba71');
            $this->sessionVariable('UserIdentifier', $userIdentifier);
        }
        return $userIdentifier;
    }

    /**
     * Get service token string
     *
     * @return string
     */
    protected function _getServiceToken(Request $request)
    {
        if (null === ($serviceToken = $this->sessionVariable('ServiceToken'))) {
            $serviceToken = $request->get('ServiceToken',
                'X2222cOhc6Vttcxs6r6bmtdlc8Z1ryTN1TQ16pjivEcprZhye9e17ba7508a4358f99c8ba52ded0f70RnZDhDyKMXLEWobXI2ZOrJ7mXjcPJJNk7wxoAw8WUTk0IMYa');
            $this->sessionVariable('ServiceToken', $serviceToken);
        }
        return $serviceToken;
    }

    /**
     * Get country string
     *
     * @return string
     */
    protected function _getServiceCountry(Request $request)
    {
        if (null === ($serviceCountryCode = $this->sessionVariable('ServiceCountryCode'))) {
            $serviceCountryCode = $request->get('ServiceCountryCode', 'DE');
            $this->sessionVariable('ServiceCountryCode', $serviceCountryCode);
        }
        return $serviceCountryCode;
    }

    /**
     * Set or get session variable
     *
     * @param string $varname
     * @param mixed $value
     * @return mixed
     */
    private function sessionVariable($varname, $value = null)
    {
        if (!$this->has('session')) {
            return null;
        }
        $session = $this->get('session');
        if (2 == func_num_args()) {
            $session->set($varname, $value);
        }
        return $session->has($varname) ? $session->get($varname) : null;
    }


    /**
     * Build xml to identify user
     *
     * @param array $params
     * @param string $prefix
     * @return string
     */
    protected function _xmlBuildLanguageIdentifier($params, $prefix = '')
    {
        $keys = array(
            'Code',
        );
        return $this->xmlBuildIdentifier($keys, $params, $prefix);
    }

    /**
     * Build xml to identify type
     *
     * @param array $params
     * @param string $prefix
     * @return string
     */
    protected function _xmlBuildTypeIdentifier($params, $prefix = '')
    {
        $keys = array(
            'Name',
            'TypeOrder',
        );
        return $this->xmlBuildIdentifier($keys, $params, $prefix);
    }

    /**
     * Build xml to identify type
     *
     * @param array $params
     * @param string $prefix
     * @return string
     */
    protected function _xmlBuildTypeUpdateIdentifier($params, $prefix = '')
    {
        $keys = array(
            'Id',
            'Name',
            'TypeOrder',
        );
        return $this->xmlBuildIdentifier($keys, $params, $prefix);
    }

    /**
     * Build xml to identify type
     *
     * @param array $params
     * @param string $prefix
     * @return string
     */
    protected function _xmlBuildTypeShowIdentifier($params, $prefix = '')
    {
        $keys = array(
            'Id',
            'Name',
        );
        return $this->xmlBuildIdentifier($keys, $params, $prefix);
    }

    /**
     * Build xml to delete type
     *
     * @param array $params
     * @param string $prefix
     * @return string
     */
    protected function xmlBuildTypeDeleteIdentifier($params, $prefix = '')
    {
        $keys = array(
            'Id',
        );
        return $this->xmlBuildIdentifier($keys, $params, $prefix);
    }

    /**
     * Build xml to identify type
     *
     * @param array $keys
     * @param array $params
     * @param string $prefix
     * @return string
     */
    protected function xmlBuildIdentifier($keys, $params, $prefix = '')
    {
        $xml = array();
        foreach ($keys as $key) {
            $idx = $prefix . $key;
            if (!empty($params[$idx]) || $params[$idx] === 0) {
                $xml[] = '<' . $key . '>' . $params[$idx] . '</' . $key . '>';
            }
        }
        return implode("\n", $xml);
    }

    /**
     * Parse xml string
     *
     * @param string $response
     * @return string Formatted xml string
     */
    protected function _formatXml($response)
    {
        libxml_clear_errors();
        libxml_disable_entity_loader(true);
        libxml_use_internal_errors(true);
        $xml = new \DOMDocument('UTF-8', LIBXML_NONET);
        $xml->preserveWhiteSpace = false;
        if (true === @$xml->loadXML($response, LIBXML_DTDLOAD | LIBXML_DTDATTR)) {
            $xml->formatOutput = true;
            libxml_clear_errors();
            libxml_disable_entity_loader(false);
            return $xml->saveXml();
        }
        libxml_clear_errors();
        libxml_disable_entity_loader(false);
        return $response;
    }

    /**
     *
     * @param type $formData
     * @param type $controller
     * @param type $action
     * @return type
     */
    protected function _runAction($formData, $controller, $action, $request)
    {
        $method = '_xml' . $controller . $action;
        return $this->_callWebservice($this->$method($formData), $controller, $action, $request);
    }

    /**
     * Send request to webservice
     *
     * @param string $xmlRequest
     * @param string $controller
     * @param string $action
     * @return string
     */
    protected function _callWebservice($xmlRequest, $controller, $action, $request)
    {
        // check header
        $httpsTrue = $request->headers->get('x-forwarded-proto');
        if (!empty($httpsTrue)) {
            $url = $httpsTrue . "://" . $request->getHost();
        } else {
            $url = $request->getScheme() . "://" . $request->getHost();
        }

        $username = "sso";
        $password = "23#99";

        $headers = array(
            'SSO-API-VERSION: 1',
            'SSO-API-CONTROLLER: ' . $controller . '',
            'SSO-API-ACTION: ' . $action . '',
            'Content-Type: text/xml',
        );

        $connection = curl_init();
        curl_setopt($connection, CURLOPT_URL, $url);
        curl_setopt($connection, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($connection, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($connection, CURLOPT_USERPWD, $username . ":" . $password);
        curl_setopt($connection, CURLOPT_HEADER, 1);
        curl_setopt($connection, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($connection, CURLOPT_POST, 1);
        curl_setopt($connection, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($connection, CURLOPT_TIMEOUT, 200);
        curl_setopt($connection, CURLOPT_ENCODING, "");

        curl_setopt($connection, CURLOPT_POSTFIELDS, $xmlRequest);
        $response = curl_exec($connection);
        $c_error = curl_error($connection);
        if ($c_error) {
            $c_error_no = curl_errno($connection);
            throw new \Exception("Server Error " . $c_error_no . ' : ' . $c_error);
        }
        $responseHeaderSize = curl_getinfo($connection, CURLINFO_HEADER_SIZE);
        curl_close($connection);

        $responseHeaders = substr($response, 0, $responseHeaderSize);
        $responseXml = substr($response, $responseHeaderSize);
        $this->urlProfiler = $this->_getProfilerLink($responseHeaders);

        return array($this->_formatXml($xmlRequest), $this->_formatXml($responseXml));
    }

    /**
     * Pull out profiler link from response header
     *
     * @param string $headers
     * @return string Link to profiler
     */
    protected function _getProfilerLink($headers)
    {
        return preg_match('/X-Debug-Token-Link:\s*([^\s^\n]*)/i', $headers, $matches) ? $matches[1] : '';
    }

    /**
     * Generate response for template
     *
     * @param \Symfony\Component\Form\Form $form
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @param string $controller
     * @param string $action
     * @return array
     */
    protected function _getResponseFromForm($form, $request, $controller, $action, $stressMe = false)
    {
        $form->handleRequest($request);
        $formData = $form->getData();
        if (false !== $stressMe) {
            list($xmlRequest, $xmlResponse) = $form->isValid() ? $this->$stressMe($formData, $controller,
                $action) : array('', '');
        } else {
            list($xmlRequest, $xmlResponse) = $form->isValid() ? $this->_runAction($formData, $controller, $action,
                $request) : array('', '');
        }

        // Save some values
        if (isset($formData['ServiceToken'])) {
            $this->sessionVariable('ServiceToken', $formData['ServiceToken']);
        }
        if (isset($formData['UserIdentifier'])) {
            $this->sessionVariable('UserIdentifier', $formData['UserIdentifier']);
        }
        if (isset($formData['ServiceCountryCode'])) {
            $this->sessionVariable('ServiceCountryCode', $formData['ServiceCountryCode']);
        }
        if (isset($formData['UserUsername'])) {
            $this->sessionVariable('UserUsername', $formData['UserUsername']);
        }

        return array(
            'wsRequest' => $xmlRequest,
            'wsResponse' => $xmlResponse,
            'wsProfiler' => $this->urlProfiler,
            'form' => $form->createView()
        );
    }

    /**
     * Build xml request credentials
     *
     * @param array $params
     * @return string
     */
    protected function _xmlCredentials($params)
    {
        return "
            <Credentials>
                <ServiceProvider>
                    <ServiceToken>" . $params['ServiceToken'] . "</ServiceToken>
                    <ServiceName>MyService</ServiceName>
                </ServiceProvider>
                <ServiceTrigger>
                    <Username>" . $params['UserUsername'] . "</Username>
                    <UserIdentifier>" . $params['UserIdentifier'] . "</UserIdentifier>
                </ServiceTrigger>
                <ServiceCountry>
                    <Code>" . $params['ServiceCountry'] . "</Code>
                </ServiceCountry>
            </Credentials>";
    }

    /**
     * Api Manager
     *
     * @return Api\Manager
     */
    protected function apiM()
    {
        return $this->get('service_api_manager');
    }

    /**
     *
     * @return \Symfony\Component\Form\FormBuilderInterface
     */
    protected function buildFormCredentials()
    {
        return $this->createFormBuilder()->create('credentials', null,
            array('compound' => true, 'inherit_data' => true, 'attr' => array('class' => 'form-group-indent')))
            ->add('ServiceToken', FormType\TextType::class)
            ->add('ServiceCountry', FormType\HiddenType::class)
            ->add('UserUsername', FormType\TextType::class)
            ->add('UserIdentifier', FormType\TextType::class);
    }
}
