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




constexpr int  shift_amount = 4;


Element::Element():
state(0),
ptr(nullptr)
{
}


Element::
Element(uint32_t  flags, int  chr_):
state((static_cast<int>(ElementKind::character)<<shift_amount)|flags),
chr(chr_)
{
}


Element::
Element(uint32_t  flags, const char*  id_):
state((static_cast<int>(ElementKind::identifier)<<shift_amount)|flags),
id(new Identifier(id_))
{
}


Element::
Element(uint32_t  flags, Identifier*  id_):
state((static_cast<int>(ElementKind::identifier)<<shift_amount)|flags),
id(id_)
{
}


Element::
Element(uint32_t  flags, Group*   grp_):
state((static_cast<int>(ElementKind::group)<<shift_amount)|flags),
grp(grp_)
{
}


Element::
Element(const Element&  rhs)
{
  *this = rhs;
}


Element::
Element(Element&&  rhs)
{
  *this = std::move(rhs);
}


Element::
~Element()
{
  clear();
}




Element&
Element::
operator=(const Element&  rhs)
{
  state = rhs.state;

    switch(get_kind())
    {
      case(ElementKind::null):
        break;
      case(ElementKind::character):
        chr = rhs.chr;
        break;
      case(ElementKind::identifier):
        id = new Identifier(*rhs.id);
        break;
      case(ElementKind::group):
        grp = new Group(*rhs.grp);
        break;
      default:
        printf("Element assignment error");
    }


  return *this;
}


Element&
Element::
operator=(Element&&  rhs)
{
  state = rhs.state    ;
          rhs.state = 0;

  ptr = rhs.ptr          ;
        rhs.ptr = nullptr;

  return *this;
}


void
Element::
clear()
{
    switch(get_kind())
    {
      case(ElementKind::null):
      case(ElementKind::character):
        break;
      case(ElementKind::identifier):
        delete id;
        break;
      case(ElementKind::group):
        delete grp;
        break;
      default:
        printf("Element clear error");
    }


  state = 0;
  ptr   = nullptr;
}


ElementKind  Element::get_kind() const{return static_cast<ElementKind>(state>>shift_amount);}

const Identifier&  Element::get_identifier() const{return *id;}
const Group&            Element::get_group() const{return *grp;}
int                 Element::get_character() const{return chr;}

bool  Element::test_omittable() const{return(state&ElementFlag::omittable);}
bool  Element::test_repeat() const{return(state&ElementFlag::repeat);}


void
Element::
print() const
{
    if(test_omittable())
    {
      printf("?");
    }


    if(test_repeat())
    {
      printf("*");
    }


    switch(get_kind())
    {
      case(ElementKind::null):
        printf("(null)");
        break;
      case(ElementKind::character):
        printf("\'%c\'",chr);
        break;
      case(ElementKind::identifier):
        printf("%s",id->get_buffer());
        break;
      case(ElementKind::group):
        printf("(");

        grp->print();

        printf(")");
        break;
      default:
        printf("(unknown)");
    }
}




