/***************************************************
* unit:    sets           release 0.9              *
* purpose: general manipulation with binary arrays *
****************************************************/
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#ifdef Streams
 #include <iostream.h>
#endif

#include "typedfs.h"
#include <sets.h>


//Constructors Of set class
set::set(void)
{
 data=NULL;
 MinElement=MaxElement=0;
}

set::set(int number)
{
 MaxElement=number | 0xF;
 MinElement=MaxElement-15;
 if((data=(WORD *)malloc(2))==NULL)
	{
	MaxElement=MinElement=0;
	RaiseError(SetsId|No_Memory,this);	//Memory Exhausted
	return;
	}
 *data=1<<(number & 15);
}

set::set(const set & s)
{
int size;

 size=(s.MaxElement-s.MinElement+1)>>3;
 if(size==0)
	{
	data=NULL;
	goto Empty;
	}
 if((data=(WORD *)malloc(size))==NULL)
	{
	RaiseError(SetsId|No_Memory,this);	//Memory Exhausted
Empty:  MaxElement=MinElement=0;
	return;
	}

 memcpy(data,s.data,size);
 MaxElement=s.MaxElement;
 MinElement=s.MinElement;
return;
}

set::set(temp_set & s)
{
 data=s.data;			s.data=NULL;
 MaxElement=s.MaxElement;	s.MaxElement=0;
 MinElement=s.MinElement;	s.MinElement=0;
return;
}


set::set(int Min, int Max)
{
int size;

 if(Min>Max)		//if wrong bounds are given, create and empty set
	{
	MaxElement=MinElement=0;
	data=NULL;
	return;
	}
 MaxElement=Max | 0xF;
 MinElement=Min & ~0xF;

 size=(MaxElement-MinElement+1)>>3;		//Size must be>=1
 if((data=(WORD *)malloc(size))==NULL)
	{
	RaiseError(SetsId|No_Memory,this);	//Memory Exhausted
	return;
	}
 memset(data,0,size);
}

set::set(const int *Array, int Size)
{
int i;
const int *Element;

 MaxElement=INT_MIN;
 MinElement=INT_MAX;

 Element=Array;
 for(i=Size;i>0;i--)
 	{
        if(*Element!=TrickInterval)
          {
          if(*Element>MaxElement) MaxElement=*Element;
          if(*Element<MinElement) MinElement=*Element;
          }
	Element++;
        }
 if(MaxElement<MinElement)
 	{
        data=NULL;
	MaxElement=MinElement=0;
        return;
        }

 MaxElement|=0xF;
 MinElement&=~0xF;
 i=(MaxElement-MinElement+1)>>3;
 if((data=(WORD *)malloc(i))==NULL)
	{
        MaxElement=MinElement=0;
	RaiseError(SetsId|No_Memory,this);	//Memory Exhausted
	return;
	}
 memset(data,0,i);

 Element=Array;
 i=0;
 while(Size-->0)
 	{
        if(*Element==TrickInterval)
		{
                Element++;
                if(Size-- <= 0) break;
                if(*Element==TrickInterval) break;
                for(i++;i<=*Element-MinElement;i++)
			*(data+(i>>4))|=(int)1<<(i&0xF);
                }
           else {
                i=*Element-MinElement;
	        *(data+(i>>4))|=(int)1<<(i&0xF);
                }
	Element++;
        }
}

//Destructor Of class set
//set::~set(void)
//{
// erase(*this);
//}


//copy constructors for class set
set &set::operator=(int number)
{
  if(data==NULL) goto Empty;
  if(number>=MinElement && number<=MaxElement)
	{
	memset(data,0,(MaxElement-MinElement+1)>>3);
	number-=MinElement;
	*(data+(number>>4)) = (1<<(number&0xF));
	return(*this);
	}

  if(MaxElement-MinElement==15) goto NoAlloc;
  if(data!=NULL) free(data);
Empty:
  if((data=(WORD *)malloc(2))==NULL)
	{
	MaxElement=MinElement=0;
	RaiseError(SetsId|No_Memory,this);	//Memory Exhausted
	return(*this);
	}
NoAlloc:
  MaxElement=number | 0xF;
  MinElement=MaxElement-15;
  *data=1<<(number & 15);
return(*this);
}


