/*****************************************************************
* unit:    doublelists             release 0.9                   *
* purpose: general manipulation with array of couples of strings *
* Licency: GPL or LGPL                                           *
* Copyright: (c) 1998-2025 Jaroslav Fojtik                       *
******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "dbllist.h"
#include "std_str.h"


/**This method adds two strings into one double list record*/
void doublelist::Add(const char *str1,const char *str2)
{
char*str;
size_t SLen1, SLen2;

 if(str1==NULL) {SLen1=0;str1="";}
	  else SLen1=strlen(str1);
 if(str2==NULL) {SLen2=0;str2="";}
	  else SLen2=strlen(str2)+0;

 if((str=(char*)malloc(SLen1+SLen2+2))==NULL)
	{
	RaiseError(DblListId|No_Memory,this);	//Memory Exhausted
	return;
	}
 memmove(str,str1,SLen1+1);
 memmove(str+SLen1+1,str2,SLen2+1);
 if(flipped) str[SLen1]=1;
 MoveSTR(*this,str);
}


const char *doublelist::Find(const char *key) const
{
const char *str;

  if(key!=NULL)
  {
    for(unsigned i=0; i<NumUsed; i++)
    {
      str = (*this)[i];
      if(str==NULL) continue;
      if(!strcmp(key,str))
      {
        size_t i = strlen(str);
        return str+i+1;
      }
    }
  }
return NULL;
}


/** Obtain constant member pointer from the constant object. */
const char *doublelist::Member(const int i,const int j) const
{
const char *str;

str = (*this)[i];
if(str==NULL) return(str);

switch(j)
   {
   case 0:return(str);
   case 1:if(flipped)
		{
		str=strchr(str,'\1');
		}
	   else {
		str+=strlen(str);
		}
	   if(str!=NULL) str++;
	   return(str);
   default:return(NULL);
   }
}


char *doublelist::Member(const int i,const int j)
{
char *str;

str=(*this)[i];
if(str==NULL) return(str);

switch(j)
   {
   case 0:return(str);
   case 1:if(flipped)
		{
		str=strchr(str,'\1');
		}
	   else {
		str+=strlen(str);
		}
	   if(str!=NULL) str++;
	   return(str);
   default:return(NULL);
   }
}


void doublelist::Flip(int FlipMode)
{
char *s;
  if(FlipMode==flipped) return;
  if(flipped)
    {
    for(unsigned i=0; i<length(); i++)
      {
      s=(*this)[i];
      if(s!=NULL)
        {
        s=strchr(s,1);
        if(s!=NULL) *s=0;
        }
      }
    flipped=0;
    }
  else
    {
    for(unsigned i=0; i<length(); i++)
      {
      s=(*this)[i];
      if(s!=NULL)
        {
        s+=strlen(s);
        if(*s==0) *s=1;
        }
      }
    flipped=1;
    }
}


doublelist::doublelist(const doublelist &dl): list(), flipped(0)
{
  *this=dl;
}


doublelist &doublelist::operator=(const doublelist &dl)
{
char *s;
char **cpstr1, **cpstr2;
size_t len;

  if(this==&dl) return *this;	// check for self assignment
  erase();
  
  flipped=dl.flipped;
  
  if( (cpstr1=pstr=(char **)calloc(sizeof(char *),dl.NumUsed))==NULL)
	{
	NumAlloc=NumUsed=0;
	RaiseError(DblListId|No_Memory,this);	//Memory Exhausted
	return(*this);
	}
  NumUsed=NumAlloc=dl.NumUsed;
  cpstr2=dl.pstr;
  for(unsigned i=0; i<dl.NumUsed; i++)
	{
	if(flipped)  // stringA\1stringB
	    *cpstr1++ = StrDup(*cpstr2++);
	else	     // stringA\0stringB
	    {
	    s=dl[i];
	    if(s==NULL)
	      *cpstr1++ = NULL;
	    else
              {
	      len=strlen(s)+1;
	      len+=strlen(s+len) + 1;
	      *cpstr1 = (char *)malloc(len);
	      memcpy(*cpstr1, s, len);
	      cpstr1++;
              }
	     
	    }
	}

return(*this);
}


#ifdef Streams

#ifndef IOSTREAM_H_ONLY
std::ostream &operator<<(std::ostream &xout, const doublelist & d)
#else
ostream &operator<<(ostream &xout, const doublelist & d)
#endif
{
const char *s1, *s2;

  xout << '{';
  for(unsigned i=0; i<length(d); i++)
  {
    s1 = d.Member(i,0);
    s2 = d.Member(i,1);
    if(i>0) xout<<',';
    xout << "{\"" << (s1==NULL?"NULL":s1) << "\",\""
                  << (s2==NULL?"NULL":s2) << "\"}";
  }
return xout << '}';
}

#endif



#if 0
void main(void)
{
doublelist ll;

cout<<ll;

ll.Add("Ahoj","Svete");
ll.Add("Abbb","Ssss");
ll.Add("Abream","Abraham");

printf("\n[%s %s]\n",ll.Member(0,0),ll.Member(0,1));

cout<<ll;

}
#endif
