<?php
/**
 * core.framework
 *
 * @category   Core
 * @package    Core_Router
 * @subpackage IntegrationTests
 * @copyright  Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 */

/**
 * @category   Core
 * @package    Core_Router
 * @subpackage IntegrationTests
 * @copyright  Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 * @group      Core_Router
 * @group      IntegrationTests
 */
class Core_Router_ModelPluginRouteIntegrationTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var Core_Router
     */
    protected $_object;

    /**
     * @var Core_Request
     */
    protected $_request;

    public function __construct()
    {
        $this->_request      = new Core_Request;
    }

    protected function setUp()
    {
        $this->_object = new Core_Router;
        $this->_object->setRequest($this->_request);
    }

    /**
     * @covers Core_Router::route
     */
    public function testWillUseModelForMatchingTheRoute()
    {
        $route = $this->_setupRoute('/{category}/{id}');
        $this->_object->addRoute($route);

        $this->assertEquals($route, $this->_object->route('/clanak/23'));
    }

    /**
     * @covers Core_Router::route
     * @depends testWillUseModelForMatchingTheRoute
     */
    public function testWillFailToMatchRouteIfThePluginDoesNotMatch()
    {
        $route = $this->_setupRoute('/{category}/{id}');
        $this->_object->addRoute($route);

        // route matched, plugin does not (24 is not a valid ID for our model)
        $this->setExpectedException('RuntimeException');
        $this->_object->route('/clanak/24');
    }

    /**
     * @covers Core_Router::route
     * @depends testWillUseModelForMatchingTheRoute
     */
    public function testWillStoreModelResponseToRoute()
    {
        $route = $this->_setupRoute('/{category}/{id}');
        $this->_object->addRoute($route);
        $this->_object->route('/clanak/23');

        // the data returned from model will be added to route values
        // and then to the request
        $this->assertEquals('Naslov', $this->_request->get('title'));
    }

    /**
     * @covers Core_Router::route
     * @depends testWillStoreModelResponseToRoute
     */
    public function testIfTheModelWrapsTheDataItWillBeWrappedInTheRequestToo()
    {
        // this model will wrap the response in "node" namespace
        $route = $this->_setupRoute('/{category}/{id}', 'Invalid_Sitemap_Wrapped');
        $this->_object->addRoute($route);
        $this->_object->route('/clanak/23');

        // the data returned from model will be added to route values
        // and then to the request
        $node = $this->_request->get('node');
        $this->assertEquals('Naslov', $node['title']);
    }

    /**
     * @covers Core_Router::route
     * @depends testWillUseModelForMatchingTheRoute
     */
    public function testWillRemapRouteValuesBeforeSendingThemToTheModel()
    {
        $route = $this->_setupRoute('/{code}/{id}');
        // remap "code" param to "category"
        $route->getPlugin('model')->setMap(array('code' => 'category'));
        $this->_object->addRoute($route);

        $this->assertEquals($route, $this->_object->route('/clanak/23'));
    }

    protected function _setupRoute($pattern, $modelClass = 'Invalid_Sitemap')
    {
        $model  = new $modelClass;
        $plugin = new Core_Router_Route_Plugin_Model(array('name' => 'model'));
        $plugin->setModel($model);

        $route  = new Core_Router_Route_Token;
        $route
            ->setPattern($pattern)
            ->addPlugin($plugin);

        return $route;
    }
}

class Invalid_Sitemap implements Core_Router_Route_Plugin_Model_Interface
{
    protected $_targets = array(
        array(
            'category' => 'clanak',
            'id'       => 23,

            // this property is NOT verified, it's just used to verify we don't
            // need to match EVERY targer property
            'title'    => 'Naslov',
        ),
    );

    public function match(array $values, array $request = null)
    {
        foreach ($this->_targets as $target) {
            if (!array_diff_assoc($values, $target)) {
                return $target;
            }
        }
        return null;
    }
}

class Invalid_Sitemap_Wrapped extends Invalid_Sitemap
{
    public function match(array $values, array $request = null)
    {
        $match = parent::match($values);
        if ($match) {
            $match = array('node' => $match);
        }
        return $match;
    }
}
