#ifndef TOKENIZERLOCAL
#define TOKENIZERLOCAL

#include <tokenizer.h>

/*!
\brief Primitive tag parser, supporting reading and writing.   
The parser generally looks at the local scope.

Attributes <sometag hell="true"> not supported.
 However they could be pre-processed into strict tags.

Use scope() to find matching tags once they have been atomized.
 Combinations of scope and others are then possible. e.g.
 scope and erasetag. 

atomize(tag) create scoped tags. The scope search can
 be bounded by setting iend. e.g. Search in a scoped
 region for a sub scope.
*/
class tokenizerlocal
{
  /** Avoid infinite loop. */
  static long int countermax;
public:

  /** Reference. */
  tokenizer& ref;

  /** If no parent global scope. */
  tokenizerlocal* parent;

  /** Point to first tag or before. */
  liststringi i1;
  /** Point to second. */
  liststringi i2;
  /** End boundary of linear search. */
  liststringi iend;

  /** Print out what i1 i2 iend point to. */
  stringc debug01() const;

  /** Constructor. */
  tokenizerlocal(tokenizer& ref_);
  /** Scope this to [tl.i1,tl.i2] */
  tokenizerlocal(tokenizerlocal& tl);

  /* Explicit control of begin and end atoms 
     - no angle brackets added. */
  boolc atomize_next(stringc & atom1, stringc& atom2);

  /** current and i1 point to start of list. */
  void reset();

  /** Reset ot tkl's scope. */
  void reset(tokenizerlocal& tkl);

  /** iend=i2 */
  void endpointcontract();
  /** i2=iend */
  void endpointexpand();
  /** iend set to end of list. */
  void endpointreset();

  /** Iterate between [i1,i2) */
  boolc operator ! () const; 
  /** Access the current token in the stream. */
  stringc & operator() () const; 
  /** Increment the stream's index. */
  void operator ++ (); 
  
  /** Assumes i1 points to atomized tag, i2 to the tag end. */
  boolc readtag(string& val, stringc& tag);
  /** Searches from current to find, erase and insert string.  */
  boolc writetag(stringc& val, stringc& tag);
  /** Assumes i1 points to atomized tag, i2 to the tag end. */
  boolc erasetag(stringc& tag);


  /** Assumes atomized tags search for matching tags: 
  [i1,i2] - [<tag>,</tag>] and current points to i1. */
  boolc scopesearch(stringc& tag);

  /* From the current position scope and read the tag. */
  boolc read(string& str, stringc& tag1);
  boolc read(string& str, stringc& tag1, stringc& tag2);
  boolc read(string& str, stringc& tag1, stringc& tag2, stringc& tag3);
  boolc read(string& str, stringc& tag1, stringc& tag2, stringc& tag3, stringc& tag4);
  boolc read(string& str, stringc& tag1, stringc& tag2, stringc& tag3, stringc& tag4, stringc& tag5);
  boolc read(string& str, stringc& tag1, stringc& tag2, stringc& tag3, stringc& tag4, stringc& tag5, stringc& tag6);

  /** Set iend=i2 after scoping. */
  boolc boundscope(stringc& tag1); 

  /* Find and atomize next <tag1> and </tag1>. */
  boolc scope(stringc& tag1); 
  /* Find and atomize matching tags in order. */
  boolc scope(stringc& tag1, stringc& tag2);
  /* Find and atomize matching tags in order. */
  boolc scope(stringc& tag1, stringc& tag2, stringc& tag3 );
  /* Find and atomize matching tags in order. */
  boolc scope(stringc& tag1, stringc& tag2, stringc& tag3, stringc& tag4 );
  /* Find and atomize matching tags in order. */
  boolc scope(stringc& tag1, stringc& tag2, stringc& tag3, stringc& tag4, stringc& tag5 );
  /* Find and atomize matching tags in order. */
  boolc scope(stringc& tag1, stringc& tag2, stringc& tag3, stringc& tag4, stringc& tag5, stringc& tag6);

};


/*!
\brief Iterate over a object tag in parents scope. 

This class is designed for use with the for loop.

The for loop tests before entry. So the ! operator
  really moves i1 i2 towards the target.

Iterator conforms to symbolic use.

\verbatim
// Iterating over a scope from tl.
tokenizerlocalvar tl2(tl,"obj");
for ( ; !tl2; ++tl2 )
{
  tokenizerlocal tl3(tl2);
  if (tl3.read(SN,"SN"))
    cout << SHOW3(SN) << endl;
  tl3.reset();
  if (tl3.read(Desc,"Desc"))
    cout << SHOW3(Desc) << endl;
} 
\endverbatim
*/
class tokenizerlocalvar : public tokenizerlocal
{
public:

  /** Iterate between [i1,i2) */
  boolc operator ! (); 

  /** Tag that is iterated over parents scope. */
  string objtag;

  /** Reset to tkl's scope. */
  tokenizerlocalvar
  (
    tokenizerlocal& tkl, 
    stringc& objtag_
  );

};




/*
Issues

* Handle attributes by pre-processing the attributes
  into the more primitive xml.

<Sandwich class_id="0" tracking_level="0" version="0">
...
</Sandwich>
 becomes
<Sandwich>
 <Sandwich.attrib>
  <x>
   <l>class_id</l>
   <r>0</r>
  </x>
  <x>
   <l>tracking_level</l>
   <r>0</r>
  </x>
  <x>
   <l>version</l>
   <r>0</r>
  </x>
 </Sandwich.attrib>
....
</Sandwich>

* Possible extension: template ref so this class may
 be either a reference or contain the tokenizer!
 This would be good for the splice_into which could
 send instead to the tokenizerlocal. 
 (one line rather than multiple lines, easier to use)
 This is probably too complex for the gain, the object
 /class would have to often be used.

* Human readable xml - automated spacing for nested tags.
 One space indent. Indent when a new tag encountered,
  push the new tag to a tag stack. Keep current count
  of depth.


*/

/*!
\brief Iterate through scopetag objects.

While tokenizerlocal can do this it is associated
 with the tokenizer which iterates through strings.

This uses symbolic iterator concepts: reset(), ++ !.
 The mechanics are hidden/automated.
*/
/*
class tokenizerscope : public tokenizerlocal
{
public:

  // Outer scope. 
  tokenizerlocal& tl;

  // Scope tag. 
  string scopetag;

  // Set the scope to tl. 
  void reset();

  // Iterate through scopetag objects. 
  boolc operator ! ();

  // Constructor. 
  tokenizerscope(tokenizerlocal& tl_,stringc & scopetag_="");
  tokenizerscope(tokenizer& tk,stringc & scopetag_);

};

*/

#endif



