/*///---------------------------------------------------------------------\\\*/
/*// Copyright (c)               (_)/=\~/_(_)         All rights reserved. \\*/
/*/  2005-2006                (_)  /=\  ~/_  (_)        Released under the  \*/
/*\  Jim Peters            (_)    /=\    ~/_    (_)             GNU GPL v2  /*/
/*\\ http://uazu.net    (_) ____ /=\ ____ ~/_ ____ (_)      http://fsf.org //*/
/*\\\---------------------------------------------------------------------///*/

//
//	SMXtree -- see SYMIRR.jot for docs
//   

#ifdef HEADER

typedef struct SMXtree SMXtree;
struct SMXtree {
   char **inp1;			// Input string reference
   char **inp2;			// Input string reference
   char *out;			// Output string
   SMTLin aa, bb;		// Input lines
   char *mode;			// Mode: 0 ending, else *mode gives the mode (see below)
   int lev;			// Level during directory copies/skips; must be 0 when not in use
};

// Modes:
//   0 in same directory, normal parallel scan
//   's' skip 'aa' directory (not including final 'X')
//   'S' skip 'bb' directory (not including final 'X')
//   'c' copy 'aa' directory (not including final 'X')
//   'C' copy 'bb' directory (not including final 'X')
//   'x' skip 'aa' directory closing 'X'
//   'X' skip 'bb' directory closing 'X'
//
// Using a string for the mode allows a sequence of modes to be
// applied before returning to mode 0 (which is the NUL at the end of
// the string).


#else

#include "all.h"


//
//	SMXtree
//

SMXtree *
smxtree(char **inp1, char **inp2) {
   SMXtree *tt= ALLOC(SMXtree);

   tt->inp1= inp1;
   tt->inp2= inp2;
   tt->aa.used= 1;
   tt->bb.used= 1;

   tt->mode= "";	// Mode 0

   return tt;
}

#define USED(pp) { pp->used= 1; }
#define RET(xx) { tt->out= xx; return 1; }

