
#ifdef HAVE_CONFIG_H
#include "../../../ext_config.h"
#endif

#include <php.h>
#include "../../../php_ext.h"
#include "../../../ext.h"

#include <Zend/zend_operators.h>
#include <Zend/zend_exceptions.h>
#include <Zend/zend_interfaces.h>

#include "kernel/main.h"
#include "kernel/object.h"
#include "kernel/memory.h"
#include "kernel/fcall.h"
#include "kernel/operators.h"
#include "kernel/exception.h"
#include "kernel/string.h"
#include "kernel/concat.h"
#include "kernel/array.h"


/**
 * This file is part of the Phalcon Framework.
 *
 * (c) Phalcon Team <team@phalcon.io>
 *
 * For the full copyright and license information, please view the LICENSE.txt
 * file that was distributed with this source code.
 */
/**
 * This class represents every route added to the router
 *
 * @phpstan-import-type cli_route_converters from CliTypes
 * @phpstan-import-type cli_route_extracted from CliTypes
 * @phpstan-import-type cli_route_paths from CliTypes
 * @phpstan-import-type cli_route_reversed_paths from CliTypes
 */
ZEPHIR_INIT_CLASS(Phalcon_Cli_Router_Route)
{
	ZEPHIR_REGISTER_CLASS(Phalcon\\Cli\\Router, Route, phalcon, cli_router_route, phalcon_cli_router_route_method_entry, 0);

	/**
	 * @var string
	 */
	zend_declare_property_string(phalcon_cli_router_route_ce, SL("delimiterPath"), " ", ZEND_ACC_PROTECTED|ZEND_ACC_STATIC);
	{
		zval _zc0;
		ZVAL_LONG(&_zc0, 0);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("uniqueId"), &_zc0, ZEND_ACC_PROTECTED|ZEND_ACC_STATIC, MAY_BE_LONG, NULL, 0);
	}

	/**
	 * @var mixed|null
	 */
	zend_declare_property_null(phalcon_cli_router_route_ce, SL("beforeMatch"), ZEND_ACC_PROTECTED);
	{
		zval _zc0;
		ZVAL_STRINGL(&_zc0, "", sizeof("") - 1);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("compiledPattern"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_STRING, NULL, 0);
	}

	/**
	 * @phpstan-var cli_route_converters
	 */
	{
		zval _zc0;
		array_init_size(&_zc0, 1);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("converters"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_ARRAY, NULL, 0);
	}

	{
		zval _zc0;
		ZVAL_UNDEF(&_zc0);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("delimiter"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_STRING, NULL, 0);
	}

	{
		zval _zc0;
		ZVAL_STRINGL(&_zc0, "", sizeof("") - 1);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("description"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_STRING, NULL, 0);
	}

	{
		zval _zc0;
		ZVAL_STRINGL(&_zc0, "", sizeof("") - 1);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("name"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_STRING, NULL, 0);
	}

	/**
	 * @phpstan-var cli_route_paths
	 */
	{
		zval _zc0;
		array_init_size(&_zc0, 1);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("paths"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_ARRAY, NULL, 0);
	}

	{
		zval _zc0;
		ZVAL_STRINGL(&_zc0, "", sizeof("") - 1);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("pattern"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_STRING, NULL, 0);
	}

	{
		zval _zc0;
		ZVAL_UNDEF(&_zc0);
		zephir_declare_typed_property(phalcon_cli_router_route_ce, SL("routeId"), &_zc0, ZEND_ACC_PROTECTED, MAY_BE_STRING, NULL, 0);
	}

	/**
	 * @var string
	 */
	zephir_declare_class_constant_string(phalcon_cli_router_route_ce, SL("DEFAULT_DELIMITER"), " ");

	zend_class_implements(phalcon_cli_router_route_ce, 1, phalcon_cli_router_routeinterface_ce);
	return SUCCESS;
}

/**
 * Constructor
 *
 * @param array|string paths
 */
