/***********************************************************************************
Filename: main.c
Authors: Eija Achren, Lauri Glad, Pekka Haara, Sarianne Mykra, Tuija Rinne
Date:    01.06.1992

Description: This file contains the main function for the read ABAQUS module program. The module
             is intended to be used with ConvexAVS and was designed and implemented for 
	     csc.helsinki.fi by five students in the University of Helsinki Finland department
	     of computer science.

	     The program is divided into 5 files: abaqus.c, main.c (this file), construct.c,
             read.c and set.c . There is also a standalone version of this program named
	     read ABAQUS standalone. The main function of the standalone version can be found
	     in file read_ABAQUS.c. 3 header files must also be included in order to be 
	     able to compile these programs. They are: abaqus.h, fem.h and defin.h .
	     Compiling must be done with the cc-compiler and linkin with the fc-linker.
	     The makefile can be as follows:
	     
	     OBJS= abaqus.o construct.o main.o read.o set.o 
	     OBJSTDAL= abaqus.o read_abaqus.o read.o construct.o

	     module: $(OBJS) 
	             fc -no -fi  -o $@ $(OBJS)  -labqshr -L/usr/avs/lib -lsim_c -lgeom -lutil

	     read_ABAQUS: $(OBJSTDAL) 
	             fc -fi  -o $@ $(OBJSTDAL)  -labqshr -L/usr/avs/lib -lsim_c -lgeom -lutil

	     abaqus.o: abaqus.c
	     cc -no -c abaqus.c -fi

	     construct.o: construct.c
	     cc -no -c eija.c -fi

	     main.o: main.c
	     cc -no -c lauri.c -fi

	     read.o: read.c
	     cc -no -c sarianne.c -fi

	     set.o: set.c
	     cc -no -c tuija.c -fi

	     read_abaqus.o: read_abaqus.c
	     cc -no -c read_abaqus.c -fi

Modifications: I made a new version of the function error_message in order to  be able 
               to acchieve better functionality with the auto update option.
	       For detailed explanation on these modifications see 'read ABAQUS Module and
	       Standalone Version: Documentation'
	       16.6-92. LG

-----------------------------------------------------------------------------------*/

#define IS_MAIN 1 /* this file contains the main function */
#include "fem.h"
#include <string.h>
#include <stdio.h>
#include <avs/avs.h>
#include <avs/flow.h>

#include <sys/types.h>
#include <sys/time.h>
#include <time.h>

#include <sys/file.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
#include <avs/ucd_defs.h>

#include "defin.h"

/***************************************************************************************
 * Global variables. These variables are defined as external variables in the
 * file defin.h for other read_ABAQUS-modules code-files 
 --------------------------------------------------------------------------------------*/

bool done;        /* variable to hold the parameter do UCD    */
bool disp_vec;    /* variable for the param. Disp.vector      */
bool disp_x;      /* variable for the param. displacement x   */
bool disp_y;      /*         -//-            displacement y   */
bool disp_z;      /*         -//-            displacement z   */
bool stress_x;    /*         -//-               stress x      */
bool stress_y;    /*         -//-               stress y      */
bool stress_z;    /*         -//-               stress z      */
bool stress_xy;   /*         -//-               stress xy     */
bool stress_xz;   /*         -//-               stress xz     */
bool stress_yz;   /*         -//-               stress yz     */
bool stress_vec;  /*         -//-               stress vector */
bool von_Mises;   /* variable for the parameter von Mises     */
bool max_shear;   /* variable for the parameter max shear     */
bool temperature; /* variable for the param. temperature      */
bool auto_update; /* variable for the param. auto-update      */

int step_nr; /* variable for the parameter step number        */
int inc_nr;  /*           -//-             inc number         */
int shell_elem;  /* variable for the parameter shell element  */
int temp_filename; /* string for the parameter choose file. If temp_filename
                        is something else than NULL it is instantly copied to
                        the variable "filename" which is defined in the main
                        function                                                */
int pic_time;     /* string for the parameter time, no meaningful value         */


/***************************************************************************************
  Functions in other files:
---------------------------------------------------------------------------------------*/


/* in read.c :      */ 

