// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      struct remove_state
      {
         template< typename Rule,
                   apply_mode A,
                   rewind_mode M,
                   template< typename... >
                   class Action,
                   template< typename... >
                   class Control,
                   typename Input,
                   typename... States >
         static bool match( Input& in, States&&... /*unused*/ )
         {
            return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in );
         }
      };

      // further generic helpers could be build, e.g.
      //
      // - change_control
      // - remove prefix/suffix from input (e.g. remove surrounding quotes)
      // - replace the input completely?
      // - append states
      // - prepend states
      // - ...

      std::size_t global_state = 0;

      struct state_one
      {
         std::size_t byte_in_line_a;
         std::size_t byte_in_line_b;
      };

      // clang-format off
      struct grammar_inner : one< 'a' > {};
      struct grammar_one_c : seq< grammar_inner > {};
      struct grammar_one_b : seq< grammar_inner, grammar_one_c > {};
      struct grammar_one_a : seq< grammar_inner, grammar_one_b, eof > {};
      // clang-format on

      template< typename Rule >
      struct action_one_b
      {};

      template< typename Rule >
      struct action_one_t
      {};

      template< typename Rule >
      struct action_one_a
      {};

      template<>
      struct action_one_b< grammar_one_c >
         : remove_state
      {};

      template<>
      struct action_one_b< grammar_inner >
      {
         // used inside of remove_state
         template< typename Input >
         static void apply( const Input& /*unused*/ )
         {
            ++global_state;
         }

         // used outside of remove_state
         template< typename Input >
         static void apply( const Input& in, state_one& state )
         {
            state.byte_in_line_b += in.input().byte();
         }
      };

      template<>
      struct action_one_t< grammar_one_b >
         : change_action< action_one_b >
      {};

      template<>
      struct action_one_a< grammar_one_b >
         : change_action< action_one_t >
      {};

      template<>
      struct action_one_a< grammar_inner >
      {
         template< typename Input >
         static void apply( const Input& in, state_one& state )
         {
            state.byte_in_line_a += in.input().byte();
         }
      };

      void unit_test()
      {
         state_one state{ 0, 0 };
         bool parse_result = parse< grammar_one_a, action_one_a >( memory_input<>( "aaa", __FUNCTION__ ), state );
         TAO_PEGTL_TEST_ASSERT( parse_result );
         TAO_PEGTL_TEST_ASSERT( state.byte_in_line_a == 1 );
         TAO_PEGTL_TEST_ASSERT( state.byte_in_line_b == 2 );
         TAO_PEGTL_TEST_ASSERT( global_state == 1 );
      }

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#include "main.hpp"
