#include "def.h"
#include "macro.h"

typedef struct node {
    char * _key; /* dies enthaelt ein object */
    struct node * _l, * _r;
    char _rtag;
} Node;

#define KEY(p) ((p) -> _key)
#define LINKS(p) ((p) -> _l)
#define RECHTS(p) ((p) -> _r)
#define RTAG(p) ((p) -> _rtag)


/* TSEARCH(3C) */
typedef enum {
    preorder, postorder, endorder, leaf }
VISIT;


static INT AK_twalk(Node *, void (*)(OP*,VISIT,INT));
static void AK_tfree(Node **, void (*)(OP *, VISIT, OP, INT (*)(OP,OP), INT (*)(OP,OP)), OP, INT (*)(OP,OP), INT (*)(OP,OP));
static char ** AK_tsearch(char *, Node **, INT (*)(char*,char*));
static char ** AK_tdelete(char *, Node **, INT (*)(char*,char*));
static char ** AK_tfind(char *k, Node **rootp, INT (*compar)(char*,char*));
static void walk(Node *, void (*)(OP*,VISIT,INT), INT);
static void freeself_bintree_action(OP *, VISIT, OP, INT (*)(OP,OP), INT (*)(OP,OP));
static void fprint_bintree_action(OP *, VISIT, INT);
static void insert_bt_bt_action(OP *, VISIT, OP, INT (*)(OP,OP), INT (*)(OP,OP));
static void copy_bintree_action(OP *, VISIT, INT);
static void t_BINTREE_LIST_action(OP *, VISIT, INT);
static void t_BINTREE_SCHUR_action(OP *, VISIT, INT);
static void t_BINTREE_POLYNOM_action(OP *, VISIT, INT);
static void t_BINTREE_HOMSYM_action(OP *, VISIT, INT);
static void t_BINTREE_ELMSYM_action(OP *, VISIT, INT);
static void t_BINTREE_POWSYM_action(OP *, VISIT, INT);
static void t_BINTREE_MONOMIAL_action(OP *, VISIT, INT);
static void t_BINTREE_SCHUBERT_action(OP *, VISIT, INT);
static void t_BINTREE_GRAL_action(OP *, VISIT, INT);
static void t_BINTREE_SCHUR_action_apply(OP *, VISIT, INT);
static void t_BINTREE_POLYNOM_action_apply(OP *, VISIT, INT);
static void t_BINTREE_HOMSYM_action_apply(OP *, VISIT, INT);
static void t_BINTREE_POWSYM_action_apply(OP *, VISIT, INT);
static void t_BINTREE_MONOMIAL_action_apply(OP *, VISIT, INT);
static void t_BINTREE_ELMSYM_action_apply(OP *, VISIT, INT);

static char *_bt_p1, *_bt_p2, *_bt_p3; /* fur twalk */
#define TWALK(a,b) AK_twalk((Node *)a, b)
#define TSEARCH(a,b,c) AK_tsearch((char *)a, (Node **)b, c)
#define TFIND(a,b,c) AK_tfind((char*)a, (Node **) b, c)
#define TDELETE(a,b,c) AK_tdelete((char*)a, (Node **)b, c)

#ifdef BINTREETRUE
static void freeself_bintree_action(OP *a, VISIT type, OP bt, INT (*eh)(OP,OP), INT (*cf)(OP,OP))
{
    if ((type==postorder) ||  (type==leaf))
        freeall(*a);
}


INT freeself_bintree(OP a)
{
    OBJECTSELF d ;
    d = S_O_S(a);

    // Cast to Node** should be OK since the first member of
    // a Node struct is a char*?
    AK_tfree((Node**)&d.ob_charpointer,freeself_bintree_action,NULL,NULL,NULL);
    C_O_K(a,EMPTY);
    return OK;
}


INT init_bintree(OP a)
{
    OBJECTSELF d;
    C_O_K(a,BINTREE);
    d.ob_charpointer = (char *) NULL;
    C_O_S(a,d);
    return(OK);
}


static void length_bintree_action(OP *a, VISIT type, INT l)
{
    OP p1 = (OP ) _bt_p1;
    if ((type==postorder)||  (type==leaf))
    {
        inc(p1);
    }
}