extern int read_initial_data(char *filename, AllData *changes, Model *original, STime *inc_time);
extern int read_ABAQUS_data(AllData *changes, int last_step, int last_inc);

/* in construct.c : */

extern int  construct_UCD(UCD_structure **out,Model *original,AllData *changes,char *filename);

/* in set.c         */

extern int search_first_inc(int local_step,STime *inc_time);
extern int search_last_inc(int local_step,STime *inc_time);
extern void set_inc_and_time(STime *inc_time);
extern bool set_step_and_inc(STime *inc_time);
extern void set_time(STime *inc_time);
extern void set_dial_limits(STime *inc_time);


/**************************************************************************************
  Functions in this file:
---------------------------------------------------------------------------------------/

/*************************************************************
Function:	change_path

Description:	changes working directory and removes directories from the front of the filename

Input:		*path1:	directory path from the root to the filename

Output:		*path1:	pure filename

Global variables:	-

Return: 		-
------------------------------------------------------------------*/

void change_path(path1)
char *path1;				/* pointer to the path1 string 		*/
{
char tmp[FILENAME_SIZE], *tp1, *tp2;	/* all three pointers are temporary	*/

strcpy(tmp, path1);			/* copy the filename to tmp array		*/
tp1=tmp;

tp2=strrchr(tp1,'/');			/* search the rightmost '/'-character 	*/
tp1 = ++tp2;				/* tp1 points the filename			*/
tmp[strlen(tmp)-strlen(tp1)-1]='\0';	/* set NUL character between the path and the filename	*/
chdir(tmp);				/* change working directory			*/
strcpy(path1,tp1);			/* copy the filename (tp1) to the path1		*/

}

/*************************************************************
Function: set_parameter_visibility

Description: This fuction sets all the widgets other than the file browser invisble

Input: visibility: whether to show or hide widgets
       all:        to show/hide or not show/hide (all widgets)

Output: -

Return: -
------------------------------------------------------------*/

void set_parameter_visibility(visibilty,all)
     bool visibilty;
     bool all;

 {
   AVSparameter_visible("Disp. vector",visibilty);
   AVSparameter_visible("Displacement x",visibilty);
   AVSparameter_visible("Displacement y",visibilty);
   AVSparameter_visible("Displacement z",visibilty);
   AVSparameter_visible("Stress x",visibilty);
   AVSparameter_visible("Stress y",visibilty);
   AVSparameter_visible("Stress z",visibilty);
   AVSparameter_visible("Stress xy",visibilty);
   AVSparameter_visible("Stress xz",visibilty);
   AVSparameter_visible("Stress yz",visibilty);
   AVSparameter_visible("Stress vector",visibilty);
   AVSparameter_visible("von Mises",visibilty);
   AVSparameter_visible("Max shear",visibilty);
   AVSparameter_visible("Temperature",visibilty);
   AVSparameter_visible("Auto-update",visibilty);
   AVSparameter_visible("Shell element layer",visibilty);
   if (all)
     {
       AVSparameter_visible("Step nr.",visibilty);
       AVSparameter_visible("Inc nr.",visibilty);
       AVSparameter_visible("Time",visibilty);
       AVSparameter_visible("Do UCD",visibilty);
     }
 } /* set_parameter_visibility */




/**************************************************************************************
Function:	error_message

Description: Displays an AVS error message of seriousity warning, error or fatal. If
             the error is fatal this function blocks forever.	

Input: *format: the message
       *str1  : first parameter in the message
       *str2  : second parameter in the message
       code   : action for the switch-clause
       *inc_time pointer to a STime structure (defined in abaqus.h)	

Output:	-	

Global variables: autoupdate 
		

Return: OK,ERROR or NODATA (defined in fem.h) 	
--------------------------------------------------------------------------------------*/

int error_message(format,str1,str2,code,inc_time)

