#include"mkf_book.hpp"
#include"mkf_identifier.hpp"
#include"mkf_group.hpp"
#include"mkf_book.hpp"




bool
Book::
compare(CompareContext&  ctx, const Element*  elm) const
{
    switch(elm->get_kind())
    {
      case(ElementKind::null):
        report;
        break;
      case(ElementKind::character):
          if(elm->get_character() == *ctx.p0)
          {
            int  c = *ctx.p0++;

              if(ctx.nd)
              {
                ctx.nd->character = c;
              }


            return true;
          }
        break;
      case(ElementKind::identifier):
        {
          auto  def = find(elm->get_identifier());

            if(def)
            {
              auto  p = ctx.p0;

              CompareContext  subctx(p,ctx.p1,new Node(def));

                if(compare(subctx,*def))
                {
                  ctx.p0 = p;

                  ctx.nd->append(subctx.nd);


                  return true;
                }


              delete subctx.nd;
            }

          else
            {
              report;
              printf("definition [%s] is not found.\n",elm->get_identifier().get_buffer());
              printf("%s.\n",ctx.p0);
            }
        }
        break;
      case(ElementKind::group):
        {
          auto&  grp = elm->get_group();

          auto  p = ctx.p0;

          CompareContext  subctx(p,ctx.p1,new Node);

            if(compare(subctx,grp))
            {
              ctx.p0 = p;

              ctx.nd->append(subctx.nd);


              return true;
            }


          delete subctx.nd;
        }
        break;
      default:
        report;
    }


  return false;
}


bool
Book::
compare(CompareContext&  ctx, const Group&  grp) const
{
  auto&  blocks = grp.get_list();

    if(blocks.empty())
    {
      return true;
    }


  const char*  last_p = ctx.p0;

    for(auto&  blk: blocks)
    {
        if(ctx.p0 >= ctx.p1)
        {
          return false;
        }


        if(blk.separator == '|')
        {
            if(!compare_for_any(ctx,blk))
            {
              return false;
            }


            if(ctx.p0 == last_p)
            {
              report;
              printf("**looping**\n");
              return false;
            }
        }

      else
        if(blk.separator == ',')
        {
            if(!compare_for_all(ctx,blk))
            {
              return false;
            }


            if(ctx.p0 == last_p)
            {
              report;
              printf("**looping**\n");
              return false;
            }
        }

      else
        {
            if(!compare_for_all(ctx,blk))
            {
              return false;
            }

          break;
        }
    }


  return true;
}




bool
Book::
compare_for_any(CompareContext&  ctx, const Block&  blk) const
{
    for(auto&  elm: blk.elements)
    {
        if(compare(ctx,&elm))
        {
            if(elm.test_repeat())
            {
                for(;;)
                {
                    if(!compare(ctx,&elm))
                    {
                      break;
                    }
                }
            }


          return true;
        }
    }


  return false;
}


bool
Book::
compare_for_all(CompareContext&  ctx, const Block&  blk) const
{
    for(auto&  elm: blk.elements)
    {
        if(ctx.p0 >= ctx.p1)
        {
          return false;
        }


        if(!compare(ctx,&elm))
        {
            if(elm.test_omittable())
            {
              continue;
            }


          return false;
        }


          if(elm.test_repeat())
          {
              for(;;)
              {
                  if(!compare(ctx,&elm))
                  {
                    break;
                  }
              }
          }
    }


  return true;
}




