#ifndef EINTERPRET_ATOM_H
#define EINTERPRET_ATOM_H

#include <typeinfo>
using namespace std;

#undef check

struct stopExecutionStruct {
  bool flag;
  estr error;
  int line;
  stopExecutionStruct(): flag(false),line(-1) {}
};

class eatom_base
{
 public:
  int type;
  bool evald;
  estr exechost;
  unsigned int remote;

  int line;

//  bool internal;
  evar rvalue;
  ebasicarray<eatom_base*> args;
  eatom_base(int type);
  virtual ~eatom_base();
  virtual evar& make(estrhashof<evar>& env,stopExecutionStruct& stopExecution)=0;
  virtual const type_info& check(estrhashof<evar>& env,stopExecutionStruct& stopExecution)=0;
  virtual void clear()=0;
  virtual void print(estr& s)=0;
  virtual void serial(estrhashof<evar>& env,estr& data)=0;
  virtual size_t unserial(const estr& data,size_t pi)=0;
  void remoteExecute(estrhashof<evar>& env);
  void setRemote();
};

class eatom_value : public eatom_base
{
 public:
  estr value;
  bool constant;
  evar& make(estrhashof<evar>& env,stopExecutionStruct& stopExecution);
  const type_info& check(estrhashof<evar>& env,stopExecutionStruct& stopExecution);

  void print(estr& s);
  void clear();

  eatom_value(): eatom_base(2),constant(false) {}
  eatom_value(const estr& str);

  void serial(estrhashof<evar>& env,estr& data);
  size_t unserial(const estr& data,size_t ip);
};

class eatom;

typedef void (*epop_f)(eatom*,evar&,estrhashof<evar>&,stopExecutionStruct&,const estr& name,ebasicarray<eatom_base*>&,evararray&);

class eatom : public eatom_base
{
 public:
  estr name;
  evararray vargs;
  epop_f fcall;
  efunc *efcall;
  eclassMethodBase *mcall;

  evar& make(estrhashof<evar>& env,stopExecutionStruct& stopExecution);
  const type_info& check(estrhashof<evar>& env,stopExecutionStruct& stopExecution);
  void print(estr& s);
  void clear();

  eatom(): eatom_base(1),efcall(0x00),mcall(0x00) {}
  eatom(const estrarray& strarr);

  void serial(estrhashof<evar>& env,estr& data);
  size_t unserial(const estr& data,size_t i);
};


enum catype{CA_CODE,CA_BLOCK,CA_ARG,CA_NUM,CA_STR,CA_SINGLE,CA_FOR,CA_IF,CA_WHILE,CA_DO,CA_FUNCTION,CA_CONTINUE,CA_BREAK,CA_RETURN};

class ecodeParser;


class ecodeAtom
{
 public:
  catype type;
  estr text;
  int line;
  
  virtual estr check(estrhashof<evar>& env,stopExecutionStruct& stopExecution) {return(estr()); }
  virtual evar interpret(estrhashof<evar>& env,stopExecutionStruct& stopExecution,int& loopControl)=0;
  virtual ~ecodeAtom() {}
  virtual void serial(estrhashof<evar>& env,estr& data)=0;
  virtual size_t unserial(const estr& data,size_t i)=0;
};

class ecodeAtomBlock : public ecodeAtom
{
 public:
  estr exechost;
  estr code;
  ebasicarray<ecodeAtom*> exec;

  ~ecodeAtomBlock();

  void clear();
  virtual estr check(estrhashof<evar>& env,stopExecutionStruct& stopExecution);
  virtual evar interpret(estrhashof<evar>& env,stopExecutionStruct& stopExecution,int& loopControl);
  void parse(ecodeParser& cparser,const estr& str);
  void serial(estrhashof<evar>& env,estr& data);
  size_t unserial(const estr& data,size_t i);
};


class ecodeParser
{
 public:
  int error;

  ecodeParser();

  void getcontrolstr(const estr&,long&,int&,estr&); 
  ecodeAtom *getcodeifatom(const estr&,long&,int&);
  ecodeAtom *getcodeforatom(const estr&,long&,int&);
  ecodeAtom *getcodewhileatom(const estr&,long&,int&);
  ecodeAtom *getcodedoatom(const estr&,long&,int&);
  ecodeAtom *getsingleatom(const estr&,long&,int&);
  ecodeAtom *getcodeatom(const estr& str,long& ind,int&);
  ecodeAtom *getcodefunctionatom(const estr& str,long& ind,int&);

  ecodeAtom *getargatom(const estr& str,long& ind,int&);
  ecodeAtomBlock *getblockatom(const estr& str,long& ind,int&);

  ecodeAtom *getatom(const estr& str,long& ind,int&);

  ecodeAtomBlock *parse(const estr& code);
  earray<estr> autocomplete(estr& line,estrhashof<evar>& env);
  void setError(int errcode);
};

const int CP_ERROR_NONE=0;
const int CP_ERROR_MISSING_PARENTESIS=1;
const int CP_ERROR_MISSING_IF_ARG=2;
const int CP_ERROR_WRONG_IF_ARG=3;
const int CP_ERROR_MISSING_IF_EXEC=4;
const int CP_ERROR_WRONG_IF_EXEC=5;
const int CP_ERROR_MISSING_ELSE_EXEC=6;
const int CP_ERROR_WRONG_ELSE_EXEC=7; 
const int CP_ERROR_MISSING_FOR_ARG=8;
const int CP_ERROR_WRONG_FOR_ARG=9;


size_t unserialCodeAtom(ecodeAtom* &catom,const estr& data,size_t ip);


#endif

