<?php

/**
 * Response logger
 *
 * 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  2014 Lifestyle Webconsulting GmbH
 * @version    $Id:$
 * @link       http://www.life-style.de
 */

namespace Sso\WebserviceBundle\EventListener;

use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Psr\Log\LoggerInterface;
use Sso\WebserviceBundle\ErrorHandler\ErrorHandler;

/**
 * Class ResponseLoggerListener
 * @package Sso\WebserviceBundle\EventListener
 */
class ResponseLoggerListener
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var ErrorHandler
     */
    private $errorHandler;

    /**
     * ResponseLoggerListener constructor.
     * @param LoggerInterface $logger
     * @param ErrorHandler $errorHandler
     */
    public function __construct(LoggerInterface $logger, ErrorHandler $errorHandler)
    {
        $this->logger = $logger;
        $this->errorHandler = $errorHandler;
    }

    /**
     * Log webservice response
     * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
     */
    public function onControllerResponse(PostResponseEvent $event)
    {
        // We don't do anything on other controllers than webservice-controller
        if ('_sso_webservice_service' !== $event->getRequest()->get('_route')) {
            return;
        }

        // Log exceptions
        if ($this->errorHandler->hasErrors()) {
            foreach ($this->errorHandler->getErrors()->getErrors() as $error) {
                if (null !== ($exception = $error->getException())) {
                    $this->logger->debug(sprintf(
                        'Catched exception (%d): "%s" in %s at line %d!' . PHP_EOL . 'Stacktrace: %s',
                        $exception->getCode(),
                        $exception->getMessage(),
                        $exception->getFile(),
                        $exception->getLine(),
                        $exception->getTraceAsString()
                    ));
                }
            }
        }

        // Log response
        try {
            $nonUtf8Chars = $this->countNonUtf8Characters($event->getResponse()->getContent());
            $this->logger->debug('Webservice response-encoding: '.mb_detect_encoding($event->getResponse()->getContent()).' (Non UTF-8 characters: '.$nonUtf8Chars.')');
            $this->logger->info('Webservice response: '.$event->getResponse()->getContent());
        } catch (\Exception $ex) {
            $this->logger->error($ex->getMessage());
        }
    }

    /**
     * @param string $string
     * @return false|int
     */
    private function countNonUtf8Characters($string)
    {
        $regex = '/(
                [\xC0-\xC1] # Invalid UTF-8 Bytes
                | [\xF5-\xFF] # Invalid UTF-8 Bytes
                | \xE0[\x80-\x9F] # Overlong encoding of prior code point
                | \xF0[\x80-\x8F] # Overlong encoding of prior code point
                | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
                | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
                | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
                | (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
                | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
                | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
                | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
                | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
                )/x';

        return preg_match($regex, $string);
    }
}