PHP_METHOD(Phalcon_Cli_Router_Route, __construct)
{
	zval _2;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval pattern_zv, *paths = NULL, paths_sub, __$null, routeId, uniqueId, _0, _1;
	zend_string *pattern = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&pattern_zv);
	ZVAL_UNDEF(&paths_sub);
	ZVAL_NULL(&__$null);
	ZVAL_UNDEF(&routeId);
	ZVAL_UNDEF(&uniqueId);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	static zend_string *_zephir_prop_0 = NULL;
	static zend_string *_zephir_prop_1 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("delimiter", 9, 1);
	}
	if (UNEXPECTED(!_zephir_prop_1)) {
		_zephir_prop_1 = zend_string_init("routeId", 7, 1);
	}

	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(1, 2)
		Z_PARAM_STR(pattern)
		Z_PARAM_OPTIONAL
		Z_PARAM_ZVAL_OR_NULL(paths)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	if (ZEND_NUM_ARGS() > 1) {
		paths = ZEND_CALL_ARG(execute_data, 2);
	}
	zephir_memory_observe(&pattern_zv);
	ZVAL_STR_COPY(&pattern_zv, pattern);
	if (!paths) {
		paths = &paths_sub;
		paths = &__$null;
	}
	zephir_memory_observe(&_0);
	zephir_read_static_property_ce(&_0, phalcon_cli_router_route_ce, SL("delimiterPath"), PH_NOISY_CC);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 513, &_0);
	ZEPHIR_CALL_METHOD(NULL, this_ptr, "reconfigure", NULL, 0, &pattern_zv, paths);
	zephir_check_call_status();
	zephir_memory_observe(&_1);
	zephir_read_static_property_ce(&_1, phalcon_cli_router_route_ce, SL("uniqueId"), PH_NOISY_CC);
	ZEPHIR_CPY_WRT(&uniqueId, &_1);
	ZEPHIR_CPY_WRT(&routeId, &uniqueId);
	zephir_cast_to_string(&_2, &routeId);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_1, 514, &_2);
	ZVAL_UNDEF(&_1);
	ZVAL_LONG(&_1, (zephir_get_numberval(&uniqueId) + 1));
	zephir_update_static_property_ce(phalcon_cli_router_route_ce, ZEND_STRL("uniqueId"), &_1);
	ZEPHIR_MM_RESTORE();
}

/**
 * Set the routing delimiter.
 *
 * This sets a process-global delimiter that each route captures at
 * construction time. Configure it once during bootstrap, before any routes
 * are created: routes built before and after a change keep their own
 * delimiter, and `Console::setArgument()` reads the current value when it
 * parses arguments.
 */
PHP_METHOD(Phalcon_Cli_Router_Route, delimiter)
{
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zval delimiter_zv;
	zend_string *delimiter = NULL;

	ZVAL_UNDEF(&delimiter_zv);
	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(0, 1)
		Z_PARAM_OPTIONAL
		Z_PARAM_STR_OR_NULL(delimiter)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	if (!delimiter) {
		ZEPHIR_INIT_VAR(&delimiter_zv);
	} else {
		zephir_memory_observe(&delimiter_zv);
	ZVAL_STR_COPY(&delimiter_zv, delimiter);
	}
	zephir_update_static_property_ce(phalcon_cli_router_route_ce, ZEND_STRL("delimiterPath"), &delimiter_zv);
	ZEPHIR_MM_RESTORE();
}

/**
 * Get routing delimiter
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getDelimiter)
{
	zval _0;

	ZVAL_UNDEF(&_0);
	zephir_read_static_property_ce(&_0, phalcon_cli_router_route_ce, SL("delimiterPath"), PH_NOISY_CC | PH_READONLY);
	RETURN_CTORW(&_0);
}

/**
 * Resets the internal route id generator.
 *
 * Intended for test isolation only. The router keys its route map by the
 * route id, so resetting the sequence while a router still holds routes
 * makes newly created routes overwrite existing entries.
 */
PHP_METHOD(Phalcon_Cli_Router_Route, reset)
{
	zval _0;

	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_0);
	ZVAL_LONG(&_0, 0);
	zephir_update_static_property_ce(phalcon_cli_router_route_ce, ZEND_STRL("uniqueId"), &_0);
}

/**
 * Sets a callback that is called if the route is matched.
 * The developer can implement any arbitrary conditions here
 * If the callback returns false the route is treated as not matched
 *
 * @param mixed callback
 */
PHP_METHOD(Phalcon_Cli_Router_Route, beforeMatch)
{
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval *callback, callback_sub, _0$$3, _1$$3;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&callback_sub);
	ZVAL_UNDEF(&_0$$3);
	ZVAL_UNDEF(&_1$$3);
	static zend_string *_zephir_prop_0 = NULL;
	static zend_string *_zephir_prop_1 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("pattern", 7, 1);
	}
	if (UNEXPECTED(!_zephir_prop_1)) {
		_zephir_prop_1 = zend_string_init("beforeMatch", 11, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_ZVAL(callback)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 0, &callback);
	if (UNEXPECTED(!(zephir_is_callable(callback)))) {
		ZEPHIR_INIT_VAR(&_0$$3);
		object_init_ex(&_0$$3, phalcon_cli_router_exceptions_beforematchnotcallable_ce);
		zephir_read_property_cached(&_1$$3, this_ptr, _zephir_prop_0, 515, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_CALL_METHOD(NULL, &_0$$3, "__construct", NULL, 458, &_1$$3);
		zephir_check_call_status();
		zephir_throw_exception_debug(&_0$$3, "phalcon/Cli/Router/Route.zep", 124);
		ZEPHIR_MM_RESTORE();
		return;
	}
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_1, 516, callback);
	RETURN_THIS();
}