char *format, *str1, *str2;
int code;
STime *inc_time;
{
char *answer;              /* pointer to the choice from AVSmesage */
struct timeval *checking;  /* structure used by select sytem call via AVScorout_event_wait */
int temp = ERROR;          /* variable to hold the return value */
unsigned int mask;        /* this allso for the select sytem call - see manual for select  */
  
fd_set readfds,          /* file descriptor sets for the select system call. These are not */
       writefds,         /* used in this application...                                    */ 
       exceptfds;

FD_ZERO(&readfds);      /* ... and so they are just initialized to NULL sets with these   */
FD_ZERO(&writefds);     /* system macros.                                                 */
FD_ZERO(&exceptfds);

switch(code)
  {
  case -1:       
    AVSwarning(format,str1,str2); /* give a warning */
    break;

  case -2:   
    AVSerror(format,str1,str2);  /* give an errormessage */
    break;

  case -3:
    AVSfatal(format,str1,str2);  /* fatal error has occurred */
    while(TRUE)
      AVScorout_wait();         /* block forever */

  case -4:
    answer =  AVSmessage("1",AVS_Warning,NULL,"error_message","Auto update!Select new file",format,str1,str2);
	               /* give an errormessage with choises */
    if(!strcmp(answer,"Select new file")) /* determine what to do */
      return ERROR;                       /* go to select a new file */
    else                                  /* try to automaticly determine when the file is ready */
      {
	set_parameter_visibility(TRUE,FALSE);               /* show the necessary widgets           */
	AVSmodify_parameter("Auto-update",AVS_VALUE,1,0,1);  /* set the auto update option on    */
	auto_update = TRUE;
	AVSparameter_visible("Choose file",0);               /* unable switching the file        */

	/* as long as the auto update is on and ABAQUS Open fails (nodal data not written yet)   */

	while(auto_update && ((temp = ABAQUS_Open(str1))!=OK))
	  {
	    AVScorout_input(&done,&disp_vec, &disp_x,&disp_y,&disp_z,
			    &stress_x,&stress_y,&stress_z,&stress_xy,&stress_xz,
			    &stress_yz,&stress_vec,&von_Mises,&max_shear,&temperature,
			    &auto_update,&step_nr,&inc_nr,&temp_filename,      
			    &shell_elem,&pic_time);
	    if (temp != OK && auto_update)
	      {
		mask = COROUT_WAIT;
		set_timeout(&checking);
		AVScorout_event_wait(0,&readfds,&writefds,&exceptfds,checking,&mask);
	      }/*if*/
	  }/*while*/
	set_parameter_visibility(auto_update,FALSE); /* if not auto_update hide the widgets */
	return temp;
      }/*else*/    
    break;

  case -5:
    /* this is  same as case -4 and it is only necessary because ABAQUS (propably) writes the  */
    /* necessary time data after the nodal data. See read_initial_data() in read.c !           */

    if(!auto_update) /* if we are not auto updating give an error message that allows to put it on */
      {
	answer =  AVSmessage("1",AVS_Warning,NULL,"error_message","Auto update!Select new file",format,str1,str2);
	if(!strcmp(answer,"Select new file"))
	  return ERROR;
      } 
    set_parameter_visibility(TRUE,FALSE);
    AVSmodify_parameter("Auto-update",AVS_VALUE,1,0,1);
    auto_update = TRUE;
    AVSparameter_visible("Choose file",0);
    
    /* make notice how in this while clause we call ABAQUS_Time_Data as in case -4 we used   */
    /* ABAQUS_Open()                                                                         */

    while(auto_update && ((temp = ABAQUS_Time_Data(inc_time))!=OK))
      {
	fprintf(stderr,"Time_Data not written yet\n");
	AVScorout_input(&done,&disp_vec, &disp_x,&disp_y,&disp_z,
			&stress_x,&stress_y,&stress_z,&stress_xy,&stress_xz,
			&stress_yz,&stress_vec,&von_Mises,&max_shear,&temperature,
			&auto_update,&step_nr,&inc_nr,&temp_filename,      
			&shell_elem,&pic_time);
	if (temp!=OK && auto_update)
	  {
	    mask = COROUT_WAIT;
	    set_timeout(&checking);
	    AVScorout_event_wait(0,&readfds,&writefds,&exceptfds,checking,&mask);
	  }/*if*/
      }/*while*/
    set_parameter_visibility(auto_update,FALSE);
    return temp;
    break;

  default: break;
  }	    /* switch */
return OK;         
} /* error_message */