static void fprint_bintree_action(OP *a, VISIT type, INT l)
{
    FILE *p1 = (FILE *) _bt_p1;
    if ((type==postorder)||  (type==leaf))
    {
        fprint(p1,*a);
        fprintf(p1," ");
        if (p1==stdout)
            {
            zeilenposition++;
            if (zeilenposition >70L) {
                fprintf(p1,"\n");
                zeilenposition=0L; }
            }
    }
}




INT length_bintree(OP a, OP b)
{
    OBJECTSELF d;
    m_i_i(0,b);
    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        }
    else
        {
        _bt_p1 = (char *) b;
        TWALK(d.ob_charpointer,length_bintree_action);
        }
    return OK;
}


/* gibt einen bintree aus */
INT fprint_bintree(FILE *fp, OP a)
{
    OBJECTSELF d;
    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        fprintf(fp,"empty tree");
        if (fp == stdout) zeilenposition += 10L;
        }
    else
        {
        _bt_p1 = (char *) fp;
        _bt_p2 = (char *) NULL;
        _bt_p3 =(char *)  NULL;
        TWALK(d.ob_charpointer,fprint_bintree_action);
        }
    return OK;
}


/* fuegt a in bintree bt ein. cf ist die vergleichsfunktion eh gibt
 * die operation bei schon vorhandenem gleichen eintrag an */
INT insert_bintree(OP a, OP bt, INT (*eh)(OP,OP), INT (*cf)(OP,OP))
{
    INT erg = OK;
    char ** result;

    if (S_O_K(a) == BINTREE)
        {
        OBJECTSELF d;
        d = S_O_S(a);
        if (d.ob_charpointer == NULL)
            {
            freeall(a);
            return INSERTOK;
            }
        d = S_O_S(bt);
                if (d.ob_charpointer == NULL)
                        {
                        swap(a,bt);
            freeall(a);
                        return INSERTOK;
                        }
        return insert_bt_bt(a,bt,eh,cf);
        }
    else if ( LISTP(a) )
        {
        OP z;
        z = a;
        if (S_L_S(z) != NULL)
            while (z != NULL)
                {
                insert_bintree(S_L_S(z),bt,eh,cf);
                C_L_S(z,NULL);
                z = S_L_N(z);
                }
        FREEALL(a);
        return INSERTOK;
        }

    /* default wert */
    if (cf == NULL) cf = comp;

    // ignore char* <-> OP type mismatch in comparison function?
    INT (*charcf)(char*,char*) = (INT (*)(char*,char*))cf;

    result = TSEARCH(a, &((S_O_S(bt)).ob_charpointer), charcf);
    if (*result == (char *)a)
        return INSERTOK;
                /* d.h. das element wurde eingefuegt */
    else             /* d.h. es wurde ein gleiches element festgestelt
		      * und result ist ein pointer darauf */
        {
        if (eh != NULL)
            (*eh)(a,(OP)*result);
        if (EMPTYP((OP)*result)) /* eq-handle hat geloescht */
            {
            OP z = (OP)*result;
            *z = *a;
            TDELETE(a, &((S_O_S(bt)).ob_charpointer), charcf);
            C_O_K(z,EMPTY);
            FREEALL(z);
            }
        FREEALL(a);

        return INSERTEQ;
        }
    ENDR("insert_bintree");
}


/* fuegt a was auch bintree ist in bintree bt ein.cf ist die
 * vergleichsfunktion eh gibt die operation bei schon vorhandenem
 * gleichen eintrag an.
 */
INT insert_bt_bt(OP a, OP bt, INT (*eh)(OP,OP), INT (*cf)(OP,OP))
{
    OBJECTSELF d;
    INT erg = OK;
    CTO(BINTREE,"insert_bt_bt(1)",a);
    CTO(BINTREE,"insert_bt_bt(2)",bt);

    d = S_O_S(a);
    // Cast to Node** should be OK since the first member of
    // a Node struct is a char*?
    AK_tfree((Node**)&d.ob_charpointer,insert_bt_bt_action,bt,eh,cf);
    C_O_K(a,EMPTY); /* leer setzen */
    erg += freeall(a);
    ENDR("insert_bt_bt");
}



static void insert_bt_bt_action(OP *a, VISIT type, OP bt, INT (*eh)(OP,OP), INT (*cf)(OP,OP))
{
    INT insert_erg;

    if ((type==postorder)||  (type==leaf))
    {
        insert_erg = insert_bintree(*a,bt,eh,cf);
    }
}



