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




Group::
Group()
{
}


Group::
Group(const char*&  p, int  close)
{
  scan(p,close);
}


Group::
Group(const Group&   rhs):
blocks(rhs.blocks)
{
}


Group::
Group(Group&&  rhs):
blocks(std::move(rhs.blocks))
{
}




namespace{
Element
scan_character(uint32_t  flags, const char*&  p)
{
  int  c = *p++;

    if(c == '\\')
    {
      c = *p++;

        switch(c)
        {
          case('0'): c = '\0';break;
          case('n'): c = '\n';break;
          case('t'): c = '\t';break;
        }
    }


    if(*p != '\'')
    {
      printf("**%2d\n",*p);
      printf("**%s\n",p);
      report;
    }


  ++p;

  return Element(flags,c);
}


Element
scan_identifier(uint32_t  flags, const char*&  p)
{
  auto  id = new Identifier(p);

  p += id->get_length();

  return Element(flags,id);
}
}




namespace{
uint32_t
read_flags(const char*&  p)
{
  uint32_t  flags = 0;

    for(;;)
    {
           if(*p == '?'){flags |= ElementFlag::omittable;}
      else if(*p == '*'){flags |= ElementFlag::repeat   ;}
      else
        {
          break;
        }


      ++p;
    }


  return flags;
}
}


void
Group::
scan(const char*&  p, int  close)
{
  const char*  last = nullptr;

    for(;;)
    {
      skip_space(p);

      uint32_t  flags = read_flags(p);

      skip_space(p);

      Element  el;

        switch(*p)
        {
          case('(' ): el = Element(flags,new Group(++p,')'));break;
          case('\''): el = scan_character(flags,++p);break;
          default:
              if(isalnum(*p) || (*p == '_'))
              {
                el = scan_identifier(flags,p);
              }

            else
              {
                report;
                printf("**%c**\n",*p);
              }
        }


      skip_space(p);

      auto  c = *p++;

      append(std::move(el),c);

        if(c == close)
        {
          break;
        }


        if(last == p)
        {
          report;
          printf("**loop**%s",p);
          break;
        }


      last = p;
    }
}


void
Group::
clear()
{
  blocks.clear();
}


void
Group::
append(Element&&  el, int  sep)
{
    if(blocks.empty())
    {
      blocks.emplace_back(sep);

      blocks.back().elements.emplace_back(std::move(el));
    }

  else
    {
      auto&  blk = blocks.back();

      blk.elements.emplace_back(std::move(el));

        if((blk.separator != ',') ||
           (blk.separator != '|'))
        {
        }

      else
        if(blk.separator != sep)
        {
          blocks.emplace_back(sep);
        }
    }
}


const BlockList&
Group::
get_list() const
{
  return blocks;
}




void
Group::
print() const
{
    for(auto&  blk: blocks)
    {
        if(blk.elements.size())
        {
          auto   it = blk.elements.cbegin();
          auto  end = blk.elements.cend();

          it->print();

          ++it;

            while(it != end)
            {
              printf("%c",blk.separator);

              it->print();

              ++it;
            }
        }
    }
}




