#include <stdio.h>
#include <stdlib.h>
struct bufnode{
char value;
struct bufnode* next;
struct bufnode* prev;
};
void buflistcreate(struct bufnode** baseptr,char value){
*baseptr = malloc(sizeof(struct bufnode));
(*baseptr)->next=NULL;
(*baseptr)->prev=NULL;
(*baseptr)->value=value;
return;
}
void buflistdestroy(struct bufnode** base){ //ONLY A SINGLE NODE!!!
if ((*base)==NULL) return;
(*base)->next = NULL;
(*base)->prev = NULL;
(*base)->value = '@';
free(*base);
(*base)=NULL;
}
void _buflisttostringrec(unsigned int depth, struct bufnode** node, char** output){
(*output)[depth]=(*node)->value;
if ((*node)->next == NULL) {return;}
_buflisttostringrec(depth+1,&((*node)->next),output);
return;
}

void buflistremall(struct bufnode** base){
if ((*base)==NULL) return;
buflistremall(&((*base)->next));
buflistdestroy(base);
}
void buflistremfirst(struct bufnode** base){
if ((*base)==NULL) return;
if ((*base)-> next == NULL) {buflistdestroy(base);
return;}
(*base)->next->prev=NULL;
struct bufnode* temp = (*base)->next;
buflistdestroy(base);
*base=temp;
return;
}
void buflistremlast(struct bufnode** base){
if ((*base)!=NULL){ if ((*base)->next!=NULL) {buflistremlast(&((*base)->next));}
else {buflistdestroy(base);};}
}

unsigned int buflistgetlength(struct bufnode** base){
if ((*base)==NULL) return 0;
if ((*base)->next!=NULL) return (buflistgetlength((&(*base)->next))+1);
return 1;
}
char buflistget(struct bufnode** base, unsigned int index){
if (index!=0) return buflistget(&((*base)->next),index-1);
if (*base==NULL) return '@';
return (*base)->value;
}
void buflistset(struct bufnode** base, char value, unsigned int index){
if (index!=0) {buflistset(&((*base)->next),value,index-1); return;}
(*base)->value = value;
}
int buflisttostring(struct bufnode** base,char** string){
if((*base)==NULL) {(*string)=calloc(1,1); return 1;}
unsigned int len = buflistgetlength(&(*base));
//printf("length is %i\n",len);
*string = realloc(*string,len+1);
_buflisttostringrec(0,base,&(*string));
(*string)[len]='\0';
return 0;
}
void buflistaddlast(struct bufnode** base, char value){
if ((*base)==NULL) { buflistcreate((&(*base)),value); return;}
if((*base)->next!=NULL){
buflistaddlast(&((*base)->next),value);
return;
}

struct bufnode* temp;
buflistcreate(&temp,value);
(*base)->next = temp;
temp->prev = (*base);
temp->value = value;
return;
}
void buflistaddfirst(struct bufnode** base, char value){
if ((*base)==NULL) {buflistcreate((&(*base)),value); return;}
struct bufnode* temp;
buflistcreate(&temp,value);
temp->next = (*base);
(*base)->prev = temp;
temp->value = value;
(*base)=temp;
}
struct linenode{
char* value;
struct linenode* next;
struct linenode* prev;
};
void linelistcreate(struct linenode** baseptr,char* value){
*baseptr = malloc(sizeof(struct linenode));
(*baseptr)->next=NULL;
(*baseptr)->prev=NULL;
(*baseptr)->value=malloc(sizeof(value)*strlen(value)+1);
strcpy((*baseptr)->value,value);
(*baseptr)->value[sizeof(value)*strlen(value)]='\0';
//printf("made %s at %p\n",(*baseptr)->value,*baseptr);
return;
}