INT copy_bintree(OP a, OP b)
{
    OBJECTSELF d;

    init(BINTREE,b);
    d = S_O_S(a);
        _bt_p1 = (char *) b;
        _bt_p2 = (char *) NULL;
        _bt_p3 = (char *) NULL;
    TWALK(d.ob_charpointer,copy_bintree_action);
    return OK;
}

static void copy_bintree_action(OP *a, VISIT type, INT l)
{
    OP bt = (OP) _bt_p1;
    if ((type==postorder)||  (type==leaf))
    {
        OP c=callocobject();
        copy(*a,c);
        insert_bintree(c,bt,NULL,NULL);
    }
}


OP find_user_bintree(OP a, OP b, INT (*f)(char*,char*))
{
    char ** result;
    result = TFIND(a, &((S_O_S(b)).ob_charpointer), f);
    if (result == NULL) return NULL;
    return (OP) *result;
}

/* test ob a in b */
OP find_bintree(OP a, OP b)
{
    char ** result;

    // ignore char* <-> OP type mismatch in comparison function?
    INT (*charcf)(char*,char*) = (INT (*)(char*,char*))comp;

    result = TFIND(a, &((S_O_S(b)).ob_charpointer), charcf);
    if (result == NULL) return NULL;
    return (OP) *result;
}


static Node ** bi_find(char *k, Node ** rootp, INT (*compar)(char*,char*), Node ** parent, INT *c)
{
    *parent = (Node *) 0;
    if (rootp && *rootp)
        for (;;)
        {
            if ((*c = (*compar) (k,KEY(*rootp))) == 0L)
                break;
            *parent = *rootp;
            if( *c < 0L)
            {
                rootp = & LINKS(*parent);
                if (! *rootp) break;
            }
            else {
                rootp = & RECHTS(*parent);
                if (RTAG(*parent)) break;
            }
        }

    return (rootp);
}


static char ** AK_tfind(char *k, Node **rootp, INT (*compar)(char*,char*))
{
    Node * parent;
        INT c;
    if ((rootp = bi_find(k,rootp,compar, &parent, &c)))
                if (*rootp && (c == 0))
                        return (&KEY(*rootp));
    return NULL;
}


/* Schreiner: UNIX Sprechstude p.248 */
static char ** AK_tdelete(char *k, Node ** rootp, INT (*compar)(char*,char*))
{
    register Node *p;
    char **result;
    Node * parent; INT c;

    if (! (rootp = bi_find(k,rootp,compar,&parent, &c))
        || ! * rootp || c)
            return (char **) 0;

    result = ! parent ? & KEY (*rootp): & KEY(parent);

    if (!RTAG(*rootp)) {
        Node * R = RECHTS(*rootp);
        if (!LINKS(*rootp)) {
            p = *rootp, *rootp=R, SYM_free(p);
            return result;
            }
        if (! LINKS(R))
            LINKS(R) = LINKS(*rootp), SYM_free(*rootp), *rootp = R;
        else    {
            p = R;
            while(LINKS(LINKS(p)))    p = LINKS(p);
            LINKS(LINKS(p)) = LINKS(*rootp);
            SYM_free(*rootp), *rootp = LINKS(p);
            LINKS(p) = RTAG(LINKS(p))? (Node *)0: RECHTS(LINKS(p));
            RECHTS(*rootp) = R, RTAG(*rootp)=0;
            }
        if ((p = LINKS(*rootp))) {
            while (! RTAG(p)) p = RECHTS(p);
            RECHTS(p) = *rootp, RTAG(p)=1;
            }
        }
    else if ((p=LINKS(*rootp))) {
        while(! RTAG(p)) p = RECHTS(p);
        RECHTS(p) = RECHTS(*rootp), RTAG(p)=1;
        p = *rootp, *rootp = LINKS(p), SYM_free(p);
        }
    else if (parent && RECHTS(parent) == *rootp) {
        p = *rootp;
        RECHTS(parent) = RECHTS(p), RTAG(parent) = 1;
        SYM_free(p);
        }
    else
        SYM_free(*rootp), *rootp = (Node *)0;

    return result;
}

