/// EntityTree.cpp 
/// 
/// (c) 2005-2013 by Bastian Spiegel <bs@tkscript.de> 
///     - published under the terms of the GNU general public license (GPL). 
/// 
/// 
 
#include "tks.h" 
 
#ifdef TKS_EXPORT_ENTITY_SCANNER 
 
#include "EntityTree.h" 
 
EntityTreeNode::EntityTreeNode(void)  
{ 
   for(int i=0; i<EntityTree_ASCII_HI; i++) 
   { 
      nodes[i] = NULL; 
   }

   entries = NULL; 
} 
 
EntityTreeNode::~EntityTreeNode()  
{ 
   for(sSI i=0; i<EntityTree_ASCII_HI; i++) 
   { 
      if(NULL != nodes[i]) 
      { 
         delete nodes[i]; 
         nodes[i] = NULL; 
      } 
   }

   if(NULL != entries) 
   { 
      delete [] entries; 
      entries = NULL; 
   } 
} 
 
EntityTree::EntityTree(void)  
{ 
   for(sSI i=0; i<EntityTree_MAX_LENGTH; i++) 
   { 
      nodes[i] = NULL; 
   } 
} 
 
EntityTree::~EntityTree()  
{ 
   cleanup(); 
} 
  
void EntityTree::cleanup(void)  
{ 
   for(sSI i=0; i<EntityTree_MAX_LENGTH; i++) 
   { 
      if(NULL != nodes[i]) 
      { 
         delete nodes[i]; 
         nodes[i] = NULL; 
      } 
   } 
} 
 
sBool EntityTree::addEntity(const char *_name, sUI _id) 
{ 
 /*  if(_id>EntityTree_MAX_ENTITIES) 
   { 
      tkscript->printf("[---] EntityTree::addEntity(): %i>MAX_ENTITIES.\n", _id); 
      return 0; 
   }*/ 
    
   YAC_String s; 
   s.visit((char*)_name); 
   sUI l = s.length; 

   if(l < 2)
   {
      return YAC_FALSE;
   }

   if(--l > (EntityTree_MAX_LENGTH - 1))
   {
      return YAC_FALSE;
   }

   if(NULL == nodes[l])
   {
      nodes[l] = new EntityTreeNode();
   }

   EntityTreeNode *ct = nodes[l];
   sUI i = 0; 
   sU8 c = _name[i++] & EntityTree_ASCII_MASK; 

   while(i < l)
   { 
      if(NULL == ct->nodes[c])
      {
         ct->nodes[c] = new EntityTreeNode();
      }

      ct = ct->nodes[c]; 
      c  = _name[i++]; 
   }

   if(NULL == ct->entries) 
   { 
      ct->entries = new sUI[EntityTree_ASCII_HI];

      for(sUI j=0; j<EntityTree_ASCII_HI; j++) 
      {
          ct->entries[j] = NULL;
      }

      ct->entries[c] = _id;
      return YAC_TRUE; 
   }

   if(NULL == ct->entries[c])
   { 
      ct->entries[c] = _id;
      return YAC_TRUE;
   } 
   else
   {
      return YAC_FALSE;
   }
} 
 
sUI EntityTree::getEntityIDByString(YAC_String *_s) 
      // ---- this method returns the ID of the entity called _s or 0 if no entity with such a name exists. 
{ 
   if(NULL == _s)
   {
      return 0;
   }

   sSI l = _s->length;

   if( (l < 2) || (l > (EntityTree_MAX_LENGTH - 1)) ) 
   {
      return 0;
   }

   if(NULL == _s->chars)
   {
      return 0;
   }

   sU8 *s  = _s->chars; 
   sU8 *se = s+--l; 

   EntityTreeNode *ct = nodes[l];

   while((NULL != ct) && (s < se)) 
   { 
      register sU8 c = *s++ & EntityTree_ASCII_MASK;

      if(NULL != ct->nodes[c])
      {
         ct = ct->nodes[c];
      }
      else if(ct->entries) 
      {
         return ct->entries[c];
      }
      else
      {
         return 0;
      }
   }

   return 0; 
} 
 
