/****************************************************************************/
/*                                                                          */
/*  VolVis is a volume visualization system for investigating, manipulating */
/*  and rendering geometric and volumetric data.                            */
/*                                                                          */
/*  Copyright (C) 1993 by the Research Foundation of the State University   */
/*                            of New York                                   */
/*                                                                          */
/*  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 1, 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.               */
/*                                                                          */
/*  For information on VolVis, contact us at:                               */
/*                                                                          */
/*                volvis@cs.sunysb.edu                         (email)      */
/*                                                                          */
/*                Lisa Sobierajski & Ricardo Avila             (US Mail)    */
/*                Department of Computer Science                            */
/*                State University of New York at Stony Brook               */
/*                Stony Brook, New York  11794-4400                         */
/*                                                                          */
/****************************************************************************/



/*                  File: MOTIF_ide_token.c
 *                Author: He, Taosong 
 *                  Date: 1/18/93 
 *           Description: MOTIF  routines for tokenizer 
 *  Modification History:
 *
 *         who?         when?           why?
 *    -----------------------------------------------------------
 *            
 */


/******************************************************************/
/*               The MOTIF include file                           */
/******************************************************************/

#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xm/PanedW.h>
#include <Xm/Scale.h>
#include <Xm/RowColumn.h>
#include <Xm/DrawingA.h>
#include <Xm/Label.h>
#include <X11/Xutil.h>
#include <Xm/BulletinB.h>
#include <Xm/DialogS.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>


/******************************************************************/
/*                The standard C include file                     */
/******************************************************************/

#include <stdio.h>
#include <varargs.h>
#include <time.h>

/******************************************************************/
/*                  VolVis include file                           */
/******************************************************************/

#include "C_volvis.h"
#include "C_ide.h"


/*         Global Variable: IDE_active_widget
 *                          This variable keeps the current active drawingarea
 */

C_IDE_token ide_data_token[C_MAX_RD_NUMBER];

C_IDE_window_information        IDE_active_window_information;

static Widget                IDE_active_widget;

char *application[C_MAX_WINDOW_NUMBER];

XtIntervalId ide_timeout_flag[C_MAX_VD_NUMBER];

int monitor_timeout;

int IDE_spaceball_active;


int IDE_vd_active[C_MAX_WINDOW_NUMBER];

void get_window_size(drawingarea, width, height)
int *width;
int *height;
{

       Dimension wid, hei;
       int n;
       Arg args[2];

       n =  0;
       XtSetArg(args[n], XtNwidth, &wid); n++;
       XtSetArg(args[n], XtNheight, &hei); n++;
       XtGetValues(drawingarea, args, n);

       *width = wid;
       *height = hei;
}

void register_application(drawingarea, function_address)
Widget drawingarea;
void (*function_address)();
{
  extern void X_get_window_index();
  int window_index;

  X_get_window_index(XtWindow(drawingarea), &window_index);

  application[window_index] = (char *)(*function_address);

}
 
void start_application(drawingarea, function)
Widget drawingarea;
void (*function)();
{
    (*function)(drawingarea);
}


void IDE_add_start_end_handler(drawingarea)
Widget drawingarea;
{
     void monitor_start_control();

     monitor_timeout = 1;

     monitor_start_control(drawingarea);
}

void IDE_drop_start_end_handler()
{
     monitor_timeout = 0;
}

void monitor_start_control(w)
Widget w;
{
  extern void C_insert_select();
  extern Widget vv_toplevel;
  extern Window        root_window;
  extern XtAppContext     vv_app_context;
  extern void selection_panel_control();
  extern void spaceball_start_control();
  extern int C_init_spaceball();

  XtInputMask mask;

  Display *theDisplay;
  XEvent theEvent;

  int window_index;

  theDisplay = XtDisplay(vv_toplevel);
  XSelectInput(theDisplay, XtWindow(w), ResizeRedirectMask | ExposureMask |
                                        KeyPressMask | ButtonPressMask | 
                                        LeaveWindowMask | EnterWindowMask); 
 

  IDE_spaceball_active = C_init_spaceball();
  spaceball_start_control(w, NULL);

  while ( monitor_timeout )
    {

      while (!(mask = XtAppPending(vv_app_context)));
      
      if (mask == XtIMXEvent)
       {
          XtAppNextEvent(vv_app_context, &theEvent);

          if ((theEvent.type == KeyPress) || (theEvent.type == ButtonPress))
           selection_panel_control(w, 0, &theEvent);
          else
          XtDispatchEvent(&theEvent);
       }
      else
         XtAppProcessEvent(vv_app_context, XtIMTimer | XtIMAlternateInput);
    } 

   window_index = IDE_active_window_information.window_index;

   if (IDE_vd_active[window_index]) 
     {
      start_application(w, application[window_index]);
      if (!IDE_vd_active[window_index])
        {
          monitor_timeout = 1;
          monitor_start_control(w);
        }
     }

}

