/*
 * poly - polynomial functions
 *
 * Copyright (C) 1999,2021,2023,2026  Ernest Bowen and Landon Curt Noll
 *
 * Primary author:  Ernest Bowen
 *
 * Calc is open software; you can redistribute it and/or modify it under
 * the terms of the version 2.1 of the GNU Lesser General Public License
 * as published by the Free Software Foundation.
 *
 * Calc is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
 * Public License for more details.
 *
 * A copy of version 2.1 of the GNU Lesser General Public License is
 * distributed with calc under the filename COPYING-LGPL.  You should have
 * received a copy with calc; if not, write to Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Under source code control:   1995/12/02 03:10:28
 * File existed as early as:    1995
 *
 * chongo <was here> /\oo/\     http://www.isthe.com/chongo/
 * Share and enjoy!  :-)        http://www.isthe.com/chongo/tech/comp/calc/
 */

/*
 * important <system> header includes
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

/*
 * calc local src includes
 */
#include "value.h"

#include "banned.h" /* include after all other includes */

bool
evp(LISTELEM *cp, LISTELEM *x, VALUE *vres)
{
    VALUE v, tmp1, tmp2;
    bool s;

    s = false;
    while (cp) {
        if (s) {
            mulvalue(vres, &x->e_value, &tmp1);
            freevalue(vres);
            *vres = tmp1;
        }
        v = cp->e_value;
        if (v.v_type == V_LIST) {
            if (evalpoly(v.v_list, x->e_next, &tmp1)) {
                if (s) {
                    addvalue(&tmp1, vres, &tmp2);
                    freevalue(&tmp1);
                    freevalue(vres);
                    *vres = tmp2;
                } else {
                    s = true;
                    *vres = tmp1;
                }
            }
        } else {
            if (s) {
                addvalue(&v, vres, &tmp1);
                freevalue(vres);
                *vres = tmp1;
            } else {
                s = true;
                copyvalue(&v, vres);
            }
        }
        cp = cp->e_prev;
    }
    return s;
}

bool
evalpoly(LIST *clist, LISTELEM *x, VALUE *vres)
{
    LISTELEM *cp;
    VALUE v;

    cp = clist->l_first;
    if (cp == NULL) {
        return false;
    }
    if (x == NULL) {
        v = cp->e_value;
        if (v.v_type == V_LIST) {
            return evalpoly(v.v_list, x->e_next, vres);
        }
        copyvalue(&v, vres);
        return true;
    }
    return evp(clist->l_last, x, vres);
}

void
insertitems(LIST *lp1, LIST *lp2)
{
    LISTELEM *ep;

    for (ep = lp2->l_first; ep; ep = ep->e_next) {
        if (ep->e_value.v_type == V_LIST) {
            insertitems(lp1, ep->e_value.v_list);
        } else {
            insertlistlast(lp1, &ep->e_value);
        }
    }
}

long
countlistitems(LIST *lp)
{
    LISTELEM *ep;

    long n = 0;
    for (ep = lp->l_first; ep; ep = ep->e_next) {
        if (ep->e_value.v_type == V_LIST) {
            n += countlistitems(ep->e_value.v_list);
        } else {
            n++;
        }
    }
    return n;
}

void
addlistitems(LIST *lp, VALUE *vres)
{
    LISTELEM *ep;
    VALUE tmp;

    for (ep = lp->l_first; ep; ep = ep->e_next) {
        addvalue(vres, &ep->e_value, &tmp);
        freevalue(vres);
        *vres = tmp;
        if (vres->v_type < 0) {
            return;
        }
    }
}

void
addlistinv(LIST *lp, VALUE *vres)
{
    LISTELEM *ep;
    VALUE tmp1, tmp2;

    for (ep = lp->l_first; ep; ep = ep->e_next) {
        if (ep->e_value.v_type == V_LIST) {
            addlistinv(ep->e_value.v_list, vres);
        } else {
            invertvalue(&ep->e_value, &tmp1);
            addvalue(vres, &tmp1, &tmp2);
            freevalue(&tmp1);
            freevalue(vres);
            *vres = tmp2;
        }
        if (vres->v_type < 0) {
            return;
        }
    }
}