int 
smxtree_do(SMXtree *tt) {
   int mode;
   SMTLin *aa= &tt->aa;
   SMTLin *bb= &tt->bb;

   if (tt->out) return 0;	// Nothing to do until our output has been cleared

   if (aa->used) {
      if (!*tt->inp1) return 0;	// Wait for input
      smtlin_decode(aa, tt->inp1);
   }

   if (bb->used) {
      if (!*tt->inp2) return 0;	// Wait for input
      smtlin_decode(bb, tt->inp2);
   }

   if (!tt->mode) {
      // Ending mode
      tt->out= StrDup(SMEOF);
      return 0;
   }
   if (aa->typ == 0) DIE;	// Unexpected EOF on 'aa'
   if (bb->typ == 0) DIE;	// Unexpected EOF on 'bb'

   mode= *tt->mode;
   if (mode == 0) {
      // Normal parallel operation
      int cmp;

      if (aa->typ == 'END' && bb->typ == 'END') {
	 USED(aa); USED(bb);
	 tt->mode= 0;
	 RET(StrDup("END"));
      }
      
      if (aa->typ == 'X' && bb->typ == 'X') {
	 USED(aa); USED(bb);
	 RET(StrDup("X"));
      }

      cmp= strcmp(aa->nam, bb->nam);
      if (cmp == 0) {
         // Same name, both will be consumed
         USED(aa); USED(bb);
	 switch (enc_ccN(aa->typ, bb->typ, 0)) {
	  case 'FF':
	     if (str_ne(aa->szt, bb->szt) ||
		 str_ne(aa->mug, bb->mug)) {
		RET(StrDupT("Fu", bb->mug, bb->nam, bb->szt, 0));
	     }
	     RET(StrDupT("F", bb->mug, bb->nam, bb->szt, 0));
	  case 'DD':
	     if (str_ne(aa->mug, bb->mug)) {
		RET(StrDupT("Du", bb->mug, bb->nam, 0));
	     }
	     RET(StrDupT("D", bb->mug, bb->nam, 0));
	  case 'DF':
	     tt->mode= "sx";
	     RET(StrDupT("Fn", bb->mug, bb->nam, bb->szt, 0));
	  case 'FD':
	     tt->mode= "CZ";
	     RET(StrDupT("Dn", bb->mug, bb->nam, 0));
	 }
         DIE;
      }

      if (cmp > 0) {
	 // 'bb' comes first in sort order
	 USED(bb);
	 switch (bb->typ) {
	  case 'F':
	     RET(StrDupT("Fn", bb->mug, bb->nam, bb->szt, 0));
	  case 'D':
	     tt->mode= "CZ";
	     RET(StrDupT("Dn", bb->mug, bb->nam, 0));
	 }
	 DIE;
      }

      // 'aa' comes first in sort order
      USED(aa);
      switch (aa->typ) {
       case 'F':
	  RET(StrDupT("Fd", aa->mug, aa->nam, aa->szt, 0));
       case 'D':
	  tt->mode= "sz";
	  RET(StrDupT("Dd", aa->mug, aa->nam, 0));
      }
      DIE;
   }

   // Note that both 's' and 'c' consume elements right up to BUT NOT
   // INCLUDING the 'X' that would close this directory.  If we are
   // working through a directory that occurs only on one machine, we
   // can then use mode 'x' to consume this 'X'.  Otherwise we can
   // drop back to mode 0 and consume the two 'X's in parallel.  The
   // mode 'z' consumes the 'x', but also outputs it.

   switch (mode) {
    case 'x':
       USED(aa);
       if (aa->typ != 'X') DIE;
       tt->mode++; 
       return 1;
    case 'z':	// Like 'x' but outputs the 'X'
       USED(aa);
       if (aa->typ != 'X') DIE;
       tt->mode++; 
       RET(StrDup("X"));
    case 's':
       if (aa->typ == 'X' && tt->lev == 0) { tt->mode++; return 1; }
       USED(aa);
       if (aa->typ == 'D') tt->lev++;
       if (aa->typ == 'X') tt->lev--;
       return 1;
       //    case 'X':
       //       USED(bb);
       //       if (bb->typ != 'X') DIE;
       //       tt->mode++; 
       //       return 1;
    case 'Z':	// Like 'X' but outputs the 'X'
       USED(bb);
       if (bb->typ != 'X') DIE;
       tt->mode++; 
       RET(StrDup("X"));
    case 'S':
       if (bb->typ == 'X' && tt->lev == 0) { tt->mode++; return 1; }
       USED(bb);
       if (bb->typ == 'D') tt->lev++;
       if (bb->typ == 'X') tt->lev--;
       return 1;
    case 'C':
      if (bb->typ == 'X' && tt->lev == 0) { tt->mode++; return 1; }
      USED(bb); 
      if (bb->typ == 'F') {
	  RET(StrDupT("Fn", bb->mug, bb->nam, bb->szt, 0));
      }
      if (bb->typ == 'D') {
         tt->lev++;
	 RET(StrDupT("Dn", bb->mug, bb->nam, 0));
      }
      if (bb->typ == 'X') {
         tt->lev--;
	 RET(StrDup("X"));
      }
      DIE;
   }

   DIE;
}
   
void 
smxtree_del(SMXtree *tt) {
   free(tt->out);
   smtlin_del(&tt->aa);
   smtlin_del(&tt->bb);
   free(tt);
}

#endif

/*///---------------------------------------------------------------------\\\*/
/*// )`( )()/)(`/\`//\`          (_)/=\~/_(_)           '/\\'/\')(\()( )'( \\*/
/*/ ()(')()\)(/`/\\ `         (_)  /=\  ~/_  (_)          ' //\'\)(/()(`)() \*/
/*\  )`()( )(/'            (_)    /=\    ~/_    (_)             `\)( )()'(  /*/
/*\\  ()()(`)(/         (_) ____ /=\ ____ ~/_ ____ (_)          \)(')()()  //*/
/*\\\---------------------------------------------------------------------///*/