/*
 *        Procedure Name:   C_ide_report_token
 *          Return Value:   void
 *       Input Variables:   string, display_bulletin
 *      Output Variables:   void
 *      Update Variables:
 *      Global Variables:
 *           Description:   Display the information on the output bulletin.
 */

void C_ide_report_token(string, display_bulletin)
char *string;
Widget display_bulletin;
{
        void xs_wprintf();

        xs_wprintf(display_bulletin, string);
}

void C_get_token_from_device(device, orientation_mode, token, drawingarea)
int device;
int orientation_mode;
C_IDE_token *token;
Widget drawingarea;
{
   extern C_IDE_simulation_method C_ide_simulation_method;

   switch (device)
    {
     case C_MOUSE:
        C_ide_fill_in_mouse_token(drawingarea);
        break;
     case C_SPACEBALL:
#ifdef C_SGI
        if (IDE_spaceball_active)
          C_ide_fill_in_spaceball_token(drawingarea);
#endif
        break;
     default:
        break;
     }
   *token = ide_data_token[device];
   if (device == C_MOUSE && orientation_mode == C_MATRIX)
    convert_euler_matrix(token, token->orientation);
}

/*
 *        Procedure Name: C_get_token_fun
 *          Return Value: void
 *       Input Variables:
 *      Output Variables: token, drawingarea)
 *      Update Variables:
 *      Global Variables:
 *           Description: routine for get the information from active
 *                        virtual device and store them in a token.
 */

void C_get_token_fun(token, drawingarea)
C_IDE_token *token;
Widget drawingarea;
{
   extern int C_check_VD_change_mode();
   extern C_IDE_VD_configuration       IDE_active_config;

        int                   i;

        static C_IDE_token    temp_token[C_MAX_RD_NUMBER];

        if (C_check_VD_change_mode()) return;

        for (i= 0; i < C_CURRENT_RD_NUMBER; i++)
           {
             if (IDE_active_config.device_involved[i])
                 C_get_token_from_device(i, IDE_active_config.orientation_mode,
                                         &temp_token[i], drawingarea);
            }

        token->pos2d.x = temp_token[IDE_active_config.pos2dx].pos2d.x;
        token->pos2d.y = temp_token[IDE_active_config.pos2dy].pos2d.y;

        token->pos3d.x = temp_token[IDE_active_config.pos3dx].pos3d.x;
        token->pos3d.y = temp_token[IDE_active_config.pos3dy].pos3d.y;
        token->pos3d.z = temp_token[IDE_active_config.pos3dz].pos3d.z;

        switch (IDE_active_config.orientation_mode)
           {
              case  C_QUATERNION:
                 token->quaternion =
                        temp_token[IDE_active_config.ori].quaternion;
                 break;
              case  C_MATRIX:
                 token->rotation     =
                        temp_token[IDE_active_config.ori].rotation;
                 break;
              case  C_EULER:
                 token->orientation.a =
                        temp_token[IDE_active_config.oriazi].orientation.a;
                 token->orientation.b =
                        temp_token[IDE_active_config.oriele].orientation.b;
                 token->orientation.r =
                        temp_token[IDE_active_config.orirol].orientation.r;
                 break;
           }
}
  

/*
 *        Procedure Name:   C_get_token
 *          Return Value:   void
 *       Input Variables:   drawingarea
 *      Output Variables:   token
 *      Update Variables:    
 *      Global Variables:   
 *           Description:   Get the information for a specific drawingarea
 *                          and store them in the token
 */

void C_ide_get_token(token, selection, drawingarea)
C_IDE_token *token;
int         *selection;
Widget drawingarea;
{
   if ((IDE_active_widget == drawingarea))
     {
       C_get_token_fun(token, drawingarea);
       C_get_selection_fun(selection, drawingarea);
     }
}

/*
 *        Procedure Name:   change_vd_handler
 *          Return Value:   void  
 *       Input Variables:   drawingarea;
 *                          index of this drawingarea window in the window
 *                          queue
 *      Output Variables:   
 *      Update Variables:
 *      Global Variables:   
 *           Description:   This function is an event handler. It assign 
 *                          an virtual device number to a specific drawingarea.
 */
 