set &set::operator=(const set & s)
{
int size;

 size=(s.MaxElement-s.MinElement+1)>>3;
 if(size==0)
	{
	free(data);
	data=NULL;
	goto Empty;
	}
 if((s.MaxElement-s.MinElement)==(MaxElement-MinElement))
	goto SameRange; 	//Amount of allocated memory is same, skip allocation step

 if(s.MinElement>=MinElement && s.MaxElement<=MaxElement)
	{
	memset(data,0,(s.MinElement-MinElement)>>3);
	memset((char *)data+((s.MaxElement-MinElement+1)>>3),0,(MaxElement-s.MaxElement)>>3);
	memcpy((char *)data+((s.MinElement-MinElement)>>3),s.data,size);
	return(*this);
	}

 free(data);
 data=(WORD *)malloc(size);
 if(data==NULL)
	{
	RaiseError(SetsId|No_Memory,this);	//report memory allocation error
Empty:  MaxElement=MinElement=0;
	return(*this);
	}

SameRange:
 memcpy(data,s.data,size);
 MaxElement=s.MaxElement;
 MinElement=s.MinElement;

return(*this);
}


//tunelling copy operator
set &set::operator=(temp_set & s)
{
  if(data) free(data);
  data=s.data;			s.data=NULL;
  MaxElement=s.MaxElement;	s.MaxElement=0;
  MinElement=s.MinElement;	s.MinElement=0;
return *this;
}


//comparing operators
int set::operator==(const set &s) const
{
int size1,size2,offset;
WORD *Data1,*Data2;

 if(data==NULL)
 	{
	return(EmptyCheck(s));
        }
 if(s.data==NULL)
 	{
	return(EmptyCheck(*this));
        }

 size1=(MaxElement-MinElement+1)>>4;
 size2=(s.MaxElement-s.MinElement+1)>>4;
 offset=(MinElement-s.MinElement+1)>>4;
 Data1=data;
 Data2=s.data;

 while((size1>0)||(size2>0))
 	{
	if(offset>0)
        	{
                offset--;
                size2--;        //tady je chyba, pridat test size
                if(*Data2++ !=0 ) return(0);
		continue;
                }
        if(offset<0)
        	{
                offset++;
                size1--;
                if(*Data1++ !=0 ) return(0);
                continue;
                }

	size1--;
        size2--;
	if(size2<0)
        	{
                if(*Data1++ !=0 ) return(0);
                continue;
                }
        if(size1<0)
        	{
                if(*Data2++ !=0 ) return(0);
		continue;
                }

	if(*Data1++ != *Data2++) return(0);
        }

return(1);

}


/*returns true when set has all its membest inside set s*/
int set::operator IN (const set &s) const
{
int size,size2,offset;
WORD *InData,*CheckedData;

 size=(MaxElement-MinElement+1)>>4;
 size2=(s.MaxElement-s.MinElement+1)>>4;
 offset=(MinElement-s.MinElement)>>4;
 InData=data;
 CheckedData=s.data;
 if(offset>0)
	{
	CheckedData+=offset;
	size2-=offset;
	offset=0;
	}

 while(size-->0)
	{
	if(offset<0)
		{
		offset++;
		if(*InData++ !=0 ) return(0);
		continue;
                }
	if(size2<=0)
        	{
                if(*InData++ !=0 ) return(0);
                continue;
		}

        size2--;
	if((*InData & *CheckedData++)!=*InData) return(0);
	InData++;
        }

return(1);
}


//Receiving one bit from set
int set::operator[](int i) const
{
 if(i>MaxElement || i<MinElement || data==NULL) return(0);
 i-=MinElement;
 return( (*(data+(i>>4)) & 1<<(i&0xF)) != 0);
}