static char ** AK_tsearch(char *k, Node ** rootp, INT (*compar)(char*,char*))
{
    register Node *p;
    Node * parent;
    INT c;

    if ((rootp = bi_find(k,rootp,compar, &parent, &c))) {
        if (*rootp && c == 0)
            return (&KEY(*rootp));
        else if ((p = (Node *) SYM_malloc(sizeof(Node))))
        {
            KEY(p) =k;
            LINKS(p) = (Node *) 0;
            if (parent && c>0)
            {
                RECHTS(p) = RECHTS(parent);
                RECHTS(parent) = p, RTAG(parent)= 0;
            }
            else
            {
                RECHTS(p) = parent;
                * rootp = p;
            }
            RTAG(p) = 1;
            return (&KEY(p));
        }
    }
    return ((char**) 0);
}


/* fuer parameter bei action */
static void walk(Node *root, void (*action)(OP*,VISIT,INT), INT l)
{
    /* ignore OP* <-> char** type mismatch on action function? */
    void (*charaction)(char**,VISIT,INT) = (void (*)(char**,VISIT,INT))action;

    if (! LINKS(root) && RTAG(root))
        (*charaction) (&KEY(root), leaf, l);
    else
    {
        (*charaction) (&KEY(root), preorder, l);
        if (LINKS(root))
            walk(LINKS(root), action, l+1L);
        (*charaction) (&KEY(root), postorder, l);
        if (! RTAG(root))
            walk(RECHTS(root), action, l+1L);
        (*charaction) (&KEY(root), endorder, l);

    }
}

static INT AK_twalk(Node *root, void (*action)(OP*,VISIT,INT))
{
    if (root)
        walk(root,action,0L);
    return OK;
}


/* type of "a" inferred from insert_bt_bt which passes in
 * a = insert_bt_bt_action. Likewise the types of "eh" and "cf"
 * should match the args of insert_bt_bt_action.
 */
static void AK_tfree(Node **rootp, void (*a)(OP *, VISIT, OP, INT (*)(OP,OP), INT (*)(OP,OP)), OP bt, INT (*eh)(OP,OP), INT (*cf)(OP,OP))
{
    register Node *root,*p;

    if (!rootp || ! (root = *rootp))
        return;
    * rootp = (Node *)0;
    for (;;)
    {
        while ((p = LINKS(root)))
            root = p;
        if (RTAG(root))
        {
            if (a)
                (* a)((OP*)&KEY(root), leaf,bt,eh,cf);
            do
            {
                p=RECHTS(root),SYM_free(root),root=p;
                if (! root)
                    return;
                if (a)
                    (* a)((OP*)&KEY(root),postorder,bt,eh,cf);
            } while(RTAG(root));
        }
        else
        {
            if (a)
                (* a)((OP*)&KEY(root),postorder,bt,eh,cf);
        }
        p=RECHTS(root),SYM_free(root),root=p;
    }
}


/* input: BINTREE object a; output: sorted VECTOR object b with copy
 * of the objects in a as content. a and b may be equal.
 */
INT t_BINTREE_VECTOR(OP a, OP b)
{
    INT erg = OK;
    OP c;
    CTO(BINTREE,"t_BINTREE_VECTOR",a);
    c = callocobject();
    erg += t_BINTREE_LIST(a,c);
    erg += t_LIST_VECTOR(c,b);
    erg += freeall(c);
    ENDR("t_BINTREE_VECTOR");
}

/* wandelt einen BINTREE in ein LIST object um die liste ist nach den
 * gleichen vergleich sortiert */
INT t_BINTREE_LIST(OP a, OP b)
{
    INT erg = OK;
    OP h, *h2;
    OBJECTSELF d;

    CTO(BINTREE,"t_BINTREE_LIST",a);
    CE2(a,b,t_BINTREE_LIST);

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(LIST,b);
        goto endr_ende;
        }

    h = callocobject();
    erg += b_sn_l(NULL,NULL,h);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    erg += TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_LIST_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        erg += b_sn_l(NULL,NULL,b);

    C_O_K(S_L_N(h),EMPTY);
    freeall(S_L_N(h));
    C_L_N(h,NULL);
    erg += freeall(h);
    ENDR("t_BINTREE_LIST");
}



static void t_BINTREE_LIST_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder) ||  (type==leaf))
        {
        **(OP **)_bt_p1 = callocobject();
        b_sn_l(callocobject(),NULL,**(OP **)_bt_p1);
        copy(*a,S_L_S(**(OP **)_bt_p1));
        *(OP **)_bt_p1 = & S_L_N(**(OP **)_bt_p1);
        }
}