void change_vd_handler(drawingarea, window_index, event)
 Widget drawingarea ;
 int    window_index;
 XEvent *event;
{

   extern void C_set_VD_handler();

   C_set_VD_handler(window_index);

   XtRemoveEventHandler(drawingarea, ButtonPressMask, FALSE, 
                        change_vd_handler, window_index);

}      

void IDE_drop_leave_enter(drawingarea)
Widget drawingarea;
{
     extern void X_get_window_index();
     void add_drop_handler();

     int   window_index;

     X_get_window_index(XtWindow(drawingarea), &window_index);

     XtRemoveEventHandler(drawingarea, EnterWindowMask, FALSE,
                        add_drop_handler, window_index);
     XtRemoveEventHandler(drawingarea, LeaveWindowMask, FALSE,
                        add_drop_handler, window_index);
}

void IDE_add_leave_enter(drawingarea)
Widget drawingarea;
{
     extern void X_get_window_index();
     void add_drop_handler();

     int   window_index;

     X_get_window_index(XtWindow(drawingarea), &window_index);

     XtAddEventHandler(drawingarea, EnterWindowMask, FALSE,
                        add_drop_handler, window_index);
     XtAddEventHandler(drawingarea, LeaveWindowMask, FALSE,
                        add_drop_handler, window_index);
}


/*
 *        Procedure Name: add_drop_handler 
 *          Return Value: void
 *       Input Variables: drawingarea
 *                        correspondent window index
 *      Output Variables:
 *      Update Variables:
 *      Global Variables: IDE_active_config;
 *                        IDE_current_window_number; 
 *                        vv_toplevel;
 *                        root_window;
 *           Description: An event handler. Called when the pointer enter
 *                        or leave a drawingarea. This function initialize
 *                        the virtual device when pointer enter the 
 *                        drawingarea, stop it when pointer leave. 
 */


void add_drop_handler(drawingarea, window_index, event)
 Widget drawingarea;
 int window_index;
 XCrossingEvent *event;
{
 extern          int  C_check_VD_change_mode();
 extern          void C_set_VD_change_mode();
 extern          void C_add_proc();
 extern          C_IDE_VD_configuration       IDE_active_config;
 extern          int                          IDE_current_window_number;
 extern Widget vv_toplevel;
 extern Window root_window;

 int n;
 Arg args[20];

 int height, width;

 int             i;


 if (event->type == EnterNotify) 
           {
               if (C_check_VD_change_mode() )
                {
                 XtAddEventHandler(drawingarea, ButtonPressMask, FALSE, 
                                   change_vd_handler, window_index);
                 return;
                }

               IDE_active_widget = drawingarea;

               get_window_size(drawingarea, &width, &height);


               IDE_active_window_information.width  = width;
               IDE_active_window_information.height = height;

               IDE_active_window_information.window_index = window_index;
 
               C_add_proc(window_index);

               IDE_vd_active[window_index] = 0;

               IDE_add_start_end_handler(drawingarea);
           }
 else
           {
             if (C_check_VD_change_mode() ) 
              {
               C_set_VD_change_mode(-1);
               return;
              }
             IDE_drop_start_end_handler();

             IDE_active_widget = NULL;
             IDE_vd_active[window_index] = 0;

             }
} 

void reset_monitor_event_handler(drawingarea, window_index)
Widget drawingarea;
int window_index;
{
   extern int  IDE_vd_active[C_MAX_WINDOW_NUMBER];
   void child_drop_handler();

   XtRemoveEventHandler(drawingarea, LeaveWindowMask, FALSE,
                    child_drop_handler, window_index);

   IDE_vd_active[window_index] = 0;
   IDE_add_leave_enter(drawingarea);
}

void child_drop_handler(drawingarea, window_index, event)
Widget drawingarea;
int window_index;
XCrossingEvent *event;
{
   extern int screen_active();

   if (screen_active()) return;
   reset_monitor_event_handler(drawingarea, window_index);
}

/*
 *        Procedure Name: check_vd_active_status
 *          Return Value: whether the virtual device for a specific 
 *                        drawingarea is active or not.
 *       Input Variables: drawingarea
 *      Output Variables:
 *      Update Variables:
 *      Global Variables:
 *           Description: This function checks whether the virtual 
 *                        device for a specific drawingarea is active or not.
 */
  
int check_vd_active_status(drawingarea)
Widget drawingarea;
{
  extern void X_get_window_index();

  int   window_index;

  X_get_window_index(XtWindow(drawingarea), &window_index);

  return(IDE_vd_active[window_index]); 
}


