#include <string.h>

#ifndef __RTL__

#include <stdio.h>
#include <stdlib.h>

#else /*__RTL__*/

#include <rtl.h>
#include <signal.h>
#include <pthread.h>
#define printf rtl_printf

#endif /*__RTL__*/

#include "ul_utmalloc.h"
#include "ul_gsa.h"

/*===========================================================*/
/* custom array definition */

#include "ul_gsacust.h"

typedef struct cust2_item {
  int my_val;
  /*gavl_node_t my_node;*/
  int more_data;
} cust2_item_t;

typedef struct cust2_root {
  gsa_array_field_t my_root;
  int my_info;
  int my_first_val;
  int my_last_val;
} cust2_root_t;

typedef int cust2_key_t;

/* Custom array declarations */

GSA_CUST_DEC(cust2, cust2_root_t, cust2_item_t, cust2_key_t,
	my_root, my_val, cust2_cmp_fnc)

inline int
cust2_cmp_fnc(const cust2_key_t *a, const cust2_key_t *b)
{
  if (*a>*b) return 1;
  if (*a<*b) return -1;
  return 0;
}

GSA_CUST_IMP(cust2, cust2_root_t, cust2_item_t, cust2_key_t,
	my_root, my_val, cust2_cmp_fnc, 0)

cust2_root_t cust2_root;


#ifdef WITH_C99

void test_cust_array(void)
{
  int i;
  cust2_key_t k;
  cust2_item_t *item, *item2;
  for(i=1;i<=100;i++){
    item=malloc(sizeof(cust2_item_t));
    item->my_val=i;
    if(cust2_insert(&cust2_root,item)<0)
      printf("cust2_insert error\n");
  }
  printf("Custom array cust2 for_each:\n");
  gsa_cust_for_each(cust2, &cust2_root, item)
    printf("%d ",item->my_val);
  printf("\n");

  k=90;
  printf("Custom array cust2 for_each_from %ld:\n", (long)k);
  gsa_cust_for_each_from(cust2, &cust2_root, &k, item){
    printf("After %d : ",item->my_val);
    gsa_cust_for_each_after(cust2, &cust2_root, &item->my_val, item2)
      printf(" %d",item2->my_val);
    printf("\n");
  }

  printf("Custom array cust2 delete 1-90:\n");
  for(i=1;i<=100-10;i++){
    item=cust2_find(&cust2_root,&i);
    if(cust2_delete(&cust2_root,item)<0)
      printf("cust2_delete error\n");
    free(item);
  }

  printf("Custom array cust2 for_each_rev:\n");
  gsa_cust_for_each_rev(cust2,&cust2_root,item)
    printf("%d ",item->my_val);
  printf("\n");

  printf("Custom array cust2 for_each_cut:\n");
  gsa_cust_for_each_cut(cust2,&cust2_root,item){
    printf("%d ",item->my_val);
    free(item);
  }
  printf("\n");
}

#endif /*WITH_C99*/

void test_cust_array_it(void)
{
  int i;
  cust2_key_t k;
  cust2_item_t *item;
  cust2_it_t it1, it2;
  
  for(i=1;i<=100;i++){
    item=malloc(sizeof(cust2_item_t));
    item->my_val=i;
    if(cust2_insert(&cust2_root,item)<0)
      printf("cust2_insert error\n");
  }
  printf("Custom array cust2 for each with iterator:\n");
  for(cust2_first_it(&cust2_root, &it1);
      (item=cust2_it2item(&it1));cust2_next_it(&it1))
    printf("%d ",item->my_val);
  printf("\n");

  k=90;
  printf("Custom array cust2 for_each_from %ld:\n", (long)k);
  for(cust2_find_first_it(&cust2_root, &k, &it1);
      (item=cust2_it2item(&it1));cust2_next_it(&it1)){
    printf("After %d : ",item->my_val);
    for(cust2_find_after_it(&cust2_root, &item->my_val, &it2);
        (item=cust2_it2item(&it2));cust2_next_it(&it2))
      printf(" %d",item->my_val);
    printf("\n");
  }

  printf("Custom array cust2 delete 1-90:\n");
  for(i=1;i<=100-10;i++){
    item=cust2_find(&cust2_root,&i);
    if(cust2_delete(&cust2_root,item)<0)
      printf("cust2_delete error\n");
    free(item);
  }

  printf("Custom array cust2 for_each_rev:\n");
  for(cust2_last_it(&cust2_root, &it1);
      (item=cust2_it2item(&it1));cust2_prev_it(&it1))
    printf("%d ",item->my_val);
  printf("\n");

  printf("Custom array cust2 for_each_cut:\n");
  gsa_cust_for_each_cut(cust2,&cust2_root,item){
    printf("%d ",item->my_val);
    free(item);
  }
  printf("\n");
}

void test_cust_array_macro_it(void)
{
  int i;
  cust2_key_t k;
  cust2_item_t *item;
  cust2_it_t it1, it2;
  
  for(i=1;i<=100;i++){
    item=malloc(sizeof(cust2_item_t));
    item->my_val=i;
    if(cust2_insert(&cust2_root,item)<0)
      printf("cust2_insert error\n");
  }
  printf("Custom array cust2 for each with iterator:\n");
  ul_for_each_it(cust2, &cust2_root, it1){
    item=cust2_it2item(&it1);
    printf("%d ",item->my_val);
  }
  printf("\n");

  k=90;
  printf("Custom array cust2 for_each_from %ld:\n", (long)k);
  ul_for_each_from_it(cust2, &cust2_root, &k, it1){
    item=cust2_it2item(&it1);
    printf("After %d : ",item->my_val);
    ul_for_each_after_it(cust2, &cust2_root, &item->my_val, it2){
      item=cust2_it2item(&it2);
      printf(" %d",item->my_val);
    }
    printf("\n");
  }

  printf("Custom array cust2 delete 1-90:\n");
  for(i=1;i<=100-10;i++){
    item=cust2_find(&cust2_root,&i);
    if(cust2_delete(&cust2_root,item)<0)
      printf("cust2_delete error\n");
    free(item);
  }

  printf("Custom array cust2 for_each_rev:\n");
  ul_for_each_rev_it(cust2, &cust2_root, it1){
    item=cust2_it2item(&it1);
    printf("%d ",item->my_val);
  }
  printf("\n");

  printf("Custom array cust2 for_each_cut:\n");
  gsa_cust_for_each_cut(cust2,&cust2_root,item){
    printf("%d ",item->my_val);
    free(item);
  }
  printf("\n");
}

/*===========================================================*/

int main(int argc, char *argv[])
{
 #ifdef WITH_C99
  printf("\nCheck of for_each for C99 compliant compiler\n");
  test_cust_array();
 #endif /*WITH_C99*/
  printf("\nCheck of iterators\n");
  test_cust_array_it();
  printf("\nCheck of for_each iterators\n");
  test_cust_array_macro_it();
  return 0;
}

/*===========================================================*/
#ifdef __RTL__

pthread_t t1;

void * t1_routine(void *arg)
{
  main(0, NULL);

  while (1) {
    pthread_wait_np ();

  }
  return 0;
}


int init_module(void) {
        return pthread_create (&t1, NULL, t1_routine, 0);

}

void cleanup_module(void) {
        pthread_delete_np (t1);
}

#endif /*__RTL__*/