#ifdef SCHURTRUE
INT t_BINTREE_SCHUR_apply(OP a)
{
    OP b;
    OP *h2,h;
    OBJECTSELF d;
    INT erg = OK;
    b = CALLOCOBJECT();

    d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(SCHUR,a);
                goto endr_ende;
                }

        h = CALLOCOBJECT();
        erg += b_sn_s(NULL,NULL,h);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_SCHUR_action_apply);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
        erg += b_sn_s(NULL,NULL,b);
                }

        C_O_K(S_L_N(h),EMPTY);
        FREEALL(S_L_N(h));
        C_L_N(h,NULL);
        FREEALL(h);

    erg += swap(b,a);
    FREEALL(b);

    ENDR("t_BINTREE_SCHUR_apply");
}

/* wandelt einen BINTREE in ein SCHUR object um die liste ist nach den
 * gleichen vergleich sortiert */
INT t_BINTREE_SCHUR(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;

    CTO(BINTREE,"t_BINTREE_SCHUR(1)",a);

    if (a == b) {
        erg += t_BINTREE_SCHUR_apply(a);
        goto endr_ende;
        }

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(SCHUR,b);
        goto endr_ende;
        }

    h = CALLOCOBJECT();
    erg += b_sn_l(NULL,NULL,h);
    C_O_K(h,SCHUR);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_SCHUR_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        {
        erg += b_sn_l(NULL,NULL,b);
        C_O_K(b,SCHUR);
        }

    C_O_K(S_L_N(h),EMPTY);
    erg += freeall(S_L_N(h));
    C_L_N(h,NULL);
    FREEALL(h);
    ENDR("t_BINTREE_SCHUR");
}



static void t_BINTREE_SCHUR_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder)||  (type==leaf))
        {
        **(OP**)_bt_p1 = CALLOCOBJECT();
        b_sn_s(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
        copy_monom(*a,S_L_S(**(OP**)_bt_p1));
        *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
        }
}

static void t_BINTREE_SCHUR_action_apply(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = CALLOCOBJECT();
                b_sn_s(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
                swap(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

INT t_BINTREE_POWSYM_apply(OP a)
{
    OP b;
    OP *h2,h;
    OBJECTSELF d;
    INT erg = OK;
    CTO(BINTREE,"t_BINTREE_POWSYM_apply(1)",a);

    b = CALLOCOBJECT();

    d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(POWSYM,a);
                goto endr_ende;
                }

        h = CALLOCOBJECT();
        erg += b_sn_l(NULL,NULL,h);
        C_O_K(h,POWSYM);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_POWSYM_action_apply);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
        erg += b_sn_l(NULL,NULL,b);
                C_O_K(b,POWSYM);
                }

        C_O_K(S_L_N(h),EMPTY);
        erg += freeall(S_L_N(h));
        C_L_N(h,NULL);
        erg += freeall(h);

    erg += swap(b,a);
    erg += freeall(b);

    ENDR("t_BINTREE_POWSYM_apply");
}

/* wandelt einen BINTREE in ein POWSYM object um die liste ist nach
 * den gleichen vergleich sortiert */
INT t_BINTREE_POWSYM(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;
    CTO(BINTREE,"t_BINTREE_POWSYM(1)",a);

    if (a == b) {
        erg += t_BINTREE_POWSYM_apply(a);
        goto endr_ende;
        }

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(POWSYM,b);
        goto endr_ende;
        }

    h = CALLOCOBJECT();
    erg += b_sn_l(NULL,NULL,h);
    C_O_K(h,POWSYM);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_POWSYM_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        {
        erg += b_sn_l(NULL,NULL,b);
        C_O_K(b,POWSYM);
        }

    C_O_K(S_L_N(h),EMPTY);
    erg += freeall(S_L_N(h));
    C_L_N(h,NULL);
    erg += freeall(h);
    ENDR("t_BINTREE_POWSYM");
}


