
 
/***************************************************************************
 *                                                                         *
 * Alberi:  Graphical Language Interface for POSTGRES                      *
 *                                                                         *
 * Copyright (c) 1992, 1993 The University of Georgia Research             *
 *                          Foundation, Inc.                               *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 * Designer and Programmer:  Ruben Robles                                  *
 * Email:  ruben@pollux.cs.uga.edu or rubenr3@aol.com or                   *
 *         rubenr3@psi.com@aol.com                                         *
 *                                                                         *
 * Modified by:		K.J. Kochut                                        *
 *			Department of Computer Science                     *
 *			University of Georgia                              *
 *			Athens, GA 30602                                   *
 *                                                                         *
 * Send comments/fixes/improvements/modifications to:                      *
 *                                                                         *
 *                     kochut@cs.uga.edu                                   *
 *                                                                         *
 ***************************************************************************/


#include <xview/xview.h>
#include <xview/panel.h>
#include <xview/textsw.h>
#include <xview/xv_xrect.h>

#include <sspkg/canshell.h>
#include <sspkg/rectobj.h>
#include <sspkg/drawobj.h>
#include <sspkg/tree.h>
#include <sspkg/array.h>
#include <sspkg/list.h>

#include <tmp/c.h>
#include <tmp/libpq-fe.h>

#include "delete_replace_instances_ui.h"
#include "constants.h"
#include "funcs.h"


extern int PQtracep;
extern bool Debugging;
extern Server_image gray2, gray4;
extern void free_string(),  adding_stuff_to_the_expression_tree(),
  	    show_hide_expression_tree(),
            assign_constant_proc(), delete_array_elem_proc(), 
	    name_retrieve_attr_proc(), 
            delete_leaf_proc(), add_unary_opr_proc();

/*
 * Notify callback function for `class_list'.
 */
int
class_selection(item, string, client_data, op, event)
	Panel_item	item;
	char		*string;
	Xv_opaque	client_data;
	Panel_list_op	op;
	Event		*event;
{
	delete_replace_instances_pop_objects	*ip = (delete_replace_instances_pop_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
        Rectobj_list *the_classes, *the_instances, *the_array;
        Array_tile class_list, instances_list;
        Rectobj class, temp, instance;
        char *classname, *the_parent_name, *current_name;
	
	switch(op) {
	case PANEL_LIST_OP_DESELECT:
                while((int) xv_get(ip->instances_list, PANEL_LIST_NROWS))  
                    xv_set(ip->instances_list, 
                        PANEL_LIST_DELETE, 0,
                        NULL);
                xv_set(ip->instances_list, PANEL_LABEL_STRING, "Nothing", NULL);
                xv_set(ip->instance_field, PANEL_VALUE, "", NULL);
		
		break;

	case PANEL_LIST_OP_SELECT:
                class_list = (Array_tile) xv_get(ip->pop, XV_KEY_DATA, FUNC);
                the_classes = (Rectobj_list *) xv_get(class_list, RECTOBJ_CHILDREN);
                list_for(the_classes) {
                  temp = RECTOBJ_LIST_HANDLE(the_classes);
                  classname = strdup((char *) xv_get(temp, DRAWTEXT_STRING));
                  if(!strcmp(classname, string)) class = temp;
                }
                the_array = (Rectobj_list *) xv_get(class, RECTOBJ_CHILDREN);
                xv_set(ip->instances_list, XV_KEY_DATA, OPER, class, NULL);
                if((Array_tile) xv_get(class, XV_KEY_DATA, INSTANCES) == 0) {  /* Do nothing */
                    while((int) xv_get(ip->instances_list, PANEL_LIST_NROWS))  
                        xv_set(ip->instances_list, 
                               PANEL_LIST_DELETE, 0,
                               NULL);
                     xv_set(ip->instances_list, PANEL_LABEL_STRING, "Nothing", NULL);
                     xv_set(ip->instance_field, PANEL_VALUE, "", NULL);
                  
                } else {
                  instances_list = (Array_tile) xv_get(class, XV_KEY_DATA, INSTANCES);
  
                  current_name = (char *)
		    malloc(15*sizeof(char) + strlen(classname));
                  sprintf(current_name, "%s's instances", classname);
                  xv_set(ip->instances_list, PANEL_LABEL_STRING, current_name, NULL);
                  the_instances = (Rectobj_list *) xv_get(instances_list, RECTOBJ_CHILDREN);
                  while((int) xv_get(ip->instances_list, PANEL_LIST_NROWS))  
                        xv_set(ip->instances_list, 
                               PANEL_LIST_DELETE, 0,
                               NULL);

                  if((Rectobj_list *) the_instances != NULL) {
                    list_for(the_instances) {
                     temp = RECTOBJ_LIST_HANDLE(the_instances);
       
                     the_parent_name = strdup((char *) xv_get(temp, DRAWTEXT_STRING));
                     xv_set(ip->instances_list, 
                     PANEL_LIST_INSERT, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS) ,
                     PANEL_LIST_STRING, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS) , 
                                         the_parent_name,
                     PANEL_LIST_CLIENT_DATA, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), 
                                             (Rectobj) instance,
                                             NULL);
                    }
                  }
                }
		
		break;

	case PANEL_LIST_OP_VALIDATE:
	
		break;

	case PANEL_LIST_OP_DELETE:
	
		break;
	}
	return XV_OK;
}