/*******************************************************************************************
Function: read_ABAQUS_filename

Description: This function reads the filename for the file to be processed. It also tries
             to open this fiel in order to determine wether the file exists or not

Input: *filename:    an empty string
       *access_time: an integer to show how many times we have been here

Output: The name is read into the global variable temp_filename and the variable
        filename carries a copy of it outside this function.

Return: -

--------------------------------------------------------------------------------------------*/


void read_ABAQUS_filename(filename,access_time) 
 char *filename;
 int *access_time;

 { 
   int fd;           /* file descriptor      */
   int file_exists;  /* does the file exist? */

   if (*access_time == 1 && *((char *)temp_filename)=='\0') 
     {
      /* this is done only when we are here for the first time */
      AVScorout_wait();
      (*access_time)++;
     }
   do
   { 
     AVScorout_input(&done,&disp_vec, &disp_x,&disp_y,&disp_z,
                     &stress_x,&stress_y,&stress_z,&stress_xy,&stress_xz,
                     &stress_yz,&stress_vec,&von_Mises,&max_shear,&temperature,
                     &auto_update,&step_nr,&inc_nr,&temp_filename,
                     &shell_elem,&pic_time);

     if (*((char *)temp_filename)=='\0')
            AVScorout_wait();  /* lets wait fot the filename */
     else
      {
       strcpy(filename,(char *)temp_filename);
       file_exists = ((fd = open(filename,O_RDONLY,0))!= -1);
       if (!file_exists)
         {
          error_message("Cannot open file %s. File does not exist or access denied",
                     filename,NULL,-1,NULL);
	  filename[0]='\0';
         AVScorout_wait();
	}
      } 
    }while(filename[0]=='\0'); /* we stay here until we get a proper filename */

   close(fd); 
 } /* read_ABAQUS_filename */


/************************************************************************************************
Function: set_timeout


Description: In the main function there is a call for the AVS_corout_event_wait which in
             turn uses the select system call. timeout determines the time that select blocks.
             If timeout=NULL select blocks indefinetly. The other possibility here is that select
             blocks for 30 seconds.

Input: ** timeout a double pointer to a timeval structure (defined in time.h)

Output: after executing this function timeout points either to the static timeval structure
        or is NULL

Return:-
-------------------------------------------------------------------------------------------------*/
void set_timeout(timeout)

 struct timeval **timeout;
 
{ 
  static struct timeval blocking_timeval; /*  *timeout is set to point to this static structure */
                                          /*  timeval is defined in time.h                      */

  blocking_timeval.tv_sec=30;
  blocking_timeval.tv_usec=0;

  if (auto_update)
   {
    *timeout = &blocking_timeval;
   }
  else
   {
    *timeout = NULL;
   }
}



/***********************************************************************

Function: read_ABAQUS_desc()

Description: This is the description function for the read_ABAQUS module

Input: -
Output: -

Return: -
-----------------------------------------------------------------------*/