static void t_BINTREE_POWSYM_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder)||  (type==leaf))
        {
        **(OP**)_bt_p1 = CALLOCOBJECT();
        b_sn_l(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
        C_O_K(**(OP**)_bt_p1,POWSYM);
        copy_monom(*a,S_L_S(**(OP**)_bt_p1));
        *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
        }
}
static void t_BINTREE_POWSYM_action_apply(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = CALLOCOBJECT();
                b_sn_l(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
                C_O_K(**(OP**)_bt_p1,POWSYM);
                swap(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

INT t_BINTREE_ELMSYM_apply(OP a)
{
    OP b;
    OP *h2,h;
    OBJECTSELF d;
    INT erg = OK;
    CTO(BINTREE,"t_BINTREE_ELMSYM_apply(1)",a);
    b = CALLOCOBJECT();

    d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(ELMSYM,a);
                goto endr_ende;
                }

        h = CALLOCOBJECT();
        erg += b_sn_l(NULL,NULL,h);
        C_O_K(h,ELMSYM);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_ELMSYM_action_apply);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
        erg += b_sn_l(NULL,NULL,b);
                C_O_K(b,ELMSYM);
                }

        C_O_K(S_L_N(h),EMPTY);
        erg += freeall(S_L_N(h));
        C_L_N(h,NULL);
        erg += freeall(h);

    erg += swap(b,a);
    erg += freeall(b);

    ENDR("t_BINTREE_ELMSYM_apply");
}


/* wandelt einen BINTREE in ein ELMSYM object um die liste ist nach
 * den gleichen vergleich sortiert */
INT t_BINTREE_ELMSYM(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;
    CTO(BINTREE,"t_BINTREE_ELMSYM(1)",a);

    if (a == b) {
        erg += t_BINTREE_ELMSYM_apply(a);
        goto endr_ende;
        }

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(ELMSYM,b);
        goto endr_ende;
        }

    h = CALLOCOBJECT();
    erg += b_sn_l(NULL,NULL,h);
    C_O_K(h,ELMSYM);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_ELMSYM_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        {
        erg += b_sn_l(NULL,NULL,b);
        C_O_K(b,ELMSYM);
        }

    C_O_K(S_L_N(h),EMPTY);
    erg += freeall(S_L_N(h));
    C_L_N(h,NULL);
    erg += freeall(h);
    ENDR("t_BINTREE_ELMSYM");
}


static void t_BINTREE_ELMSYM_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder)||  (type==leaf))
        {
        **(OP**)_bt_p1 = CALLOCOBJECT();
        b_sn_l(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
        C_O_K(**(OP**)_bt_p1,ELMSYM);
        copy_monom(*a,S_L_S(**(OP**)_bt_p1));
        *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
        }
}


static void t_BINTREE_ELMSYM_action_apply(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = CALLOCOBJECT();
                b_sn_l(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
                C_O_K(**(OP**)_bt_p1,ELMSYM);
                swap(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

INT t_BINTREE_HOMSYM_apply(OP a)
{
    OP b;
    OP *h2,h;
    OBJECTSELF d;
    INT erg = OK;
    CTO(BINTREE,"t_BINTREE_HOMSYM_apply(1)",a);
    b = CALLOCOBJECT();

    d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(HOMSYM,a);
                goto endr_ende;
                }

        h = CALLOCOBJECT();
        erg += b_sn_l(NULL,NULL,h);
        C_O_K(h,HOMSYM);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_HOMSYM_action_apply);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
        erg += b_sn_l(NULL,NULL,b);
                C_O_K(b,HOMSYM);
                }

        C_O_K(S_L_N(h),EMPTY);
        erg += freeall(S_L_N(h));
        C_L_N(h,NULL);
        erg += freeall(h);

    erg += swap(b,a);
    erg += freeall(b);

    ENDR("t_BINTREE_HOMSYM_apply");
}


/* wandelt einen BINTREE in ein HOMSYM object um die liste ist nach
 * den gleichen vergleich sortiert */
INT t_BINTREE_HOMSYM(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;
    CTO(BINTREE,"t_BINTREE_HOMSYM(1)",a);

    if (a == b) {
        erg += t_BINTREE_HOMSYM_apply(a);
        goto endr_ende;
        }

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(HOMSYM,b);
        goto endr_ende;
        }

    h = CALLOCOBJECT();
    erg += b_sn_l(NULL,NULL,h);
    C_O_K(h,HOMSYM);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_HOMSYM_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        {
        erg += b_sn_l(NULL,NULL,b);
        C_O_K(b,HOMSYM);
        }

    C_O_K(S_L_N(h),EMPTY);
    erg += freeall(S_L_N(h));
    C_L_N(h,NULL);
    erg += freeall(h);
    ENDR("t_BINTREE_HOMSYM");
}