/**
 * Replaces placeholders from pattern returning a valid PCRE regular
 * expression
 */
PHP_METHOD(Phalcon_Cli_Router_Route, compilePattern)
{
	zend_bool _20;
	zval map;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval *pattern_param = NULL, idPattern, _0$$3, _1$$3, _2$$3, _3$$3, _4$$3, _5$$3, _6$$3, _7$$3, _8$$3, _9$$3, _10$$3, _11$$3, _12$$3, _13$$3, _14$$3, _15$$3, _16$$3, _17$$3, _18$$3, _19$$3;
	zval pattern;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&pattern);
	ZVAL_UNDEF(&idPattern);
	ZVAL_UNDEF(&_0$$3);
	ZVAL_UNDEF(&_1$$3);
	ZVAL_UNDEF(&_2$$3);
	ZVAL_UNDEF(&_3$$3);
	ZVAL_UNDEF(&_4$$3);
	ZVAL_UNDEF(&_5$$3);
	ZVAL_UNDEF(&_6$$3);
	ZVAL_UNDEF(&_7$$3);
	ZVAL_UNDEF(&_8$$3);
	ZVAL_UNDEF(&_9$$3);
	ZVAL_UNDEF(&_10$$3);
	ZVAL_UNDEF(&_11$$3);
	ZVAL_UNDEF(&_12$$3);
	ZVAL_UNDEF(&_13$$3);
	ZVAL_UNDEF(&_14$$3);
	ZVAL_UNDEF(&_15$$3);
	ZVAL_UNDEF(&_16$$3);
	ZVAL_UNDEF(&_17$$3);
	ZVAL_UNDEF(&_18$$3);
	ZVAL_UNDEF(&_19$$3);
	ZVAL_UNDEF(&map);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("delimiter", 9, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_ZVAL(pattern_param)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 0, &pattern_param);
	zephir_get_strval(&pattern, pattern_param);
	if (zephir_memnstr_str(&pattern, SL(":"), "phalcon/Cli/Router/Route.zep", 142)) {
		zephir_read_property_cached(&_0$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&idPattern);
		ZEPHIR_CONCAT_VS(&idPattern, &_0$$3, "([a-zA-Z0-9\\_\\-]+)");
		ZEPHIR_INIT_VAR(&map);
		zephir_create_array(&map, 7, 0);
		zephir_memory_observe(&_1$$3);
		zephir_read_property_cached(&_1$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC);
		zephir_array_update_string(&map, SL(":delimiter"), &_1$$3, PH_COPY | PH_SEPARATE);
		zephir_read_property_cached(&_2$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_3$$3);
		ZEPHIR_CONCAT_VS(&_3$$3, &_2$$3, ":module");
		zephir_array_update_zval(&map, &_3$$3, &idPattern, PH_COPY);
		zephir_read_property_cached(&_4$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_5$$3);
		ZEPHIR_CONCAT_VS(&_5$$3, &_4$$3, ":task");
		zephir_array_update_zval(&map, &_5$$3, &idPattern, PH_COPY);
		zephir_read_property_cached(&_6$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_7$$3);
		ZEPHIR_CONCAT_VS(&_7$$3, &_6$$3, ":namespace");
		zephir_array_update_zval(&map, &_7$$3, &idPattern, PH_COPY);
		zephir_read_property_cached(&_8$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_9$$3);
		ZEPHIR_CONCAT_VS(&_9$$3, &_8$$3, ":action");
		zephir_array_update_zval(&map, &_9$$3, &idPattern, PH_COPY);
		zephir_read_property_cached(&_10$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_11$$3);
		ZEPHIR_CONCAT_VS(&_11$$3, &_10$$3, ":params");
		zephir_read_property_cached(&_12$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_13$$3);
		ZEPHIR_CONCAT_SVS(&_13$$3, "(", &_12$$3, ".*)?");
		zephir_array_update_zval(&map, &_11$$3, &_13$$3, PH_COPY);
		zephir_read_property_cached(&_14$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_NVAR(&_13$$3);
		ZEPHIR_CONCAT_VS(&_13$$3, &_14$$3, ":int");
		zephir_read_property_cached(&_15$$3, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
		ZEPHIR_INIT_VAR(&_16$$3);
		ZEPHIR_CONCAT_VS(&_16$$3, &_15$$3, "([0-9]+)");
		zephir_array_update_zval(&map, &_13$$3, &_16$$3, PH_COPY);
		ZEPHIR_INIT_VAR(&_17$$3);
		ZEPHIR_INIT_VAR(&_18$$3);
		zephir_array_keys(&_18$$3, &map);
		ZEPHIR_CALL_FUNCTION(&_19$$3, "array_values", NULL, 28, &map);
		zephir_check_call_status();
		zephir_fast_str_replace(&_17$$3, &_18$$3, &_19$$3, &pattern);
		zephir_get_strval(&pattern, &_17$$3);
	}
	_20 = zephir_memnstr_str(&pattern, SL("("), "phalcon/Cli/Router/Route.zep", 167);
	if (!(_20)) {
		_20 = zephir_memnstr_str(&pattern, SL("["), "phalcon/Cli/Router/Route.zep", 167);
	}
	if (_20) {
		ZEPHIR_CONCAT_SVS(return_value, "#^", &pattern, "$#");
		RETURN_MM();
	}
	RETURN_CTOR(&pattern);
}

/**
 * Adds a converter to perform an additional transformation for certain
 * parameter
 *
 * @param callable converter
 */
PHP_METHOD(Phalcon_Cli_Router_Route, convert)
{
	zval name_zv, *converter, converter_sub;
	zend_string *name = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&name_zv);
	ZVAL_UNDEF(&converter_sub);
	ZEND_PARSE_PARAMETERS_START(2, 2)
		Z_PARAM_STR(name)
		Z_PARAM_ZVAL(converter)
	ZEND_PARSE_PARAMETERS_END();
	converter = ZEND_CALL_ARG(execute_data, 2);
	ZVAL_STR(&name_zv, name);
	zephir_update_property_array(this_ptr, SL("converters"), &name_zv, converter);
	RETURN_THISW();
}