read_ABAQUS_desc()
{
  
  int param; /* temporary to hold the parameter id */


  /* read_ABAQUS -module is a data module */
  AVSset_module_name("read ABAQUS",MODULE_DATA);

  /* Et-module's output is an ucd-structure */
  AVScreate_output_port("ucd struct","ucd");

  /* add a boolean parameter to know when user has defined which data
     he wishes the ucd-structure to contain to be passed along the  network */
  param = AVSadd_parameter("Do UCD","boolean",0,0,1);
  AVSadd_parameter_prop(param,"width","integer",4);

  /* add the parameters to choose the data */

  AVSadd_parameter("Disp. vector","boolean",1,0,1);
  AVSadd_parameter("Displacement x","boolean",0,0,1);
  AVSadd_parameter("Displacement y","boolean",0,0,1);   
  AVSadd_parameter("Displacement z","boolean",0,0,1);
  
  AVSadd_parameter("Stress x","boolean",0,0,1);
  AVSadd_parameter("Stress y","boolean",0,0,1);
  AVSadd_parameter("Stress z","boolean",0,0,1);
  AVSadd_parameter("Stress xy","boolean",0,0,1);
  AVSadd_parameter("Stress xz","boolean",0,0,1);
  AVSadd_parameter("Stress yz","boolean",0,0,1);
  AVSadd_parameter("Stress vector","boolean",0,0,1);

  AVSadd_parameter("von Mises","boolean",1,0,1);

  AVSadd_parameter("Max shear","boolean",1,0,1);

  AVSadd_parameter("Temperature","boolean",1,0,1);

  /* on/off switch for automatic updating whith non-complete file */
  param=AVSadd_parameter("Auto-update","boolean",0,0,1);
  AVSadd_parameter_prop(param,"width","integer",4); 

  /* dial to choose the step to be viewed */
  AVSadd_parameter("Step nr.","integer",1,0,1);

  /* dial to choose the inc to be viewed */
  AVSadd_parameter("Inc nr.","integer",1,0,1); 
  
  
  /* browser to choose the file to be processed */
  param = AVSadd_parameter("Choose file","string","","",".fil");
  AVSconnect_widget(param,"browser");

  /* a slider to choose which of the shell elements is chosen */
  param = AVSadd_parameter("Shell element layer","integer",1,0,MAX_LAYER);
  AVSconnect_widget(param,"islider");

  /* a message showing the time of each picture */
  param = AVSadd_parameter("Time","string","Time: 00.00","","");
  AVSconnect_widget(param,"text");
  /*AVSadd_parameter_prop(param,"editable","integer",0);*/
  AVSadd_parameter_prop(param,"height","integer",2);
  AVSadd_parameter_prop(param,"width","integer",3);

  /* the following optional functions are not currently in use */
  /* AVSset_init_proc(Et_init) */
  /* AVSset_destroy_proc(Et_destroy) */
  /* AVSset_compute_proc(Et_widgets_compute); */
}

/*****************************************************************

Function: main

Description: See read ABAQUS documentation for further information.

Input:argc, *argv[] with nothing meaningful in them
 
Output:-

Return:-
-------------------------------------------------------------------*/

/*********************************************************************************************
    Main program for the read_ABAQUS -module       


 --------------------------------------------------------------------------------------------*/