static void t_BINTREE_HOMSYM_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder)||  (type==leaf))
        {
        **(OP**)_bt_p1 = CALLOCOBJECT();
        b_sn_l(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
        C_O_K(**(OP**)_bt_p1,HOMSYM);
        copy_monom(*a,S_L_S(**(OP**)_bt_p1));
        *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
        }
}


static void t_BINTREE_HOMSYM_action_apply(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = CALLOCOBJECT();
                b_sn_l(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
                C_O_K(**(OP**)_bt_p1,HOMSYM);
                swap(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

#endif /* SCHURTRUE */

#ifdef SCHUBERTTRUE

/* wandelt einen BINTREE in ein SCHUBERT object um die liste ist nach
 * den gleichen vergleich sortiert */
INT t_BINTREE_SCHUBERT(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;
    CTO(BINTREE,"t_BINTREE_SCHUBERT(1)",a);

    CE2(a,b,t_BINTREE_SCHUBERT);

        d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(SCHUBERT,b);
                goto endr_ende;
                }

        h = callocobject();
        erg += b_sn_l(NULL,NULL,h);
        C_O_K(h,SCHUBERT);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_SCHUBERT_action);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
                erg += b_sn_l(NULL,NULL,b);
                C_O_K(b,SCHUBERT);
                }

        C_O_K(S_L_N(h),EMPTY);
        erg += freeall(S_L_N(h));
        C_L_N(h,NULL);
        erg += freeall(h);
        ENDR("t_BINTREE_SCHUBERT");
}



static void t_BINTREE_SCHUBERT_action(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = callocobject();
                b_sn_l(callocobject(),NULL,**(OP**)_bt_p1);
                C_O_K(**(OP**)_bt_p1,SCHUBERT);
                copy_monom(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

#endif /* SCHUBERTTRUE */
static void t_BINTREE_GRAL_action(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = callocobject();
                b_sn_l(callocobject(),NULL,**(OP**)_bt_p1);
                C_O_K(**(OP**)_bt_p1,GRAL);
                copy_monom(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}


/* wandelt einen BINTREE in ein GRAL object um die liste ist nach den
 * gleichen vergleich sortiert */
INT t_BINTREE_GRAL(OP a, OP b)
{
        OP *h2,h;
        INT erg = OK;
        OBJECTSELF d;

        CE2(a,b,t_BINTREE_GRAL);

        d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(GRAL,b);
                goto endr_ende;
                }

        h = callocobject();
        erg += b_sn_l(NULL,NULL,h);
        C_O_K(h,GRAL);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_GRAL_action);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
                erg += b_sn_l(NULL,NULL,b);
                C_O_K(b,GRAL);
                }

        C_O_K(S_L_N(h),EMPTY);
        erg += freeall(S_L_N(h));
        C_L_N(h,NULL);
        erg += freeall(h);
        ENDR("t_BINTREE_GRAL");
}


INT t_BINTREE_MONOMIAL_apply(OP a)
{
    OP b;
    OP *h2,h;
    OBJECTSELF d;
    INT erg = OK;
    b = callocobject();

    d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(MONOMIAL,a);
                goto endr_ende;
                }

        h = callocobject();
        erg += b_sn_l(NULL,NULL,h);
        C_O_K(h,MONOMIAL);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_MONOMIAL_action_apply);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                {
        erg += b_sn_l(NULL,NULL,b);
                C_O_K(b,MONOMIAL);
                }

        C_O_K(S_L_N(h),EMPTY);
        erg += freeall(S_L_N(h));
        C_L_N(h,NULL);
        erg += freeall(h);

    erg += swap(b,a);
    erg += freeall(b);

    ENDR("t_BINTREE_MONOMIAL_apply");
}

/* wandelt einen BINTREE in ein MONOMIAL object um die liste ist nach
 * den gleichen vergleich sortiert */
INT t_BINTREE_MONOMIAL(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;

    if (a == b) {
        erg += t_BINTREE_MONOMIAL_apply(a);
        goto endr_ende;
        }

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(MONOMIAL,b);
        goto endr_ende;
        }

    h = callocobject();
    erg += b_sn_l(NULL,NULL,h);
    C_O_K(h,MONOMIAL);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_MONOMIAL_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        {
        erg += b_sn_l(NULL,NULL,b);
        C_O_K(b,MONOMIAL);
        }

    C_O_K(S_L_N(h),EMPTY);
    erg += freeall(S_L_N(h));
    C_L_N(h,NULL);
    erg += freeall(h);
    ENDR("t_BINTREE_MONOMIAL");
}