/**
 * Extracts parameters from a string
 *
 * @phpstan-return cli_route_extracted|false
 */
PHP_METHOD(Phalcon_Cli_Router_Route, extractNamedParams)
{
	long _0, _5$$10, _26$$18;
	zval route, item, variable, regexp, _4$$10, _21$$15, _24$$15, _27$$25, _30$$28;
	zend_long cursor = 0, cursorVar = 0, marker = 0, bracketCount, parenthesesCount, foundPattern, intermediate, numberMatches;
	zend_bool notValid = 0, _6$$11, _7$$11, _8$$11, _9$$11, _10$$11, _11$$11, _12$$11, _13$$11, _14$$11, _15$$11, _16$$11, _17$$11, _25$$17;
	zval matches;
	char ch = 0;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zval pattern_zv, tmp, _1$$10, _2$$10, _3$$10, _18$$15, _19$$15, _20$$15, _22$$15, _23$$15, _28$$27, _29$$27;
	zend_string *pattern = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&pattern_zv);
	ZVAL_UNDEF(&tmp);
	ZVAL_UNDEF(&_1$$10);
	ZVAL_UNDEF(&_2$$10);
	ZVAL_UNDEF(&_3$$10);
	ZVAL_UNDEF(&_18$$15);
	ZVAL_UNDEF(&_19$$15);
	ZVAL_UNDEF(&_20$$15);
	ZVAL_UNDEF(&_22$$15);
	ZVAL_UNDEF(&_23$$15);
	ZVAL_UNDEF(&_28$$27);
	ZVAL_UNDEF(&_29$$27);
	ZVAL_UNDEF(&matches);
	ZVAL_UNDEF(&route);
	ZVAL_UNDEF(&item);
	ZVAL_UNDEF(&variable);
	ZVAL_UNDEF(&regexp);
	ZVAL_UNDEF(&_4$$10);
	ZVAL_UNDEF(&_21$$15);
	ZVAL_UNDEF(&_24$$15);
	ZVAL_UNDEF(&_27$$25);
	ZVAL_UNDEF(&_30$$28);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("delimiter", 9, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_STR(pattern)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_memory_observe(&pattern_zv);
	ZVAL_STR_COPY(&pattern_zv, pattern);
	bracketCount = 0;
	parenthesesCount = 0;
	foundPattern = 0;
	intermediate = 0;
	numberMatches = 0;
	if (zephir_fast_strlen_ev(&pattern_zv) == 0) {
		RETURN_MM_BOOL(0);
	}
	ZEPHIR_INIT_VAR(&matches);
	array_init(&matches);
	ZEPHIR_INIT_VAR(&route);
	ZVAL_STRING(&route, "");
	for (_0 = 0; _0 < Z_STRLEN_P(&pattern_zv); _0++) {
		cursor = _0; 
		ch = ZEPHIR_STRING_OFFSET(&pattern_zv, _0);
		if (parenthesesCount == 0) {
			if (ch == '{') {
				if (bracketCount == 0) {
					marker = (cursor + 1);
					intermediate = 0;
					notValid = 0;
				}
				bracketCount++;
			} else if (ch == '}') {
				bracketCount--;
				if (intermediate > 0) {
					if (bracketCount == 0) {
						numberMatches++;
						ZEPHIR_INIT_NVAR(&variable);
						ZEPHIR_INIT_NVAR(&regexp);
						ZVAL_LONG(&_1$$10, marker);
						ZVAL_LONG(&_2$$10, (cursor - marker));
						ZEPHIR_INIT_NVAR(&_3$$10);
						zephir_substr(&_3$$10, &pattern_zv, zephir_get_intval(&_1$$10), zephir_get_intval(&_2$$10), 0);
						zephir_cast_to_string(&_4$$10, &_3$$10);
						ZEPHIR_CPY_WRT(&item, &_4$$10);
						for (_5$$10 = 0; _5$$10 < Z_STRLEN_P(&item); _5$$10++) {
							cursorVar = _5$$10; 
							ch = ZEPHIR_STRING_OFFSET(&item, _5$$10);
							if (ch == '\0') {
								break;
							}
							_6$$11 = cursorVar == 0;
							if (_6$$11) {
								_7$$11 = ch >= 'a';
								if (_7$$11) {
									_7$$11 = ch <= 'z';
								}
								_8$$11 = _7$$11;
								if (!(_8$$11)) {
									_9$$11 = ch >= 'A';
									if (_9$$11) {
										_9$$11 = ch <= 'Z';
									}
									_8$$11 = _9$$11;
								}
								_6$$11 = !(_8$$11);
							}
							if (_6$$11) {
								notValid = 1;
								break;
							}
							_10$$11 = ch >= 'a';
							if (_10$$11) {
								_10$$11 = ch <= 'z';
							}
							_11$$11 = _10$$11;
							if (!(_11$$11)) {
								_12$$11 = ch >= 'A';
								if (_12$$11) {
									_12$$11 = ch <= 'Z';
								}
								_11$$11 = _12$$11;
							}
							_13$$11 = _11$$11;
							if (!(_13$$11)) {
								_14$$11 = ch >= '0';
								if (_14$$11) {
									_14$$11 = ch <= '9';
								}
								_13$$11 = _14$$11;
							}
							_15$$11 = _13$$11;
							if (!(_15$$11)) {
								_15$$11 = ch == '-';
							}
							_16$$11 = _15$$11;
							if (!(_16$$11)) {
								_16$$11 = ch == '_';
							}
							_17$$11 = _16$$11;
							if (!(_17$$11)) {
								_17$$11 = ch == ':';
							}
							if (_17$$11) {
								if (ch == ':') {
									ZVAL_LONG(&_18$$15, 0);
									ZVAL_LONG(&_19$$15, cursorVar);
									ZEPHIR_INIT_NVAR(&_20$$15);
									zephir_substr(&_20$$15, &item, 0 , zephir_get_intval(&_19$$15), 0);
									zephir_cast_to_string(&_21$$15, &_20$$15);
									ZEPHIR_CPY_WRT(&variable, &_21$$15);
									ZVAL_LONG(&_22$$15, (cursorVar + 1));
									ZEPHIR_INIT_NVAR(&_23$$15);
									zephir_substr(&_23$$15, &item, zephir_get_intval(&_22$$15), 0, ZEPHIR_SUBSTR_NO_LENGTH);
									zephir_cast_to_string(&_24$$15, &_23$$15);
									ZEPHIR_CPY_WRT(&regexp, &_24$$15);
									break;
								}
							} else {
								notValid = 1;
								break;
							}
						}
						if (!(notValid)) {
							ZEPHIR_INIT_NVAR(&tmp);
							ZVAL_LONG(&tmp, numberMatches);
							_25$$17 = zephir_is_true(&variable);
							if (_25$$17) {
								_25$$17 = zephir_is_true(&regexp);
							}
							if (_25$$17) {
								foundPattern = 0;
								for (_26$$18 = 0; _26$$18 < Z_STRLEN_P(&regexp); _26$$18++) {
									ch = ZEPHIR_STRING_OFFSET(&regexp, _26$$18);
									if (ch == '\0') {
										break;
									}
									if (!(foundPattern)) {
										if (ch == '(') {
											foundPattern = 1;
										}
									} else {
										if (ch == ')') {
											foundPattern = 2;
											break;
										}
									}
								}
								if (foundPattern != 2) {
									ZEPHIR_INIT_NVAR(&_27$$25);
									ZEPHIR_CONCAT_SVS(&_27$$25, "(", &regexp, ")");
									zephir_concat_self(&route, &_27$$25);
								} else {
									zephir_concat_self(&route, &regexp);
								}
								zephir_array_update_zval(&matches, &variable, &tmp, PH_COPY | PH_SEPARATE);
							} else {
								zephir_read_property_cached(&_28$$27, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
								ZEPHIR_INIT_NVAR(&_29$$27);
								ZEPHIR_CONCAT_SVS(&_29$$27, "([^", &_28$$27, "]*)");
								zephir_concat_self(&route, &_29$$27);
								zephir_array_update_zval(&matches, &item, &tmp, PH_COPY | PH_SEPARATE);
							}
						} else {
							ZEPHIR_INIT_NVAR(&_30$$28);
							ZEPHIR_CONCAT_SVS(&_30$$28, "{", &item, "}");
							zephir_concat_self(&route, &_30$$28);
						}
						continue;
					}
				}
			}
		}
		if (bracketCount == 0) {
			if (ch == '(') {
				parenthesesCount++;
			} else if (ch == ')') {
				parenthesesCount--;
				if (parenthesesCount == 0) {
					numberMatches++;
				}
			}
		}
		if (bracketCount > 0) {
			intermediate++;
		} else {
			zephir_concat_self_char(&route, ch);
		}
	}
	zephir_create_array(return_value, 2, 0);
	zephir_array_fast_append(return_value, &route);
	zephir_array_fast_append(return_value, &matches);
	RETURN_MM();
}

/**
 * Returns the 'before match' callback if any
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getBeforeMatch)
{

	RETURN_MEMBER(getThis(), "beforeMatch");
}

/**
 * Returns the route's compiled pattern
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getCompiledPattern)
{

	RETURN_MEMBER_TYPED(getThis(), "compiledPattern", IS_STRING);
}

/**
 * Returns the router converter
 *
 * @phpstan-return cli_route_converters
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getConverters)
{

	RETURN_MEMBER_TYPED(getThis(), "converters", IS_ARRAY);
}

/**
 * Returns the route's description
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getDescription)
{

	RETURN_MEMBER_TYPED(getThis(), "description", IS_STRING);
}

/**
 * Returns the route's name
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getName)
{

	RETURN_MEMBER_TYPED(getThis(), "name", IS_STRING);
}

/**
 * Returns the paths
 *
 * @phpstan-return cli_route_paths
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getPaths)
{

	RETURN_MEMBER_TYPED(getThis(), "paths", IS_ARRAY);
}

/**
 * Returns the route's pattern
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getPattern)
{

	RETURN_MEMBER_TYPED(getThis(), "pattern", IS_STRING);
}

/**
 * Returns the paths using positions as keys and names as values
 *
 * @phpstan-return cli_route_reversed_paths
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getReversedPaths)
{
	zval _0;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&_0);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("paths", 5, 1);
	}
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);

	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 517, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_RETURN_CALL_FUNCTION("array_flip", NULL, 263, &_0);
	zephir_check_call_status();
	RETURN_MM();
}

/**
 * Returns the route's id
 */
PHP_METHOD(Phalcon_Cli_Router_Route, getRouteId)
{

	RETURN_MEMBER_TYPED(getThis(), "routeId", IS_STRING);
}

/**
 * Reconfigure the route adding a new pattern and a set of paths
 *
 * @param array|string|null paths
 */
PHP_METHOD(Phalcon_Cli_Router_Route, reConfigure)
{
	zend_bool _1$$10;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS, _0$$4;
	zval *pattern_param = NULL, *paths = NULL, paths_sub, __$null, moduleName, taskName, actionName, parts, routePaths, realClassName, namespaceName, pcrePattern, compiledPattern, extracted, _2$$11, _3$$9, _4$$16, _5$$18, _6$$18, _7$$21, _8$$21, _9$$21;
	zval pattern;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&pattern);
	ZVAL_UNDEF(&paths_sub);
	ZVAL_NULL(&__$null);
	ZVAL_UNDEF(&moduleName);
	ZVAL_UNDEF(&taskName);
	ZVAL_UNDEF(&actionName);
	ZVAL_UNDEF(&parts);
	ZVAL_UNDEF(&routePaths);
	ZVAL_UNDEF(&realClassName);
	ZVAL_UNDEF(&namespaceName);
	ZVAL_UNDEF(&pcrePattern);
	ZVAL_UNDEF(&compiledPattern);
	ZVAL_UNDEF(&extracted);
	ZVAL_UNDEF(&_2$$11);
	ZVAL_UNDEF(&_3$$9);
	ZVAL_UNDEF(&_4$$16);
	ZVAL_UNDEF(&_5$$18);
	ZVAL_UNDEF(&_6$$18);
	ZVAL_UNDEF(&_7$$21);
	ZVAL_UNDEF(&_8$$21);
	ZVAL_UNDEF(&_9$$21);
	static zend_string *_zephir_prop_0 = NULL;
	static zend_string *_zephir_prop_1 = NULL;
	static zend_string *_zephir_prop_2 = NULL;
	static zend_string *_zephir_prop_3 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("delimiter", 9, 1);
	}
	if (UNEXPECTED(!_zephir_prop_1)) {
		_zephir_prop_1 = zend_string_init("pattern", 7, 1);
	}
	if (UNEXPECTED(!_zephir_prop_2)) {
		_zephir_prop_2 = zend_string_init("compiledPattern", 15, 1);
	}
	if (UNEXPECTED(!_zephir_prop_3)) {
		_zephir_prop_3 = zend_string_init("paths", 5, 1);
	}

	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(1, 2)
		Z_PARAM_ZVAL(pattern_param)
		Z_PARAM_OPTIONAL
		Z_PARAM_ZVAL_OR_NULL(paths)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 1, &pattern_param, &paths);
	zephir_get_strval(&pattern, pattern_param);
	if (!paths) {
		paths = &paths_sub;
		ZEPHIR_CPY_WRT(paths, &__$null);
	} else {
		ZEPHIR_SEPARATE_PARAM(paths);
	}
	if (Z_TYPE_P(paths) == IS_NULL) {
		ZEPHIR_INIT_NVAR(paths);
		array_init(paths);
	}
	if (Z_TYPE_P(paths) == IS_STRING) {
		ZEPHIR_INIT_VAR(&moduleName);
		ZVAL_NULL(&moduleName);
		ZEPHIR_INIT_VAR(&taskName);
		ZVAL_NULL(&taskName);
		ZEPHIR_INIT_VAR(&actionName);
		ZVAL_NULL(&actionName);
		ZEPHIR_INIT_VAR(&parts);
		zephir_fast_explode_str(&parts, SL("::"), paths, LONG_MAX);
		_0$$4 = zephir_fast_count_int(&parts);
		if (_0$$4 == 3) { goto zephir_switch_0_clause_0; }
		if (_0$$4 == 2) { goto zephir_switch_0_clause_1; }
		if (_0$$4 == 1) { goto zephir_switch_0_clause_2; }
		goto zephir_switch_0_end;
		zephir_switch_0_clause_0: ;
			ZEPHIR_OBS_NVAR(&moduleName);
			zephir_array_fetch_long(&moduleName, &parts, 0, PH_NOISY, "phalcon/Cli/Router/Route.zep", 427);
			ZEPHIR_OBS_NVAR(&taskName);
			zephir_array_fetch_long(&taskName, &parts, 1, PH_NOISY, "phalcon/Cli/Router/Route.zep", 428);
			ZEPHIR_OBS_NVAR(&actionName);
			zephir_array_fetch_long(&actionName, &parts, 2, PH_NOISY, "phalcon/Cli/Router/Route.zep", 429);
			goto zephir_switch_0_end;
		zephir_switch_0_clause_1: ;
			ZEPHIR_OBS_NVAR(&taskName);
			zephir_array_fetch_long(&taskName, &parts, 0, PH_NOISY, "phalcon/Cli/Router/Route.zep", 433);
			ZEPHIR_OBS_NVAR(&actionName);
			zephir_array_fetch_long(&actionName, &parts, 1, PH_NOISY, "phalcon/Cli/Router/Route.zep", 434);
			goto zephir_switch_0_end;
		zephir_switch_0_clause_2: ;
			ZEPHIR_OBS_NVAR(&taskName);
			zephir_array_fetch_long(&taskName, &parts, 0, PH_NOISY, "phalcon/Cli/Router/Route.zep", 438);
			goto zephir_switch_0_end;
		zephir_switch_0_end: ;

		ZEPHIR_INIT_VAR(&routePaths);
		array_init(&routePaths);
		if (Z_TYPE_P(&moduleName) != IS_NULL) {
			zephir_array_update_string(&routePaths, SL("module"), &moduleName, PH_COPY | PH_SEPARATE);
		}
		if (Z_TYPE_P(&taskName) != IS_NULL) {
			if (zephir_memnstr_str(&taskName, SL("\\"), "phalcon/Cli/Router/Route.zep", 452)) {
				ZEPHIR_INIT_VAR(&realClassName);
				zephir_get_class_ns(&realClassName, &taskName, 0);
				ZEPHIR_INIT_VAR(&namespaceName);
				zephir_get_ns_class(&namespaceName, &taskName, 0);
				_1$$10 = Z_TYPE_P(&namespaceName) == IS_NULL;
				if (!(_1$$10)) {
					_1$$10 = Z_TYPE_P(&realClassName) == IS_NULL;
				}
				if (UNEXPECTED(_1$$10)) {
					ZEPHIR_INIT_VAR(&_2$$11);
					object_init_ex(&_2$$11, phalcon_cli_router_exceptions_invalidroutepaths_ce);
					ZEPHIR_CALL_METHOD(NULL, &_2$$11, "__construct", NULL, 459, &pattern);
					zephir_check_call_status();
					zephir_throw_exception_debug(&_2$$11, "phalcon/Cli/Router/Route.zep", 460);
					ZEPHIR_MM_RESTORE();
					return;
				}
				if (zephir_is_true(&namespaceName)) {
					zephir_array_update_string(&routePaths, SL("namespace"), &namespaceName, PH_COPY | PH_SEPARATE);
				}
			} else {
				ZEPHIR_CPY_WRT(&realClassName, &taskName);
			}
			ZEPHIR_INIT_VAR(&_3$$9);
			zephir_uncamelize(&_3$$9, &realClassName, NULL );
			zephir_array_update_string(&routePaths, SL("task"), &_3$$9, PH_COPY | PH_SEPARATE);
		}
		if (Z_TYPE_P(&actionName) != IS_NULL) {
			zephir_array_update_string(&routePaths, SL("action"), &actionName, PH_COPY | PH_SEPARATE);
		}
	} else {
		ZEPHIR_CPY_WRT(&routePaths, paths);
	}
	if (UNEXPECTED(Z_TYPE_P(&routePaths) != IS_ARRAY)) {
		ZEPHIR_INIT_VAR(&_4$$16);
		object_init_ex(&_4$$16, phalcon_cli_router_exceptions_invalidroutepaths_ce);
		ZEPHIR_CALL_METHOD(NULL, &_4$$16, "__construct", NULL, 459, &pattern);
		zephir_check_call_status();
		zephir_throw_exception_debug(&_4$$16, "phalcon/Cli/Router/Route.zep", 484);
		ZEPHIR_MM_RESTORE();
		return;
	}
	if (!(zephir_start_with_str(&pattern, SL("#")))) {
		if (zephir_memnstr_str(&pattern, SL("{"), "phalcon/Cli/Router/Route.zep", 492)) {
			ZEPHIR_CALL_METHOD(&extracted, this_ptr, "extractnamedparams", NULL, 0, &pattern);
			zephir_check_call_status();
			zephir_memory_observe(&pcrePattern);
			zephir_array_fetch_long(&pcrePattern, &extracted, 0, PH_NOISY, "phalcon/Cli/Router/Route.zep", 497);
			ZEPHIR_INIT_VAR(&_5$$18);
			zephir_array_fetch_long(&_6$$18, &extracted, 1, PH_NOISY | PH_READONLY, "phalcon/Cli/Router/Route.zep", 498);
			zephir_fast_array_merge(&_5$$18, &routePaths, &_6$$18);
			ZEPHIR_CPY_WRT(&routePaths, &_5$$18);
		} else {
			ZEPHIR_CPY_WRT(&pcrePattern, &pattern);
		}
		ZEPHIR_CALL_METHOD(&compiledPattern, this_ptr, "compilepattern", NULL, 0, &pcrePattern);
		zephir_check_call_status();
	} else {
		if (zephir_memnstr_str(&pattern, SL(":delimiter"), "phalcon/Cli/Router/Route.zep", 509)) {
			ZEPHIR_INIT_VAR(&_7$$21);
			zephir_read_property_cached(&_8$$21, this_ptr, _zephir_prop_0, 513, PH_NOISY_CC | PH_READONLY);
			ZEPHIR_INIT_VAR(&_9$$21);
			ZVAL_STRING(&_9$$21, ":delimiter");
			zephir_fast_str_replace(&_7$$21, &_9$$21, &_8$$21, &pattern);
			zephir_get_strval(&pattern, &_7$$21);
		}
		ZEPHIR_CPY_WRT(&compiledPattern, &pattern);
	}
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_1, 515, &pattern);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_2, 518, &compiledPattern);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_3, 517, &routePaths);
	ZEPHIR_MM_RESTORE();
}

/**
 * Sets the route's description
 */
PHP_METHOD(Phalcon_Cli_Router_Route, setDescription)
{
	zval description_zv;
	zend_string *description = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&description_zv);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("description", 11, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_STR(description)
	ZEND_PARSE_PARAMETERS_END();
	ZVAL_STR(&description_zv, description);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 519, &description_zv);
	RETURN_THISW();
}

/**
 * Sets the route's name
 *
 *```php
 * $router->add(
 *     "/about",
 *     [
 *         "controller" => "about",
 *     ]
 * )->setName("about");
 *```
 */
PHP_METHOD(Phalcon_Cli_Router_Route, setName)
{
	zval name_zv;
	zend_string *name = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&name_zv);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("name", 4, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_STR(name)
	ZEND_PARSE_PARAMETERS_END();
	ZVAL_STR(&name_zv, name);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 520, &name_zv);
	RETURN_THISW();
}

