Se me ocurre, con lo dicho antes, que si al ejecutar un click cuando la pila está vacía, puedo olvidarme de retornar el ActionResult y devolver un metadata para apilar/desapilar. La interfaz del execute del action quedaría como sigue:
execute(Model, Metadata)
El controlador instanciará un metadata que le pasará al execute.
undo(Model, Metadata)
El controlador tomará el tope de la pila y se lo pasará al undo.
A la vuelta del execute, el valor ese que llamaba ActionResult irá en el metadata. Podrá tener un valor de entre estos que se me pasan ahora por la mocha:
EXECUTE
WAIT
ABORT
El primero hará que el controlador apile el metadata y lance la acción que se cita en él.
El segundo apilará el metadata y devolverá el control a los eventos de usuario dejando la siguiente acción a ejecutar pendiente de un evento.
El abort deshará la pila ejecutando los métodos undo de las acciones que lo soporten.
Así, la primera vez que se ejecuta el click con la pila vacía, tendremos que ejecutar ClickCommand. Cuando tengamos apilado, por ejemplo, MoveCommand, esperamos que la entrada sea un lugar alcanzable por el peón que el usuario quiera desplazar. El controlador, en lugar del click normal, tendrá que ver si puede ejecutar MoveCommand en su lugar.
La cosa va mejoranding... Aunque salen problemas, alguno veo, al menos:
El controlador deberá preparar el metadata del click, drag y toda la pesca para que el click no se apile, a ver si me explico: crea el metadata para el click y lo ejecuta. Al inicio de la ejecución del comando sigue sin haber nada en la pila y será después cuando se haga el push.
Con eso evito un push sobre la pila cuando haya un comando pendiente pero, si se hace el push del ClickCommand, ¿cuándo se ejecuta el MoveCommand que dejamos antes ahí? ¡No podemos olvidar que el Click debería convertir las unidades de pantalla al mundo para la siguiente acción!
voy a ver algo de los monty python... mañana sigo...