/*
 *        Procedure Name: C_tokenizer
 *          Return Value: void
 *       Input Variables: drawingarea
 *      Output Variables:
 *      Update Variables: IDE_current_window_number
 *      Global Variables: vv_toplevel;
 *                        IDE_current_window_number;
 *           Description: This function intialize the virtual device
 *                        a specific drawingarea. It also activate the
 *                        selection queue operations. 
 */
  
void C_tokenizer(drawingarea)
  Widget drawingarea;
{

  extern void C_activate_selection_queue();
  extern void X_get_window_index();
  extern void X_assign_window_index();
  extern void C_tokenizer_c();
  extern void X_get_root_window();

  extern Widget vv_toplevel;
  extern int    IDE_current_window_number;
  

  int                          i;
  int                          window_index;

  int                          n;
  Arg                          args[10]; 

  Window                  win_id;

  X_get_root_window(XtDisplay(vv_toplevel));

  win_id = XtWindow(drawingarea);

  X_get_window_index(win_id, &window_index);
  
  if (window_index == -1) 
     {
      if (IDE_current_window_number==C_MAX_WINDOW_NUMBER-1)
           printf("Too many windows"); 
       else
        {
            X_assign_window_index(win_id);

            C_tokenizer_c();

            XtAddEventHandler(drawingarea,EnterWindowMask,FALSE,
                    add_drop_handler, IDE_current_window_number);
            XtAddEventHandler(drawingarea,LeaveWindowMask, FALSE,
                    add_drop_handler, IDE_current_window_number);        

            C_activate_selection_queue(drawingarea);

            IDE_current_window_number++;          
        }
     }
}


void C_flush_ide(drawingarea)
Widget drawingarea;
{
   extern C_init_mouse();
   extern void gl_init_spaceball_queue();
   extern C_IDE_VD_configuration       IDE_active_config;
   extern void C_reset_spaceball();

   int i;

   for (i=0; i< C_CURRENT_RD_NUMBER; i++)
                {
                  if (IDE_active_config.device_involved[i])
                   {
                     switch (i)
                       {
                         case C_MOUSE:
                           C_init_mouse();
                           break;
                         case C_SPACEBALL:
                           C_reset_spaceball();
                           break;
                         default:
                           break;
                       }
                   }
                }
   C_flush_select(drawingarea);
}

int C_ide_test_end()
{
   extern int  IDE_vd_active[C_MAX_WINDOW_NUMBER];

   int window_index;

   window_index = IDE_active_window_information.window_index;

   if (IDE_vd_active[window_index]) return(0);
   else                             return(1);
}
 
/*
 *        Procedure Name: start_end_virtual_device
 *          Return Value:
 *       Input Variables: drawingarea
 *                        correspondent window_index
 *      Output Variables: 
 *      Update Variables: IDE_vd_active
 *      Global Variables: IDE_vd_active
 *                        IDE_active_config
 *           Description: This function start or stop the virtual device 
 *                        operation for the specific drawingarea.
 */

void start_end_virtual_device(drawingarea, process_status, window_index)
Widget drawingarea;
int process_status;
int window_index;
{
     extern int  IDE_vd_active[C_MAX_WINDOW_NUMBER];
     void C_flush_ide();     


     C_flush_ide(drawingarea);

     if (process_status == 1)                 
/*     when the calling function is the child process.     */
      {
         reset_monitor_event_handler(drawingarea, window_index);
      } 
     else /*     when the calling function is of parent process.    */
      {
         IDE_drop_leave_enter(drawingarea);
 
         XtAddEventHandler(drawingarea, LeaveWindowMask, FALSE,
                    child_drop_handler, window_index);

         IDE_vd_active[window_index] = 1;
/*   set the virtual device status to be active.          */

          IDE_drop_start_end_handler();

      } 
}

/*
 *        Procedure Name: xs_wprintf
 *          Return Value: void
 *       Input Variables:
 *      Output Variables:
 *      Update Variables:
 *      Global Variables:
 *           Description: This function can write message to a label widget
 */

void xs_wprintf(va_alist)
  va_dcl
{
  Widget w;
  char *format;
  va_list args;
  char str[1000];
  Arg wargs[10];
  XmString xmstr;

  va_start(args);
  w=va_arg(args,Widget);
  if (!w) return;
  if(!XtIsSubclass(w,xmLabelWidgetClass))
     XtError("xs_wprintf() require a Label Widget");
  format=va_arg(args,char *);
  vsprintf(str,format,args);
  xmstr=XmStringLtoRCreate(str,XmSTRING_DEFAULT_CHARSET);
  XtSetArg(wargs[0],XmNlabelString,xmstr);
  XtSetValues(w,wargs,1);
  va_end(args);

}