main(argc,argv)
 int argc;     /* nothing meaningful */
 char *argv[]; /* same here          */

 { 
   bool new_file,        /* to know when the user has changed the input file  */
        new_pic_ready;   /* if we  are auto updating: are there new pictures? */

   int  last_step,       /* the last (ABAQUS computed) step shown             */
        last_inc,        /* the last increment shown                          */
        last_shell_elem; /* and the latest shell element layer                */
   
   struct timeval  *timeout;  /* pointer to a timeval structure for the select system call */
                              /* see man select, AVScorout_event_wait, time.h              */

   UCD_structure *out=NULL;   /* The output structure */

   char filename[FILENAME_SIZE]; /* copy of the currently chosen file */

   Model original;               /* The geometry for the currently computed model (fem.h)  */

   AllData changes;              /* All the data the structure contains (see defin.h)      */ 

   STime inc_time;               /* Steps and incs (defined in fem.h)                      */

   fd_set readfds,               /* see the comments in set_timeout function               */
         writefds,
         exceptfds;

   static int access_time = 1;  /* helps reading the filename in read_ABAQUS_filenam       */

   unsigned int mask;           /* this is allso for the select system call see set_timeout*/



 /* initialization of the read_ABAQUS-module via passing a pointer to the    
    description function */

AVScorout_init(argc,argv,read_ABAQUS_desc); 


#ifdef __convex__  
   f_init();      /* Initialize Fortran I/O (Convex) */
#endif


FD_ZERO(&readfds);   /* initialize the file descriptor sets into NULL sets as they carry no */
FD_ZERO(&writefds);  /* menigiful information in this context                               */
FD_ZERO(&exceptfds);

   original.node = NULL;  /* initialize these pointers to point into NULL so that we may    */
   original.elem = NULL;  /* test: (pointer==NULL)                                          */
   inc_time.inc = NULL;
   inc_time.step = NULL;
   inc_time.time = NULL;
   changes.stress.data = NULL;
   changes.stress.nid = NULL;
   changes.von_Mises.data = NULL;
   changes.von_Mises.nid = NULL;
   changes.max_shear.data = NULL;
   changes.max_shear.nid = NULL;
   changes.disp.data = NULL;
   changes.disp.nid = NULL;
   changes.temp.data = NULL;
   changes.temp.nid = NULL;


/* end of initialization */

set_parameter_visibility(FALSE,TRUE);

/* read initial values for the global variables */

AVScorout_input(&done,&disp_vec, &disp_x,&disp_y,&disp_z,
                     &stress_x,&stress_y,&stress_z,&stress_xy,&stress_xz,
                     &stress_yz,&stress_vec,&von_Mises,&max_shear,&temperature,
                     &auto_update,&step_nr,&inc_nr,&temp_filename,
                     &shell_elem,&pic_time);

while(TRUE) /* as long as we use the module in AVS */
 {
  AVSparameter_visible("Choose file",1); /* it may be invisible if read_initial_data fails         */
  set_parameter_visibility(FALSE,TRUE);      /* they may be visible  if read_initial_data fails   */
  filename[0]='\0';                                /* no file yet                                  */
  read_ABAQUS_filename(filename,&access_time);
  change_path(filename);
  if (read_initial_data(filename, &changes, &original, &inc_time) != ERROR) 
   {                                                          /* there is something we can show    */
    AVSparameter_visible("Choose file",1);   
    new_pic_ready = TRUE;
    set_parameter_visibility(TRUE,TRUE);
    set_dial_limits(&inc_time);
    last_step = -1;
    last_inc = -1;
    last_shell_elem = 1;
    new_file = FALSE;
    do
     {
       done = FALSE;
       AVSmodify_parameter("Do UCD",AVS_VALUE,0,0,1);      /* done is allways popped up ! */

       /* as long as there is no need to show a new picture                               */
       while(!done && !new_file && !(auto_update && new_pic_ready))
        {
         AVScorout_input(&done,&disp_vec, &disp_x,&disp_y,&disp_z,
                         &stress_x,&stress_y,&stress_z,&stress_xy,&stress_xz,
                         &stress_yz,&stress_vec,&von_Mises,&max_shear,&temperature,
                         &auto_update,&step_nr,&inc_nr,&temp_filename,      
                         &shell_elem,&pic_time);

	 if (!(new_file = AVSparameter_changed("Choose file"))) /* does the user choose a new file */
           { 
	     /* if we do these commands the user has NOT selected a new file */
 
             if (AVSparameter_changed("Step nr."))
               set_inc_and_time(&inc_time);
             else if (AVSparameter_changed("Inc nr."))
	             set_time(&inc_time);
             if (auto_update)
	       new_pic_ready = set_step_and_inc(&inc_time);
  
              if(!done && !new_file && !(auto_update && new_pic_ready))
		{
		  /* if there is nothing to show... */
		  mask = COROUT_WAIT;
		  set_timeout(&timeout);  /* notice: if timeout = NULL select blocks indefinetly! */
		  AVScorout_event_wait(0,&readfds,&writefds,&exceptfds,timeout,&mask);
		}
	   }
	 else /* a new file is chosen */
	   strcpy(filename,(char *)temp_filename);
       }/* while */ 

       if (!new_file) /* if we didn't come out from the while-loop via choosing a new file      */
	 {
	   if ((step_nr!=last_step) || (inc_nr!=last_inc) || (shell_elem !=
							      last_shell_elem))
	     {
	       /* if we come here then we must read new data into structure changes */
	       read_ABAQUS_data(&changes, last_step, last_inc);
	       last_step = step_nr;
	       last_inc = inc_nr;
	       last_shell_elem = shell_elem ;
	     }
              if (construct_UCD(&out,&original,&changes,filename)!= ERROR)
	        	AVScorout_output(out); /* send it along the network! */
	      else
		{
		   AVSmodify_parameter("Choose file",AVS_VALUE,"",".fil"); /* there is something wrong */
		   new_file=TRUE;  /* with the file so let's choose another one !                      */
		}   
	 }
       new_pic_ready=FALSE;  /* we'v just sent a picture */
     }while(!new_file);     /* do-while loop             */
  } /* if */
  else
    AVSmodify_parameter("Choose file",AVS_VALUE,"",".fil");
} /* while */
 
} /* main */
 	

 /* end of this fine module */   

 





