/**********
Copyright 1990 Regents of the University of California.  All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/

/*
 * Code to deal with breakpoints and tracing.
 */

#include "ngspice/ngspice.h"
#include "ngspice/cpdefs.h"
#include "ngspice/ftedefs.h"
#include "ngspice/dvec.h"
#include "ngspice/ftedebug.h"
#include "breakp2.h"


/* global linked list to store .save data and breakpoint data */
struct dbcomm *dbs = NULL;      /* export for iplot */

/* used in breakp.c and breakp2.c */
int debugnumber = 1;

static char *copynode(char* s);


/* Analyse the data given by the .save card or 'save' command.
   Store the data in the global dbs struct.
*/

/* Save a vector. */

void
com_save(wordlist *wl)
{
    settrace(wl, VF_ACCUM, NULL);
}


/* Save a vector with the analysis type given (name). */
void
com_save2(wordlist *wl, char *name)
{
    settrace(wl, VF_ACCUM, name);
}


void
settrace(wordlist *wl, int what, char *name)
{
    struct dbcomm *d, *last, *dbcheck;

    if (!ft_curckt) {
        fprintf(cp_err, "Error: no circuit loaded\n");
        return;
    }

    if (dbs)
        for (last = dbs; last->db_next; last = last->db_next)
            ;
    else
        last = NULL;

    for (;wl ;wl = wl->wl_next) {
        char *s = cp_unquote(wl->wl_word);
        char *db_nodename1 = NULL;
        char db_type = 0;
        if (eq(s, "all") || eq(s, "nosub")) {
            switch (what) {
            case VF_PRINT:
                db_type = DB_TRACEALL;
                break;
            case VF_ACCUM:
                db_nodename1 = copy(s);
                db_type = DB_SAVE;
                break;
            }
            tfree(s);
        } else {
            switch (what) {
            case VF_PRINT:
                db_type = DB_TRACENODE;
                break;
            case VF_ACCUM:
                db_type = DB_SAVE;
                break;
            }
            /* v(2) --> 2, i(vds) --> vds#branch */
            db_nodename1 = copynode(s);
            tfree(s);
            if (!db_nodename1)  /* skip on error */
                continue;
        }

        /* Don't save a nodename more than once, except for token 'all' */
        if (db_type == DB_SAVE) {
            for (dbcheck = dbs; dbcheck; dbcheck = dbcheck->db_next) {
                if (dbcheck->db_type == DB_SAVE && eq(dbcheck->db_nodename1, db_nodename1) &&
                    !eq("all", db_nodename1)) {
                    tfree(db_nodename1);
                    goto loopend;
                }
            }
        }

        d = TMALLOC(struct dbcomm, 1);
        d->db_analysis = name;
        d->db_type = db_type;
        d->db_nodename1 = db_nodename1;
        d->db_number = debugnumber++;

        if (last)
            last->db_next = d;
        else
            ft_curckt->ci_dbs = dbs = d;

        last = d;

    loopend:;
    }
}


/* retrieve the save nodes from dbs into an array */
int
ft_getSaves(struct save_info **savesp)
/* global variable: dbs */
{
    struct dbcomm *d;
    int count = 0, i = 0;
    struct save_info *array;

    for (d = dbs; d; d = d->db_next)
        if (d->db_type == DB_SAVE)
            count++;

    if (!count)
        return (0);

    *savesp = array = TMALLOC(struct save_info, count);

    for (d = dbs; d; d = d->db_next)
        if (d->db_type == DB_SAVE) {
            array[i].used = 0;
            if (d->db_analysis)
                array[i].analysis = copy(d->db_analysis);
            else
                array[i].analysis = NULL;
            array[i++].name = copy(d->db_nodename1);
        }

    return (count);
}


/* v(2) --> 2, i(vds) --> vds#branch, 3 --> 3, @mn1[vth0] --> @mn1[vth0]
 *   derived from wordlist *gettoks(char *s)
 */

static char*
copynode(char *s)
{
    char *l, *r;
    char *ret = NULL;

    if (strchr(s, '('))
        s = stripWhiteSpacesInsideParens(s);
    else
        s = copy(s);

    l = strrchr(s, '(');
    if (!l)
        return s;

    r = strchr(s, ')');
    if (!r) {
        fprintf(cp_err, "Warning: Missing ')' in %s\n  Not saved!\n", s);
        tfree(s);
        return NULL;
    }

    *r = '\0';
    if (*(l - 1) == 'i' || *(l - 1) == 'I')
        ret = tprintf("%s#branch", l + 1);
    else
        ret = copy(l + 1);

    tfree(s);
    return ret;
}
