#include <stdio.h>

/*  Coroutine
    
*/

typedef struct Fn Fn;
typedef Fn (*Ptr)(Fn);
struct Fn { Ptr ptr; };

Fn First(Fn);
Fn First(Fn r){
    printf("first\n");
    r.ptr = First;
    return r;
}
void testStructCoroutine(void);
void testStructCoroutine(void)
    {
        Fn c = {First};
        Fn cc = {0};
        c = c.ptr(cc);
        c = c.ptr(cc);
    }



typedef union Fnk Fnk;
typedef Fnk (*FnkPt)(Fnk);
union Fnk { FnkPt pt; };

Fnk A(Fnk);
Fnk A(Fnk r){
    printf("A\n");
    r.pt = A;
    {
        Fnk rr = {A};
        /*return rr;*/
        r = rr;
    }
    return r;
}

void testUnionCoroutine(void);
void testUnionCoroutine(void)
    {
        Fnk k = {A};
        k = k.pt(k);
        k = k.pt(k);
    }


/*      function guard ?             */

void GuardedHello(char *);
void GuardedHelloWithPtr(char *);
void GuardedHelloWithoutPtr(void);

void GuardedHello(char * who){
    if (who != 0)
    GuardedHelloWithPtr(who);
    else
    GuardedHelloWithoutPtr();
}

void GuardedHelloWithPtr(char * who){
    const char * hello = "hello %s\n";
    printf(hello,who);
}

void GuardedHelloWithoutPtr(void){
    printf("i am alone\n");
}

/* closure, 
   not exactly lambda expression, 
    though you can make closure with lambda expression 
      lambda expression share scope
        closure prepare a function with a scope before execution
          like an object with getter
            here i am not experimenting lambda and side effect out of scope change
              i am experimenting how to prepare a function for multiple call
                it is a deferred call. thus i would prefer a currying way
                 this implementation is like an object with this.property
*/
typedef struct ClosureScope ClosureScope;
typedef void (*ClosurePtr)(ClosureScope);
struct ClosureScope
{
    const ClosurePtr ptr;
    const char * msg;
};
ClosureScope ClosureCall(ClosureScope);
ClosureScope ClosureCall(ClosureScope scope)
{
    if (scope.ptr != 0)
    scope.ptr(scope);
    return scope;
}

ClosureScope ClosureScopeBuild(void);
void FunctionClosure(ClosureScope);
ClosureScope ClosureScopeBuild(void){
    ClosureScope s = {
        FunctionClosure,
        "closure"
    };
    return s;
}
void FunctionClosure(ClosureScope s){
    printf("%s\n", s.msg);
    
}

typedef union ClosureUnion ClosureUnion;
union ClosureUnion {
    const ClosureScope scope;
    const ClosurePtr ptr;
};

ClosureUnion ClosureUnionBuild(void);
ClosureUnion ClosureUnionBuild(void){
    const ClosureUnion u = { { FunctionClosure, "union closure" } };
    return u;
}

typedef struct ClosureSt ClosureSt;
struct ClosureSt {
    const char * msg;
};
ClosureSt ClosureBld(void);
ClosureSt ClosureBld(void){
    ClosureSt s = {"Simple closure"};
    return s;
}

ClosureSt ClosureFn(ClosureSt);
ClosureSt ClosureFn(ClosureSt s){
    printf("%s\n",s.msg);
    return s;
}

void testClosure(void);
void testClosure(void)
{
    {
    ClosureScope cc = ClosureScopeBuild();
    ClosureCall(cc);
    }
    {
    ClosureUnion cu = ClosureUnionBuild();
    cu.ptr(cu.scope);
    }
    {
    ClosureSt s = ClosureBld();
    ClosureFn(s);
    }
}

/* cons char cdr */
typedef signed int Val;
Val Car(const Val *);
Val Car(const Val * lst){
    if (lst == 0)
    return 0;
    return lst[0];
}

const Val * Cdr(const Val *);
const Val * Cdr(const Val * lst){
    if (lst == 0)
    return 0;
    if (lst[0] == 0)
    return 0;
    if (lst[1] == 0)
    return 0;
    return &lst[1];
}
/*
High order function
  how we implement map reduce filter ?

*/
typedef struct Lst Lst;
struct Lst{
    char items[100];
};
typedef char (*Hof)(char);

Lst Map(Lst,Hof);
Lst Map(Lst lst, Hof hof){
    Lst r = {{0}};
    int i;
    for (i=0;i<100&&lst.items[i]!=0;i++)
    r.items[i] = hof(lst.items[i]);
    return r;
}
char Inc(char);
char Inc(char c){
    return c+1;
}
char Prn(char);
char Prn(char c){
    printf("%d\n",c);
    return c;
}

/* this is promising,
try making a table of it

i think i found how i'll implement the event store replication db for game XD
returning an entire array as value is not threadsafe at all XD

 */
typedef Val (*Lazy)(const Val val);
typedef struct Page Page;
struct Page{
    Val lst[100];
    const Val * lft;
};
Page Tok(const Val *, const Lazy *);
Page Tok(const Val * lst, const Lazy * lazy){
    Page page = {{0},0};
    if (lst != 0)
    {
        int h=0;
        int i;for (i=0;h<100&&lst[i]!=0;i++)
        {
            Val tmp = lst[i];
            {
                int j;for (j=0;tmp!=0&&lazy[j]!=0;j++)
                {
                    tmp = lazy[j](tmp);
                }
            }
            if (tmp !=0)
            {
                page.lst[h] = tmp;
                h++;
            }
            page.lft = &lst[i];
        }
    }
    return page;
}
Page Tek(const Page, const Lazy *);
Page Tek(const Page page, const Lazy * lazy){
    return Tok(page.lst,lazy);
}

Val Dec(const Val val);
Val Dec(const Val val){
    return val - 1;
}
Val Shw(const Val val);
Val Shw(const Val val){
    printf("lazy%d\n",val);
    return val;
}

void testHOF(void);
void testHOF(void){
    {
    Lst r = {{1,2,3,4,5,0}};
    Lst rr = Map(r,Inc);
    Map(rr,Prn);
    }
    {
    Val t[] = {1,2,3,4,5,6,7,0};
    Lazy lazy[] ={Shw,Dec,Shw,0} ;
    Tok(t,lazy);
    }
}

/* curry ? */


/* call all fuckin test */

int main(void){
    printf("self pointer return xperiment\n");
    {
    testStructCoroutine();
    testUnionCoroutine();
    }

    {
    GuardedHello("world");
    GuardedHello("computer");
    GuardedHello(0);
    }
    
    {
    testClosure();
    }

    {
    testHOF();
    }
    
    return 0;
}
