/*
    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:		file.c
*
* Description:	contains functions to manipulate Felt files and parts
*		of Felt files
*
* History:	v1.0 by Jason I. Gobat and Darren C. Atkinson
*
************************************************************************/

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

char *AddQuotes ();
char *ConstraintSymbol ();

static char *direction_names [ ] = {"","LocalX","LocalY","LocalZ",
                                    "GlobalX","GlobalY","GlobalZ",
                                    "parallel","perpendicular"};

int WriteFeltFile (output, element, node, numelts, numnodes, title)
   FILE		*output;
   Element	*element;
   Node		*node;
   unsigned	numelts,
		numnodes;
   char		*title;
{
   unsigned		i,j,k;
   static Material	*material = NULL;
   unsigned		nummaterial;
   static unsigned	materialsize = 10;
   static Force		*force;
   unsigned		numforce;
   static unsigned	forcesize = 10;
   static Constraint	*constraint;
   unsigned		numconstraint;
   static unsigned	constraintsize = 10;
   static Distributed	*distrib; 
   unsigned		numdistrib;
   static unsigned	distribsize = 10;
   unsigned		flag;
   unsigned		type;
   Constraint		prev_constraint;
   Material		prev_material;

   if (numnodes == 0 || numelts == 0) {
      error ("nothing to do");
      return 1;
   }

   if (material == NULL) {
      material = (Material *) malloc (sizeof(Material)*materialsize);
      distrib = (Distributed *) malloc (sizeof(Distributed)*distribsize);
      constraint = (Constraint *) malloc (sizeof(Constraint)*constraintsize);
      force = (Force *) malloc (sizeof(Force)*forcesize);

      if (material == NULL || distrib == NULL || 
          constraint == NULL || force == NULL)

         Fatal ("allocation error writing Felt file");
   }

   numconstraint = 0;
   numforce	 = 0;
   nummaterial	 = 0; 
   numdistrib    = 0;
 
   constraint [numconstraint++] = node [1] -> constraint;

   for (i = 1 ; i <= numnodes ; i++) {

	/*
	 * find all of the named constraints
	 */

      if (node [i] -> constraint != constraint [numconstraint-1]) {
         flag = 0;
         for (j = 0 ; j < numconstraint ; j++) {
            if (node [i] -> constraint == constraint [j]) {
               flag = 1;
               break;
             }
         } 

         if (!flag) {
            if (numconstraint >= constraintsize) {
               constraintsize += 10;
               Reallocate (constraint,Constraint,constraintsize);
            }
            constraint [numconstraint ++] = node [i] -> constraint;
         }
      }

	/*
	 * find all of the named forces
	 */

      if (node [i] -> force != NULL) {

         if (numforce == 0) 
            force [numforce++] = node [i] -> force;
         else if (node [i] -> force != force [numforce-1]) {
            flag = 0;
            for (j = 0 ; j < numforce ; j++) {
               if (node [i] -> force == force [j]) {
                  flag = 1;
                  break;
               }
            }

            if (!flag) {
               if (numforce >= forcesize) {
                  forcesize += 10;
                  Reallocate (force, Force, forcesize);
               }
               force [numforce++] = node [i] -> force;
            }
         } 
      }
   }

   material [nummaterial++] = element [1] -> material;

   for (i = 1 ; i <= numelts ; i++) {

	/*
	 * find all of the used material properties
	 */

      if (element [i] -> material != material [nummaterial-1]) {
         flag = 0;
         for (j = 0 ; j < nummaterial ; j++) {
            if (element [i] -> material == material [j]) {
               flag = 1;
               break;
             }
         } 

         if (!flag) {
            if (nummaterial >= materialsize) {
               materialsize += 10;
               Reallocate (material, Material, materialsize);
            }
            material [nummaterial ++] = element [i] -> material;
         }
      }

	/*
	 * find all of the used distributed forces
	 */
	
      if (element [i] -> numdistributed > 0) {

         for (j = 1 ; j <= element [i] -> numdistributed ; j++) {
            if (numdistrib == 0) 
               distrib [numdistrib++] = element [i] -> distributed[j];
            else if (element [i] -> distributed[j] != distrib [numdistrib-1]) {
               flag = 0;
               for (k = 0 ; k < numdistrib ; k++) {
                  if (element [i] -> distributed [j] == distrib [k]) {
                     flag = 1;
                     break;
                  }
               }

               if (!flag) {
                  if (numdistrib >= distribsize) {
                     distribsize += 10;
                     Reallocate (distrib, Distributed, distribsize);
                  }
                  distrib [numdistrib++] = element [i] -> distributed [j]; 
               }
            } 
         }
      }
   }

	/*
	 * write it all out
	 */

   fprintf (output, "problem description\n");
   fprintf (output, "title=%s nodes=%d elements=%d\n\n", AddQuotes(title),
       numnodes,numelts); 

   if (numnodes > 0) {
      fprintf (output, "nodes\n");
      prev_constraint = NULL;
      for (i = 1 ; i <= numnodes ; i++) {
         if (node [i] -> constraint != prev_constraint) {
            if (node [i] -> force != NULL)
               fprintf (output,"%d  x=%g y=%g z=%g constraint=%s force=%s\n",
                  node[i] -> number, node[i] -> x, node[i] -> y, node[i] -> z,
                  AddQuotes(node[i] -> constraint -> name), 
                  AddQuotes(node[i] -> force -> name));
            else
               fprintf (output,"%d  x=%g y=%g z=%g constraint=%s\n",
                  node[i] -> number, node[i] -> x, node[i] -> y, node[i] -> z,
                  AddQuotes(node[i] -> constraint -> name));
         }   
         else {
            if (node [i] -> force != NULL)
               fprintf (output,"%d  x=%g y=%g z=%g force=%s\n",
                  node[i] -> number, node[i] -> x, node[i] -> y, node[i] -> z,
                  AddQuotes(node[i] -> force -> name));
            else
               fprintf (output,"%d  x=%g y=%g z=%g\n",
                  node[i] -> number, node[i] -> x, node[i] -> y, node[i] -> z);
         }
        
         prev_constraint = node [i] -> constraint;
      }
   }

   if (numelts > 0) {
      type = element [1] -> definition -> type;

      prev_material = NULL;
      fprintf (output, "\n%s elements\n", AddQuotes(ElementArray [type].name));
      for (i = 1 ; i <= numelts ; i++) {

         if (element [i] -> definition -> type != type) {
            type = element [i] -> definition -> type;
            fprintf (output, "\n%s elements\n",
                          AddQuotes(ElementArray[type].name));
         }
         fprintf (output, "%d  nodes=[",i);
         for (j = 1 ; j < element [i] -> definition -> numnodes ; j++) {
            if (element [i] -> node[j] != NULL)
               fprintf (output, "%d,",element[i] -> node[j] -> number);
            else
               fprintf (output, "0,");
          }
          if (element [i] -> material != prev_material) 
             fprintf (output,"%d]   material=%s    ",
               (element[i]->node[element[i]->definition->numnodes] != NULL ?
                element[i]->node[element[i]->definition->numnodes]->number : 0),
                AddQuotes(element[i] -> material -> name));
          else
             fprintf (output,"%d]   ",
              (element[i]->node[element[i]->definition->numnodes] != NULL ?
               element[i]->node[element[i]->definition->numnodes]->number : 0));

          for (j = 1 ; j <= element[i] -> numdistributed ; j++)
             fprintf (output,"load=%s   ",
                AddQuotes(element[i] -> distributed[j] -> name));
          
          fprintf (output,"\n");
          prev_material = element [i] -> material;
      }
   }

   if (nummaterial > 0) {
      fprintf (output,"\nmaterial properties\n");
      for (i = 0 ; i < nummaterial ; i++)
         fprintf (output,"%s  E=%g A=%g Ix=%g Iy=%g Iz=%g J=%g G=%g nu=%g t=%g rho=%g kappa=%g\n",AddQuotes(material[i] -> name),
                  material[i] -> E,material[i] -> A,material[i] -> Ix,
                  material[i] -> Iy, material[i] -> Iz, material[i] -> J, 
                  material[i] -> G, material[i] -> nu, material[i] -> t, 
                  material[i] -> rho, material[i] -> kappa);
   }

   if (numdistrib > 0) {
      fprintf (output,"\ndistributed loads\n");
      for (i = 0 ; i < numdistrib ; i++) {
         fprintf (output, "%s   direction=%s   values=",
            AddQuotes(distrib[i] -> name),
            direction_names [distrib[i] -> direction]);
         for (j = 1 ; j <= distrib[i] -> nvalues ; j++)
            fprintf (output,"(%d,%g) ", distrib[i] -> value[j].node,
                                        distrib[i] -> value[j].magnitude);
         fprintf (output,"\n");
      }
   }

   if (numconstraint > 0) {
      fprintf (output,"\nconstraints\n");
      for (i = 0 ; i < numconstraint ; i++)
         fprintf (output,"%s  tx=%s ty=%s tz=%s rx=%s ry=%s rz=%s\n",
           AddQuotes(constraint [i] -> name),
           ConstraintSymbol (constraint [i], 1),
           ConstraintSymbol (constraint [i], 2),
           ConstraintSymbol (constraint [i], 3),
           ConstraintSymbol (constraint [i], 4),
           ConstraintSymbol (constraint [i], 5),
           ConstraintSymbol (constraint [i], 6));
   }

   if (numforce > 0) {
      fprintf (output,"\nforces\n");
      for (i = 0 ; i < numforce ; i++)
         fprintf (output,"%s  Fx=%g Fy=%g Fz=%g Mx=%g My=%g Mz=%g\n",
           AddQuotes(force[i] -> name), force[i] -> force[1], 
           force[i] -> force[2], force[i] -> force[3], force[i] -> force[4], 
           force[i] -> force[5], force[i] -> force[6]);
   }

   fprintf (output,"\nend\n");

   return 0;
}

char *AddQuotes (string)
   char		*string;
{
   char		buffer [200];

   if (strpbrk (string,"- \t\n=[]\",+*/()#")) {
      sprintf (buffer,"\"%s\"",string);
      return buffer;
   }

   return string;
}

char *ConstraintSymbol (constraint, dof)
    Constraint	constraint;
    unsigned	dof;
{
    char	buffer [20];

    if (constraint -> constraint[dof] == 0)
        sprintf (buffer, "u\0");
    else if (constraint -> constraint[dof] == 'h')
        sprintf (buffer,"hinge\0");
    else {
       if (constraint -> dx[dof] == 0.0)
          sprintf (buffer,"c\0");
       else
          sprintf (buffer,"%g\0",constraint -> dx[dof]); 
    }

    return strdup(buffer);
}