static void t_BINTREE_MONOMIAL_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder)||  (type==leaf))
        {
        **(OP**)_bt_p1 = callocobject();
        b_sn_l(callocobject(),NULL,**(OP**)_bt_p1);
        C_O_K(**(OP**)_bt_p1,MONOMIAL);
        copy_monom(*a,S_L_S(**(OP**)_bt_p1));
        *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
        }
}


static void t_BINTREE_MONOMIAL_action_apply(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = callocobject();
                b_sn_l(callocobject(),NULL,**(OP**)_bt_p1);
                C_O_K(**(OP**)_bt_p1,MONOMIAL);
                swap(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

#endif /* BINTREETRUE */
#ifdef BINTREETRUE
INT t_BINTREE_POLYNOM_apply(OP a)
{
    OP b;
    OP *h2,h;
    OBJECTSELF d;
    INT erg = OK;
    b = CALLOCOBJECT();

    d = S_O_S(a);
        if (d.ob_charpointer == NULL)
                {
                erg += init(POLYNOM,a);
                goto endr_ende;
                }

        h = CALLOCOBJECT();
        erg += b_sn_s(NULL,NULL,h);

        h2 = &S_L_N(h);
                _bt_p1 = (char *)&h2;
                _bt_p2 = (char *)NULL;
                _bt_p3 = (char *)NULL;
        TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_POLYNOM_action_apply);

        if (S_L_N(h) != NULL)
                *b = *S_L_N(h);
        else
                erg += b_sn_po(NULL,NULL,b);

        C_O_K(S_L_N(h),EMPTY);
        FREEALL(S_L_N(h));
        C_L_N(h,NULL);
        FREEALL(h);

    erg += swap(b,a);
    FREEALL(b);

    ENDR("t_BINTREE_POLYNOM_apply");
}

/* wandelt einen BINTREE in ein POLYNOM object um die liste ist nach
 * den gleichen vergleich sortiert */
INT t_BINTREE_POLYNOM(OP a, OP b)
{
    OP *h2,h;
    INT erg = OK;
    OBJECTSELF d;

    CTO(BINTREE,"t_BINTREE_POLYNOM(1)",a);

    if (a == b) {
        erg += t_BINTREE_POLYNOM_apply(a);
        goto endr_ende;
        }

    d = S_O_S(a);
    if (d.ob_charpointer == NULL)
        {
        erg += init(POLYNOM,b);
        goto endr_ende;
        }

    h = CALLOCOBJECT();
    erg += b_sn_l(NULL,NULL,h);
    C_O_K(h,POLYNOM);

    h2 = &S_L_N(h);
        _bt_p1 = (char *)&h2;
        _bt_p2 = (char *)NULL;
        _bt_p3 = (char *)NULL;
    TWALK((S_O_S(a)).ob_charpointer,t_BINTREE_POLYNOM_action);

    if (S_L_N(h) != NULL)
        *b = *S_L_N(h);
    else
        {
        erg += b_sn_l(NULL,NULL,b);
        C_O_K(b,POLYNOM);
        }

    C_O_K(S_L_N(h),EMPTY);
    erg += freeall(S_L_N(h));
    C_L_N(h,NULL);
    FREEALL(h);
    ENDR("t_BINTREE_POLYNOM");
}


static void t_BINTREE_POLYNOM_action(OP *a, VISIT type, INT l)
{
    if ((type==postorder)||  (type==leaf))
        {
        **(OP**)_bt_p1 = CALLOCOBJECT();
        b_sn_po(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
        copy_monom(*a,S_L_S(**(OP**)_bt_p1));
        *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
        }
}


static void t_BINTREE_POLYNOM_action_apply(OP *a, VISIT type, INT l)
{
        if ((type==postorder)||  (type==leaf))
                {
                **(OP**)_bt_p1 = CALLOCOBJECT();
                b_sn_po(CALLOCOBJECT(),NULL,**(OP**)_bt_p1);
                swap(*a,S_L_S(**(OP**)_bt_p1));
                *(OP**)_bt_p1 = & S_L_N(**(OP**)_bt_p1);
                }
}

#endif /* BINTREETRUE */