void linelistaddfirst(struct linenode** base, char* value){
if ((*base)==NULL) {linelistcreate((&(*base)),value); return;}
struct linenode* temp=NULL;
linelistcreate(&temp,value);
temp->next = (*base);
(*base)->prev = temp;
(*base)=temp;
}
void linelistaddlast(struct linenode** base, char* value){
if ((*base)==NULL) { linelistcreate((&(*base)),value); return;}
if((*base)->next!=NULL){
linelistaddlast(&((*base)->next),value);
return;
}
struct linenode* temp=NULL;
linelistcreate(&temp,value);
(*base)->next = temp;
temp->prev = (*base);
//printf("made %c at %i\n",value,temp);
return;
}
void linelistremall(struct linenode** base){
if ((*base)==NULL) return;
if ((*base)->next!=NULL) linelistremall(&((*base)->next));
(*base)->next=NULL;
(*base)->prev = NULL;
(*base)->value="";
free(*base);
(*base)=NULL;
}

void linelistremfirst(struct linenode** base){
if ((*base)==NULL) return;
if ((*base)-> next == NULL) {free(*base); (*base)=NULL; return;}
(*base)->next->prev=NULL;
struct linenode* temp = (*base)->next;
free(*base);
*base=temp;
return;
}
void linelistremlast(struct linenode** base){
if ((*base)==NULL) return;
if((*base)->next!=NULL){
linelistremlast(&((*base)->next));
return;
}
(*base)->prev->next=NULL;
free(*base);
return;
}

unsigned int linelistgetlength(struct linenode** base){
if ((*base)==NULL) return 0;
if ((*base)->next!=NULL) return 
(linelistgetlength((&(*base)->next))+strlen((*base)->value));
return strlen((*base)->value);
}
struct linenode* linelistget(struct linenode** base, unsigned int index){
if (index!=0) return linelistget(&((*base)->next),index-1);
if (*base==NULL) return NULL;
return (*base);
}
void linelistset(struct linenode** base, char* value, unsigned int index){
if (index!=0) {linelistset(&((*base)->next),value,index-1); return;}
(*base)->value = value;
}
void _linelisttostringrec(size_t offset, struct linenode** node, char** output){
//printf("output contains %s\n",(*output));
for (size_t i=0; i<strlen((*node)->value);i++){
(*output)[i+offset]=((*node)->value)[i];
}
offset+=strlen((*node)->value);
if ((*node)->next == NULL) {return;}
_linelisttostringrec(offset,&((*node)->next),output);
return;
}