//family of operators +  Addind sets
temp_set operator+(const set & s1, const set & s2)
{
int size1,size2,offset;
WORD *Data1,*Data2,*OutData;

 if(s1.data==NULL) return(s2);
 if(s2.data==NULL) return(s1);

 temp_set tmp(min(s1.MinElement,s2.MinElement),max(s1.MaxElement,s2.MaxElement));

 size1=(s1.MaxElement-s1.MinElement+1)>>4;
 size2=(s2.MaxElement-s2.MinElement+1)>>4;
 offset=(s1.MinElement-s2.MinElement)>>4;
 Data1=s1.data;
 Data2=s2.data;
 OutData=tmp.data;

 while((size1>0)||(size2>0))
 	{
	if(offset>0)
        	{
                offset--;
                if(size2--<=0) *OutData++=0;
                	  else *OutData++=*Data2++;
                continue;
                }
        if(offset<0)
        	{
                offset++;
                if(size1--<=0) *OutData++=0;
			  else *OutData++=*Data1++;
                continue;
                }

        size1--;
        size2--;
	if(size2<0)
        	{
                *OutData++=*Data1++;
                continue;
                }
        if(size1<0)
		{
                *OutData++=*Data2++;
                continue;
                }

	*OutData++=*Data1++ | *Data2++;
	}

return(tmp);
}


temp_set operator+(const set & s1, int number)
{
 if(EmptyCheck(s1)) return temp_set(number);

 if(s1.MinElement<=number && s1.MaxElement>=number)
	{
	temp_set tmp(s1);
	number-=tmp.MinElement;
	*(tmp.data+(number>>4)) |= 1<<(number&0xF);
	return tmp;
	}

 temp_set tmp(min(s1.MinElement,number),max(s1.MaxElement,number));
 memcpy((char *)tmp.data+((s1.MinElement-tmp.MinElement)>>3),
	s1.data,(s1.MaxElement-s1.MinElement+1)>>3);

 number-=tmp.MinElement;
 *(tmp.data+(number>>4)) |= 1<<(number&0xF);
return(tmp);
}


set &set::operator+=(int number)
{
 if(EmptyCheck(*this)) return *this=number;

 if(number<MinElement || number>MaxElement)
	{
	temp_set tmp(min(MinElement,number),max(MaxElement,number));
	memcpy((char *)tmp.data+((MinElement-tmp.MinElement)>>3),
		data,(MaxElement-MinElement+1)>>3);
	*this=tmp;
	}

 number-=MinElement;
 *(data+(number>>4)) |= 1<<(number&0xF);

return(*this);
}


//family of operators -  Substracting sets
temp_set operator-(const set & s1, const set & s2)
{
int size,size2,offset;
WORD *Data2,*OutData;

 if((s1.data==NULL)||(s2.data==NULL))
 	{
        return s1;
	}

 temp_set tmp(s1);

 size=(s1.MaxElement-s1.MinElement+1)>>4;
 size2=(s2.MaxElement-s2.MinElement+1)>>4;
 offset=(s1.MinElement-s2.MinElement)>>4;
 Data2=s2.data;
 OutData=tmp.data;

 if(offset<0)		 //s.MinElement>MinElement
 	{
        OutData-=offset; //offset is negative!
        size+=offset;
        }
 if(offset>0)		 //s.MinElement>MinElement
 	{
	Data2+=offset;
        size2-=offset;
        }

 while(size-->0)
 	{
        if(size2-- <= 0) break;

	*OutData++ &= ~*Data2++;
        }

return(tmp);
}


temp_set operator-(const set & s1, int number)
{
 if(EmptyCheck(s1)) return temp_set();

 if(s1.MinElement<=number && s1.MaxElement>=number)
	{
	temp_set tmp(s1);
	number-=tmp.MinElement;
	*(tmp.data+(number>>4)) &= ~(1<<(number&0xF));
	return(tmp);
	}

return(s1);
}


