/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993 Jason I. Gobat and Darren C. Atkinson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:	problem.c						*
 *									*
 * Description:	This file contains the function definitions which	*
 *		relate to the problem instance.				*
 ************************************************************************/

# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include "problem.h"
# include "allocate.h"
# define  ELEMENTS
# include "element.h"

Problem problem;


static struct material empty_material = {NULL, "default material",
						0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static struct constraint empty_constraint = {NULL, "default constraint",
						{0, 0, 0, 0, 0, 0, 0}};


int node_cmp (n1, n2)
    Item n1, n2;
{
    return ((Node) n1) -> number - ((Node) n2) -> number;
}


int element_cmp (e1, e2)
    Item e1, e2;
{
    return ((Element) e1) -> number - ((Element) e2) -> number;
}


int material_cmp (m1, m2)
    Item m1, m2;
{
    return strcmp (((Material) m1) -> name, ((Material) m2) -> name);
}


int force_cmp (f1, f2)
    Item f1, f2;
{
    return strcmp (((Force) f1) -> name, ((Force) f2) -> name);
}


int constraint_cmp (c1, c2)
    Item c1, c2;
{
    return strcmp (((Constraint) c1) -> name, ((Constraint) c2) -> name);
}


int distributed_cmp (d1, d2)
    Item d1, d2;
{
    return strcmp (((Distributed) d1) -> name, ((Distributed) d2) -> name);
}


Definition defnlookup (s)
    char *s;
{
    int i, length;

    length = 0;
    while (!isspace (s [length]))
	length ++;

    i = 0;
    while (ElementArray [i].name != NULL) {
	if (!strncmp (ElementArray [i].name, s, length))
	    return ElementArray [i].definition;
	i ++;
    }

    error ("%s have no definition", s);
    return NULL;
}


static int node_resolve (item)
    Item item;
{
    struct force      f;
    struct constraint c;
    Tree              tree;
    Node              node = (Node) item;


    problem.nodes [node -> number] = node;

    tree = problem.constraint_tree;
    c.name = (char *) node -> constraint;

    if (c.name != NULL) {
	node -> constraint = (Constraint) TreeSearch (tree, &c);

	if (node -> constraint == NULL) {
	    error ("node %d uses undefined constraint %s", node->number,c.name);
	    problem.numerrors ++;
	    Deallocate (c.name);
	}
    } else
	node -> constraint = &empty_constraint;


    tree = problem.force_tree;
    f.name = (char *) node -> force;

    if (f.name != NULL) {
	node -> force = (Force) TreeSearch (tree, &f);

	if (node -> force == NULL) {
	    error ("node %d uses undefined force %s", node -> number, f.name);
	    problem.numerrors ++;
	    Deallocate (f.name);
	}
    }

    return 0;
}


static int element_resolve (item)
    Item item;
{
    unsigned           i;
    unsigned           num;
    struct material    m;
    struct distributed d;
    Tree               tree;
    Element            element = (Element) item;


    problem.elements [num = element -> number] = element;

    tree = problem.material_tree;
    m.name = (char *) element -> material;

    if (m.name != NULL) {
	element -> material = (Material) TreeSearch (tree, &m);

	if (element -> material == NULL) {
	    error ("element %d uses undefined material %s", num, m.name);
	    problem.numerrors ++;
	    Deallocate (m.name);
	}
    } else
	element -> material = &empty_material;


    tree = problem.distributed_tree;

    for (i = 1; i <= element -> numdistributed; i ++) {
	d.name = (char *) element -> distributed [i];
	element -> distributed [i] = (Distributed) TreeSearch (tree, &d);

	if (element -> distributed [i] == NULL) {
	    error ("element %d uses undefined distributed load %s", num,d.name);
	    problem.numerrors ++;
	    Deallocate (d.name);
	}
    }


    if (element -> definition != NULL)
	for (i = 1; i <= element -> definition -> numnodes; i ++)
	    if (element -> node [i])
		element -> node [i] = problem.nodes [(int) element -> node [i]];

    return 0;
}


int resolvenames ( )
{
    int i;


    problem.numerrors = 0;

    if (problem.numnodes != 0) {
	if (!(problem.nodes = Allocate (Node, problem.numnodes)))
	    Fatal ("unable to allocate memory");

	UnitOffset (problem.nodes);

	for (i = 1; i <= problem.numnodes; i ++)
	    problem.nodes [i] = NULL;

	TreeSetIterator (problem.node_tree, node_resolve);
	TreeIterate     (problem.node_tree);

	for (i = 1; i <= problem.numnodes; i ++)
	    if (problem.nodes [i] == NULL) {
		error ("node %d is not defined", i);
		problem.numerrors ++;
	    }
    }


    if (problem.numelements != 0) {
	if (!(problem.elements = Allocate (Element, problem.numelements)))
	    Fatal ("unable to allocate memory");

	UnitOffset (problem.elements);

	for (i = 1; i <= problem.numelements; i ++)
	    problem.elements [i] = NULL;

	TreeSetIterator (problem.element_tree, element_resolve);
	TreeIterate     (problem.element_tree);

	for (i = 1; i <= problem.numelements; i ++)
	    if (problem.elements [i] == NULL) {
		error ("element %d is not defined", i);
		problem.numerrors ++;
	    }
    }


    if (problem.numerrors)
	error ("%d error(s) found in input", problem.numerrors);

    return problem.numerrors;
}


/************************************************************************
 * Function:	 GetProblem						*
 *									*
 * Parameters:	 input	  - input file pointer				*
 *		 element  - pointer to an array of elements		*
 *		 node     - pointer to an array of nodes		*
 *		 numelts  - number of elements				*
 *		 numnodes - number of nodes				*
 *		 title	  - title of problem				*
 *									*
 * Return value: none							*
 *									*
 * Calls:	 yyparse						*
 *									*
 * Called by:	 main							*
 *									*
 * Global data:	 the problem instance is used				*
 *									*
 * Description:	 GetProblem is called by main to retrieve the problem	*
 *		 from input file and returns the problem instance	*
 *		 as arrays of element and node structures.		*
 ************************************************************************/

int GetProblem (input, element, node, numelts, numnodes, title)
    FILE     *input;
    Element **element;
    Node    **node;
    unsigned *numelts;
    unsigned *numnodes;
    char    **title;
{
    RestartLexer (input);
    if (yyparse ( ))
	return 1;

    *element  = problem.elements;
    *node     = problem.nodes;
    *numelts  = problem.numelements;
    *numnodes = problem.numnodes;
    *title    = problem.title;
    return 0;
}