/*
 * Notify callback function for `instances_list'.
 */
int
instance_select(item, string, client_data, op, event)
	Panel_item	item;
	char		*string;
	Xv_opaque	client_data;
	Panel_list_op	op;
	Event		*event;
{
	delete_replace_instances_pop_objects	*ip = (delete_replace_instances_pop_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
        char *the_field;
	
	switch(op) {
	case PANEL_LIST_OP_DESELECT:
                xv_set(ip->instance_field, PANEL_VALUE, "", NULL);
	
		break;

	case PANEL_LIST_OP_SELECT:
                the_field = strdup(string);
                xv_set(ip->instance_field, PANEL_VALUE, the_field, NULL);
	
		break;

	case PANEL_LIST_OP_VALIDATE:
	
		break;

	case PANEL_LIST_OP_DELETE:
	
		break;
	}
	return XV_OK;
}


/*
 * Notify callback function for `assign_button'.
 */
void
assign_the_replace_command(item, event)
        Panel_item      item;
        Event           *event;
{
  delete_replace_instances_pop_objects    *ip = 
    (delete_replace_instances_pop_objects *) xv_get(item,
						    XV_KEY_DATA, INSTANCE);
  Canvas_shell the_shell;
  Frame the_frame;
  char *classname, *footer, temp2[36];
  int ROWS, row;
  char temp[32], *type_name, *element_type, *icon_label;
  char icon_label2[64];
  Array_tile attrib_array;
  Tree tree;
  Rectobj attribute, constant, the_new_leaf;
  Menu array_elem_menu, the_menu;
  PortalBuffer   *p;
  int             i, j, k, g, n, m, t, x, ic, s;
  char            queryp[8192];
  char            type[2];
  char           *string2, *title, *parent_name;

  the_shell = (Canvas_shell) xv_get(ip->pop, XV_KEY_DATA, OPER);
  the_frame = (Frame) xv_get(the_shell, XV_OWNER);
  classname = "";
  ROWS = (int) xv_get(ip->class_list, PANEL_LIST_NROWS);
  for(row = 0 ; row < ROWS ; row++) {
    if ( (Bool) xv_get(ip->class_list, PANEL_LIST_SELECTED, row) ) 
      classname = strdup((char *) xv_get(ip->class_list, 
					 PANEL_LIST_STRING, row)); 
  }
        
  xv_set(the_shell, RECTOBJ_ACCEPTS_DROP, FALSE, NULL);
  attrib_array = (Array_tile) xv_get(the_shell, XV_KEY_DATA, THE_ARRAY);
  xv_set(the_frame, FRAME_BUSY, TRUE, NULL);
  if ( Debugging )
    PQtracep = 0;
  /* get the attributes and construct the array and expression tree related */
  sprintf(queryp, 

	  "retrieve portal schema \
(attribute=a.attname,types=t.typname, t.typtype, t.typelem, classes=r.relname) \
  from a in pg_attribute, t in pg_type, r in pg_class \
  where a.attrelid = r.oid  \
  and a.atttypid = t.oid \
  and (a.attnum > 0) \
  and  r.relname =  \"%s\"", 

          classname);

  alberi_PQexec("begin");
  alberi_PQexec(queryp);

  alberi_PQexec("fetch all in schema");

  p = PQparray("schema");
  g = PQngroups(p);
  t = 0;

  while (xv_get(attrib_array, ARRAY_TILE_POSITION, 0, 0)) {
            xv_set(attrib_array, ARRAY_TILE_AUTO_LAYOUT, FALSE, NULL);
            xv_destroy((Drawicon) xv_get(attrib_array, ARRAY_TILE_POSITION, 0, 0));
            xv_set(attrib_array, ARRAY_TILE_AUTO_LAYOUT, TRUE, NULL);
  }

  for (k = 0; k < g; k++) {

	    n = PQntuplesGroup(p, k);
            m = PQnfieldsGroup(p, k);

            for(i = 0; i < n; i++) {
                                                         
               sprintf(type, "%c", PQgetvalue(p, t+i, 2) );
               if (strcmp(PQgetvalue(p, t+i, 2), "t") == 0) ic = 1;
               if (strcmp(PQgetvalue(p, t+i, 2), "c") == 0) ic = 0;
           
                                                             
               type_name = strdup(PQgetvalue(p, t + i, 1));
	   
               element_type = strdup(PQgetvalue(p, t + i, 3));
           
               sprintf(temp, "%s = ", (char *) PQgetvalue(p, t + i, 0));
               icon_label = strdup(temp);
	       sprintf( icon_label2, "%s.%s", classname, temp );
               icon_label2[ strlen( icon_label2 )-2 ] = '\0';

               parent_name = strdup(classname);
               attribute = (Drawicon) xv_create(attrib_array, DRAWICON, 
                                      DRAWTEXT_STRING, icon_label,
                                      DRAWIMAGE_SVRIMAGE, gray2,
                                      DRAWTEXT_STRING, icon_label,
                                      RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
                                      XV_KEY_DATA, EXPRESSION_HIDE, 0,
                                      XV_KEY_DATA, EXPRESSION_TREE, 0,
                                      NULL);
               array_elem_menu = (Menu) xv_create(XV_NULL, MENU,
                                 MENU_TITLE_ITEM, "Target List Element",
                                 MENU_ACTION_ITEM, "Delete", delete_array_elem_proc,
                                 XV_KEY_DATA, MENU_OWNER, attribute,
                                 NULL);
               xv_set(attribute, RECTOBJ_MENU, array_elem_menu, NULL);

               tree = (Tree) xv_create((Canvas_shell) xv_get(attrib_array, XV_KEY_DATA, EXPRESSION_CANVAS), TREE,
                                      XV_SHOW, FALSE,                                      
                                      RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
                                      RECTOBJ_CHILD_DROP_PROC, adding_stuff_to_the_expression_tree,
                                      XV_KEY_DATA, ARRAY_ELEMENT, attribute, 
                                      XV_KEY_DATA, TREE_EMPTY, 1,
                                      XV_KEY_DATA, THE_ARRAY, attrib_array, 
                                      NULL);
               xv_set(attribute, XV_KEY_DATA, EXPRESSION_TREE, tree, NULL);
               the_new_leaf = (Rectobj) xv_create(tree, DRAWICON, 
                                                 DRAWTEXT_STRING, icon_label2,
                                                 DRAWIMAGE_SVRIMAGE, gray4,
                   			 	 XV_KEY_DATA, 
						    PARENT_NAME, parent_name,
                            RECTOBJ_ACCEPTS_DROP, TRUE, 
                            RECTOBJ_DROP_PROC,
			      adding_stuff_to_the_expression_tree,
                                                 XV_KEY_DATA, NAME_SET, 0,
                                                 XV_KEY_DATA, TYPENAME, type_name,
                                                 XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
                                                 XV_KEY_DATA, INSTANCES, 1,                                                  
                                                 NULL);
                the_menu = (Menu) xv_create(XV_NULL, MENU, 
                                        MENU_TITLE_ITEM, "Attribute",
                                        MENU_ACTION_ITEM, "Add operator", add_unary_opr_proc,
                                        MENU_ACTION_ITEM,
                                            "Name class instance...",
                                            name_class_instance_proc,
                                        MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
                                        XV_KEY_DATA, MENU_OWNER, the_new_leaf,
                                        NULL);
/*
               the_new_leaf = (Rectobj) xv_create(tree, DRAWICON, 
                                                 DRAWTEXT_STRING, "Constant {Un-assigned}",
                                                 DRAWIMAGE_SVRIMAGE, gray4,
                                                 XV_KEY_DATA, TYPE, CONSTANT,
                                                 XV_KEY_DATA, NAME_SET, 0,
                                                 XV_KEY_DATA, TYPENAME, type_name,
                                                 XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
                                                 XV_KEY_DATA, INSTANCES, 1,                                                  
                                                 NULL);
                the_menu = (Menu) xv_create(XV_NULL, MENU, 
                                        MENU_TITLE_ITEM, "Constant",
                                        MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
                                        MENU_ACTION_ITEM, "Add operator", add_unary_opr_proc,
                                        MENU_ACTION_ITEM, "Assign the constant...", assign_constant_proc,
                                        XV_KEY_DATA, MENU_OWNER, the_new_leaf,
                                        NULL);
*/
                xv_set(the_new_leaf, RECTOBJ_MENU, the_menu, NULL);
                xv_set(tree, TREE_ADD_LINK, tree, the_new_leaf,  
                         NULL);
                xv_set((Canvas_shell) xv_get(tree, XV_OWNER),
                                CANVAS_MIN_PAINT_WIDTH, xv_get(tree, XV_WIDTH) + 10,
                                CANVAS_MIN_PAINT_HEIGHT, xv_get(tree, XV_HEIGHT) + 10,
                                NULL);


                window_fit(the_shell);
             
            
          }
          t += n;
        }
        alberi_PQexec("close schema");
        alberi_PQexec("end");
        if(Debugging) PQtracep = 0;
        xv_set(the_frame, FRAME_BUSY, FALSE, NULL);

        ROWS = (int) xv_get(ip->instances_list, PANEL_LIST_NROWS); 
        for(row = 0 ; row < ROWS ; row++) {
            if((Bool) xv_get(ip->instances_list, PANEL_LIST_SELECTED, row)) 
              classname = strdup((char *) xv_get(ip->instances_list, PANEL_LIST_STRING, row)); 
        } 
        if (classname) {
            sprintf(temp2, "replace %s ", classname);
            footer = strdup(temp2);
          xv_set(the_frame, FRAME_LEFT_FOOTER, footer, NULL);
          xv_set(ip->pop, XV_SHOW, FALSE, NULL);
        } 
        else 
	  xv_set(ip->pop,
		 FRAME_LEFT_FOOTER, 
			  "Please select a class/class-instance", 
		 XV_SHOW, TRUE, 
		 NULL);     
        
}



/*
 * Notify callback function for `instance_field'.
 */
Panel_setting
instance_typed(item, event)
	Panel_item	item;
	Event		*event;
{
	delete_replace_instances_pop_objects	*ip = (delete_replace_instances_pop_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
	char *	value = (char *) xv_get(item, PANEL_VALUE);
        char *the_name, *the_whole_name, *none, *some, *the_attribute;
        int length, character, occurrence, conflict, rows, already;
        Rectobj the_element, the_other, temp, the_class;
        Rectobj_list *the_guys, *class_list, *instance_array_pointer;
        Array_tile the_instances_owner, the_classes, the_instances_array;

        if ((length = strlen(value)) > 16) {
            xv_set(ip->pop, FRAME_LEFT_FOOTER, "Names are 16 characters or less!!", NULL);
            xv_set(item, PANEL_VALUE, "Error", NULL);
         } else {
           if ((!isalpha(value[0]))  && (value[0] != '_'))  {
              xv_set(ip->pop, FRAME_LEFT_FOOTER, "Names start with alphabetic or underscore", NULL);
              xv_set(item, PANEL_VALUE,"Error" , NULL);
           } else {
             for(character =  1; character < length; character++) {
                 if ((!isalnum(value[character])) && (value[character] != '_')) {
                    xv_set(ip->pop, FRAME_LEFT_FOOTER, "Names include alphanumeric and underscore", NULL);
                    xv_set(item, PANEL_VALUE, "Error ", NULL);
                    break;
                 }
             }
          }
        }
        if(strcmp(value, "Error")) {
        /* the name is bona-fide but it is not known if it is already in use then check for its existence 
         * in some other class instances
         */
        the_classes = (Array_tile) xv_get(ip->pop, XV_KEY_DATA, FUNC); 
	the_class = (Rectobj) xv_get(ip->instances_list, XV_KEY_DATA, OPER);
        class_list = (Rectobj_list *) xv_get(the_classes, RECTOBJ_CHILDREN);
        conflict = 0;
        list_for(class_list) {
           temp = RECTOBJ_LIST_HANDLE(class_list);
           if(temp != the_class) {
             instance_array_pointer = (Rectobj_list *) xv_get(temp, RECTOBJ_CHILDREN);
             list_for(instance_array_pointer) {
                the_instances_owner = RECTOBJ_LIST_HANDLE(instance_array_pointer);
             }
             the_guys = (Rectobj_list *) xv_get(the_instances_owner, RECTOBJ_CHILDREN);
             list_for(the_guys) { /* the instances */
                the_element = RECTOBJ_LIST_HANDLE(the_guys);
                none = strdup((char *) xv_get(the_element, DRAWTEXT_STRING));
                if(!strcmp(none, value)) { conflict = 1; }
             }
           }
        }
        if(conflict) 
          xv_set(ip->pop, FRAME_LEFT_FOOTER, "This name used for other instance class", NULL);

        else {        
          if((int) xv_get(ip->instances_list, PANEL_LIST_NROWS)) { /* there are instances then just add */
            rows = (int) xv_get(ip->instances_list, PANEL_LIST_NROWS);
            already = 0;
            for(occurrence = 0 ; occurrence < rows ; occurrence++) { /* check the name is not already in the list */
               none = strdup((char *) xv_get(ip->instances_list, PANEL_LIST_STRING, occurrence));
               if(!strcmp(none, value)) { /* is on the list just select it */
                  xv_set(ip->instances_list, PANEL_LIST_SELECT, occurrence, TRUE, NULL);
                  already = 1;
               }               
            }
            if(!already) { /* create an entry */
                 the_instances_array = (Array_tile) xv_get(the_class, XV_KEY_DATA, INSTANCES);
                 some = strdup(value);
                 (void) xv_create(the_instances_array, DRAWTEXT,
                            DRAWTEXT_STRING, some, 
                            XV_SHOW, FALSE,
                            NULL);
                 xv_set(ip->instances_list, 
                      PANEL_LIST_INSERT, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), 
                      PANEL_LIST_STRING, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), some,
                      PANEL_LIST_SELECT, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), TRUE,
                      NULL);
            }
          } else { /* there is no instances array, create one */
            the_instances_array = (Array_tile) xv_create(the_class, ARRAY_TILE,  
                                       XV_SHOW, FALSE, 
                                       NULL);
            some = strdup(value);
            (void) xv_create(the_instances_array, DRAWTEXT,
                            DRAWTEXT_STRING, some, 
                            XV_SHOW, FALSE,
                            NULL);
            xv_set(the_class, XV_KEY_DATA, INSTANCES, the_instances_array, NULL);
            xv_set(ip->instances_list, 
                      PANEL_LIST_INSERT, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), 
                      PANEL_LIST_STRING, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), some,
                      PANEL_LIST_SELECT, (int) xv_get(ip->instances_list, PANEL_LIST_NROWS), TRUE,
                      NULL);
          }
        }
        }

	return panel_text_notify(item, event);
}