temp_set operator-(int number, const set & s2)
{
 if(s2[number]) return temp_set();
return temp_set(number);
}


set &set::operator-=(int number)
{
if(data!=NULL && MinElement<=number && MaxElement>=number)
	{
	number-=MinElement;
	*(data+(number>>4)) &= ~(1<<(number&0xF));
	}
return *this;
}


//family of operators +  AND sets
temp_set operator&(const set & s1, int number)
{
 if(s1[number]) return temp_set(number);
return temp_set();
}

temp_set operator&(const set & s1, const set & s2)
{
int size,size2,offset;
WORD *Data2,*OutData;

 if((s1.data==NULL)||(s2.data==NULL))
	{
	return temp_set();
	}

 temp_set tmp(s1);

 size=(s1.MaxElement-s1.MinElement+1)>>4;
 size2=(s2.MaxElement-s2.MinElement+1)>>4;
 offset=(s1.MinElement-s2.MinElement)>>4;
 Data2=s2.data;
 OutData=tmp.data;

 while(offset<0)		 //s.MinElement>MinElement
 	{
        *OutData++ =0;
        size--;
        offset++;
        }
 if(offset>0)		 //s.MinElement>MinElement
 	{
        Data2+=offset;
        size2-=offset;
        }

 while(size-->0)
 	{
        if(size2-- <= 0) break;

	*OutData++ &= *Data2++;
        }

return(tmp);
}


set &set::operator&=(int number)
{
 if((*this)[number]!=0) *this=number;
		   else erase(*this);
return *this;
}



temp_set operator^(const set & s1, const set & s2)
{
int size1,size2,offset;
WORD *Data1,*Data2,*OutData;

 if(s1.data==NULL) return(s2);
 if(s2.data==NULL) return(s1);

 temp_set tmp(min(s1.MinElement,s2.MinElement),max(s1.MaxElement,s2.MaxElement));

 size1=(s1.MaxElement-s1.MinElement+1)>>4;
 size2=(s2.MaxElement-s2.MinElement+1)>>4;
 offset=(s1.MinElement-s2.MinElement)>>4;
 Data1=s1.data;
 Data2=s2.data;
 OutData=tmp.data;

 while((size1>0)||(size2>0))
	{
	if(offset>0)
		{
		offset--;
		if(size2--<=0) *OutData++=0;
			  else *OutData++=*Data2++;
		continue;
		}
	if(offset<0)
		{
		offset++;
		if(size1--<=0) *OutData++=0;
			  else *OutData++=*Data1++;
		continue;
		}

	size1--;
	size2--;
	if(size2<0)
		{
		*OutData++=*Data1++;
		continue;
		}
	if(size1<0)
		{
		*OutData++=*Data2++;
		continue;
		}

	*OutData++=*Data1++ ^ *Data2++;
	}

return(tmp);
}


set &set::operator^=(int number)
{
 if((*this)[number]!=0) *this -= number;
		   else *this += number;
 return(*this);
}


/*This function verifies whether the given set is empty - faster than card()*/
int EmptyCheck(const set &s)
{
int size;
WORD *CheckedData;

 size=(s.MaxElement-s.MinElement+1)>>4;
 if(s.data==NULL) return(1);

 CheckedData=s.data;
 while(size-->0)
	{
	if(*CheckedData++!=0) return(0);  // set is not empty
	};
 return(1);
}


char *int2str(char *str,int i)
{
int q,qq;
char c;

if(i<0) {
	i=-i;
	*str++='-';
	}
q=0;
do {
   *str++=i%10+'0';
   i=i/10;
   q++;
   } while(i>0);

qq=q;
q=q/2;
while(q>=1)
	{
	c=*(str-q);
	*(str-q)=*(str-qq-1+q);
	*(str-qq-1+q)=c;
	q--;
	}

*str=0;
return(str);
}