void EntityTree::exportToC(const char *_filename, const char *_funname) 
      // ---- export the entity scanner true to a c file 
{ 
   YAC_String output; 
   output.alloc(8192); 
 
   output.append("// ---- auto-generated by tkscript::EntityTree - do not edit!\n"); 
   output.append("sUI "); 
   output.append((sChar*)_funname); 
   output.append("(YAC_String *_s) {\n"); 
   output.append("   if(!_s) return 0;\n"); 
   output.append("   sUI l=_s->length;\n"); 
   output.append("   if( (l<2) || (l>(EntityTree_MAX_LENGTH-1)) ) return 0;\n"); 
   output.append("   if(!_s->chars) return 0;\n"); 
   //output.append("   return "); 
   //output.append((sChar*)_funname); 
   //output.append("(_s->chars);\n"); 
   //output.append("}\n\nsUI "); 
   //output.append((sChar*)_funname); 
   //output.append("(sChar *_s) {\n"); 
   output.append("   sU8 *s=_s->chars;\n"); 
   output.append("   switch(l-1) {\n"); 
 
   YAC_String t; t.alloc(256);  
   EntityTreeNode *ct; 
   EntityTreeNode *tstack[EntityTree_MAX_LENGTH]; 
   sSI             jstack[EntityTree_MAX_LENGTH]; 
   sSI             tstacki = EntityTree_MAX_LENGTH; 

   for(sSI i=0; i<EntityTree_MAX_LENGTH; i++) 
   { 
      ct = nodes[i]; 
      t.printf("%i", i); 

      if(NULL != ct)
      { 
         output.append("      case "); 
         output.append(&t); 
         output.append(":\n"); 

         sSI depth = 0; 
         sUI bfirst = 0; 
         sSI j = 33;

         while(NULL != ct)
         { 
            // ---- write out if block for each entry 
            for(; j<EntityTree_ASCII_HI; j++) 
            { 
               if(NULL != ct->entries&&ct->entries[j]) 
               { 
                  for(sSI ind=0; ind<(9+depth*3); ind++)
                  {
                     output.append(" ");
                  }

                  if(bfirst++)
                  {
                     output.append("else ");
                  }

                  output.append("if(s["); 
                  t.printf("%i", depth); 
                  output.append(&t); 
                  output.append("]=="); 
                  t.printf("\'%c\'", (char)j); 
                  output.append(&t); 
                  output.append(")return "); 
                  t.printf("%i", ct->entries[j]); 
                  output.append(&t); 
                  output.append(";\n"); 
               } 
               else if(NULL != ct->nodes[j])
               { 
                  for(sSI ind=0; ind<(9+depth*3); ind++)
                  {
                     output.append(" ");
                  }

                  if(bfirst++)
                  {
                     output.append("else ");
                  }

                  output.append("if(s["); 
                  t.printf("%i", depth); 
                  output.append(&t); 
                  output.append("]=="); 
                  t.printf("\'%c\'", (char)j); 
                  output.append(&t); 
                  output.append(") {\n"); 
                  depth++; 
                  bfirst = 0;
                  tstack[--tstacki] = ct; 
                  jstack[tstacki] = j; 
                  ct = ct->nodes[j]; 
                  j = 0; 
               } 
            }

            if(depth > 0)
            { 
               depth--;

               for(sSI ind=0; ind<(9+depth*3); ind++)
               {
                  output.append(" ");
               }

               output.append("}\n"); 
               ct = tstack[tstacki]; 
               j = jstack[tstacki++]+1; 
            } 
            else
            {
               ct = 0;
            }
         }

         output.append("         break;\n"); 
      } // if ct 
   }

   output.append("\n   }"); 
   output.append("\n   return 0;"); 
   output.append("\n}\n"); 
   output.fixLength(); // xxx ???
   output.writeFile((sChar*)_filename); 
} 
 
 
#endif //TKS_EXPORT_ENTITY_SCANNER 