void linelisttostring(struct linenode* base,char** string){
if(base==NULL) {(*string)=calloc(1,1); return;}
size_t len = linelistgetlength(&base);
//printf("length is %i\n",len);
(*string)=realloc((*string),len+1);
_linelisttostringrec(0,&base,&(*string));
(*string)[len+1]='\0';
return;
}
struct chunk{
struct linenode* value;
struct chunk* next;
struct chunk* prev;
};
void _chunkcreaterec(struct linenode** dest, struct linenode** source,struct linenode** 
prevn){
linelistcreate(dest,(*source)->value);
if ((*source)->prev!=NULL) {(*dest)->prev=(*prevn);(*dest)->prev->next = (*dest);}
if ((*source)->next!=NULL) _chunkcreaterec(&((*dest)->next),&((*source)->next),dest);
}
void chunkcreate(struct chunk** base, struct linenode** inptr){
if ((*inptr)==NULL) return;
struct linenode* t;//=malloc(sizeof(linenode));
struct linenode* t2=NULL;//=malloc(sizeof(linenode));
//struct linenode* t3=NULL;
struct linenode* temp=(*inptr);
(*base)=malloc(sizeof(struct chunk));
_chunkcreaterec(&((*base)->value),inptr,NULL);
//printf("%s\n",(*base)->value->value);
(*base)->next =NULL;
(*base)->prev = NULL;
//printf("Chunkcreate successful. Chunk at %p has a value at %p of %s\n",*base,(*base)->value,(*base)->value->value);
//if((*base)->next!=NULL)
//printf("base->next->value->value = %s\n",(*base)->next->value->value);
}
void chunkdestroy(struct chunk** base){
free((*base)->value);
free(*base);
}
void chunkaddfirst(struct chunk** base, struct linenode** value){
//printf("Adding linenode at %p with a value of %s to a chunk at 
//%p\n",*value,(*value)->value,*base);
if ((*base)==NULL) {
//printf("base = %p\n",*base);
chunkcreate((&(*base)),value);
//printf("Chunk created1\n");
 return;}
//printf("base = %p, base->next = %p\n",*base,(*base)->next);
struct chunk* temp = NULL;
struct chunk* tmp2 = NULL;
char* str=NULL;
linelisttostring(*value,&str);
chunkcreate(&temp,value);
//printf("Chunk created %s\n",str);
temp->next = (*base);
(*base)->prev=temp;
(*base)=temp;
//printf("base = %p, base->next = %p\n",*base,(*base)->next);

free(str);
}
void chunkaddlast(struct chunk** base, struct linenode** value){
if ((*base)==NULL) {chunkcreate((&(*base)),value); return;} else if((*base)->next!=NULL){
chunkaddlast(&((*base)->next),value);
return;}
struct chunk* temp = NULL;
chunkcreate(&temp,value);
(*base)->next = temp;
(temp)->prev=(*base);
}
void chunkremfirst(struct chunk** base){
if((*base)->next==NULL) {chunkdestroy(base); 
(*base)=NULL;}
struct chunk* temp = (*base)->next;
chunkdestroy(base);
(*base) = temp;
(*base)-> prev = NULL;
}
void chunkremall(struct chunk** base){
while((*base)!=NULL)
chunkremfirst(base);
}
void chunkremlast(struct chunk** base){
if((*base)->next!=NULL) 
{chunkremlast(&((*base)->next)); return;}
chunkremfirst(base);
}
void chunkset(struct chunk** base, struct chunk* value, unsigned int index){
if (index!=0) {chunkset(&((*base)->next),value,index-1); return;}
(*base) = value;
}
struct chunk* chunkget(struct chunk** base, unsigned int index){
if (index!=0){return chunkget(&((*base)->next),index-1);}
return (*base);
}
size_t chunkgetlength(struct chunk** base){
if ((*base)->next==NULL) return 1;
return chunkgetlength(&((*base)->next))+1;
}
void chunkprint(struct chunk** base){
char* str=NULL;
linelisttostring((*base)->value,&str);
//printf("%p = %s, next = %p\n",*base,str,(*base)->next);
printf("%s\n",str);
free(str);
if((*base)->next!=NULL) chunkprint(&((*base)->next));
}
int main(){
struct bufnode* buf=NULL;
struct linenode* line=NULL;
struct chunk* c=NULL;
char* str=NULL;
char* str2=NULL;
char ch;
printf("Correct output:\n");
for(ch='a';ch<='f';ch++){
buflistaddlast(&buf,ch);
buflisttostring(&buf,&str);
linelistaddlast(&line,str);
buflistremall(&buf);
chunkaddlast(&c,&line);
chunkprint(&c);
}
buflistremall(&buf);
linelistremall(&line);
//chunkremall(&c); Doesnt work yet
c=NULL;// A memory leak, for now
printf("Incorrect output:\n");
for(ch='a';ch<='f';ch++){
buflistaddlast(&buf,ch);
buflisttostring(&buf,&str);
linelistaddlast(&line,str);
buflistremall(&buf);
chunkaddfirst(&c,&line);
chunkprint(&c);
}

//for(ch='z';ch>='a';ch--){ 
//buflistaddlast(&buf,ch);
///}
//buflisttostring(&buf,&str);
//linelistaddlast(&line,str);
//chunkaddfirst(&c,&line);
//chunkremfirst(&c);
return 0;
}