/*This procedure converts set to the string inside given buffer*/
char *set2str(char *str,const set &s)
{
int i,Last,num;
char *retstr=str;

 Last=TrickInterval;
 num=0;
 *str++='[';
 if(s.data!=NULL)
 for(i=s.MinElement;i<=s.MaxElement+1;i++)
	{
	if(s[i]) {
		 if(Last==i-1)
			{	//interval detected
			num++;
			Last++;
			continue;
			}
		 str=int2str(str,i);
		 num=0;
		 *str++=',';
		 Last=i;
		 }
	    else {
		 if((Last==i-1)&&(num>0))
			{
			* --str='.';
			* ++str='.';
			str++;
			str=int2str(str,Last);
			*str++=',';
			Last=TrickInterval;
			}
		 num=0;
		 }
	}
 if(* --str == '[') ++str;
 *str=']';
 * ++str=0;
return(retstr);
}


/*This procedure reads set from string*/
temp_set str2set(const char *str)
{
temp_set tmp;
int n,n2,state=0;

 if(str!=NULL)
  while(*str)
     {
     if(isspace(*str)) {str++;continue;}
     switch(state)
	{
	case 0:if(*str=='[') state=1;
	       break;
	case 1:if(!isdigit(*str)) goto Finish;		//read error
	case 2:
	       if(sscanf(str,"%d",&n)!=1) goto Finish;	//read error
	       tmp+=n;
ClearDigits:   while(isdigit(str[1])) str++;
	       state=3;
	       break;
	case 3:if(*str==',') {state=2;break;}
	       if(*str=='.')
		 {
		 str++;
		 if(*str!='.') goto Finish;
		 str++;
		 if(sscanf(str,"%d",&n2)!=1) goto Finish; //read error
		 while(n2!=n)
			{
			tmp+=n2;
			if(n2>n) n2--;
			    else n2++;
			}
		 goto ClearDigits;
		 }
	       if(*str==']') goto Finish;	//Set read succesfully finished
	       goto Finish;	//read error
	}
     str++;
     }
Finish:
 return tmp;
}


/*This function calculates number of elements inside given set*/
int Card(const set &s)
{
int size,ret=0;
WORD w,*CheckedData;

 size=(s.MaxElement-s.MinElement+1)>>4;
 if(s.data==NULL) return(0);

 CheckedData=s.data;
 while(size-->0)
   {
   w=*CheckedData++;
   while(w!=0)
   	{
        if(w & 1) ret++;
        w>>=1;
        }
   }
return(ret);
}


void erase(set & s)
{
 if((s.MaxElement!=s.MinElement)&&(s.data!=NULL)) free(s.data);
 s.data=NULL;
 s.MaxElement=s.MinElement=0;
}


/*This procedure verifies integrity of given object ==0 OK  !=0 fail*/
int check(set & s)
{
int ret=0;

if(s.data==NULL)
	{
	if(s.MinElement!=s.MaxElement) ret=SetsId | Bad_Bounds;
	s.MinElement=s.MaxElement=0;
	return(ret);
	}

if(s.MinElement==s.MaxElement)   // data !=  NULL     here
	{
	ret=SetsId | Wrong_Set;
	}

if(ret!=0)	//sorry, something is wrong, I must erase all set here
	{
	free(s.data);
	s.MinElement=s.MaxElement=0;
	s.data=NULL;
	}

if(s.MinElement>s.MaxElement)   // only this error may be perhaps fixed
	{
	ret=s.MinElement;
	s.MinElement=s.MaxElement;
	s.MaxElement=ret;
	ret=SetsId | Bad_Bounds;
	}


return(ret);
}



#ifdef Streams
ostream &operator<<(ostream & xout, const set &s)
{
char str[200];		//!!!!Opravit, staticky buffer je docela spatny
 return xout<<set2str(str,s);
}

/*istream &operator>>(istream &, string &)
{
} */
#endif
