/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>


#include "interact.h"

#define MAXRANK 16
#define MSGLEN 240

static int readvalue(Object,char *,char *,Object *);
static int compare_arrays(Array *a, Array *b,int items,int dim,Type type);
static Error read_and_compare(Object cvalue,Object svalue,Object uvalue,int *on,          Object *out); 

int m_Toggle(Object *in, Object *out)
{
   struct einfo ei;
   char *id, *label;
   Object idobj;
   char *set="set= ",*unset="unset= ";
   int items,shape[MAXRANK],rank;
   Type type;
   Category cat;
   void *uivalue;
   int toggle,change;

   ei.msgbuf = NULL;
   out[0] = in[1];

   /* get id */
   if (!DXExtractString(in[0], &id)){
       DXSetError(ERROR_BAD_PARAMETER,"#10000","id");
       goto error;
   }
   idobj=in[0];

   /* read toggle value (set=1, unset=0) */
   if (!in[2])
      toggle=0;
   else{
      if (!DXExtractInteger(in[2],&toggle)){
	 DXSetError(ERROR_INTERNAL,"toggle value is not integer");
	 goto error;
      }
   }
   
   /* read set value */
   change = _dxfcheck_obj_cache(in[3],id,3,idobj);
   if (change==0) set=NULL;
   if (in[3]){	/* set value is data-driven */
      if (toggle==1){
	 if (!readvalue(in[3],id,set,out))
            goto error;
      }
      else{
	 if (!readvalue(in[3],id,set,NULL))
	    goto error;
      }
   }

   /* read unset value */
   change = _dxfcheck_obj_cache(in[4],id,4,idobj);
   if (change==0) unset=NULL;
   if (in[4]){
      if (toggle==0){
	 if (!readvalue(in[4],id,unset,out))
            goto error;
      }
      else{
	 if (!readvalue(in[4],id,unset,NULL))
	    goto error;
      }
   }

   /* read label */
   if (in[5]){
      if (!DXExtractString(in[5], &label)){
         DXSetError(ERROR_BAD_PARAMETER,"#10200","label");
         goto error;
      }
      ei.maxlen = (int)strlen(label)+SLOP;
      ei.msgbuf = (char *)DXAllocateZero(ei.maxlen);
      ei.atend = 0;
      if (!ei.msgbuf)
         goto error;
      ei.mp =ei.msgbuf;
      shape[0] = (int)strlen(label);
      sprintf(ei.mp, "label="); while(*ei.mp) ei.mp++;
      if (!_dxfprint_message(label,&ei,TYPE_STRING,1,shape,1))
         goto error;
      DXUIMessage(id,ei.msgbuf);
      DXFree(ei.msgbuf);
   }


   return OK;

error:
   if (out[0]) out[0]=NULL;
   if (ei.msgbuf) DXFree(ei.msgbuf);
   return ERROR;
}


/* routine for reading, and optionally sending UIMessage or setting output */
int readvalue(Object o,char *id,char *value,Object *out)
{
   struct einfo ei;
   char *set_string,*unset_string,*cstring;
   int items,shape[MAXRANK],rank;
   Type type;
   Category cat;
   void *p_set, *p_unset;
      
   /* setup message */
   ei.maxlen = MSGLEN;
   ei.atend = 0;
   if (value) ei.msgbuf = (char *)DXAllocateZero(ei.maxlen+SLOP);
   if (!ei.msgbuf)
      goto error;
   ei.mp =ei.msgbuf;

      if (!DXExtractString((Object)o,&set_string)){
         if (!DXGetArrayInfo((Array)o,&items,&type,&cat,&rank,shape))
            return ERROR;
         p_set = DXGetArrayData((Array)o); 
         if (rank==0) shape[0]=1;
         if (value){
            sprintf(ei.mp, "%s",value); while(*ei.mp) ei.mp++;
	    if (!_dxfprint_message(p_set,&ei,type,rank,shape,items))
	       goto error;
	 }
	 if (out){
            out[0] = (Object)DXNewArrayV(type,CATEGORY_REAL,rank,shape);
            if(!out[0] || !DXAddArrayData((Array)out[0],0,items,(Pointer)p_set))
	       goto error;
	 }
      }
      else{
         shape[0] = (int)strlen(set_string);
         if (value){
            sprintf(ei.mp,"%s",value); while(*ei.mp) ei.mp++;
	    if (!_dxfprint_message(set_string,&ei,TYPE_STRING,1,shape,1))
               goto error;
	 }
	 if (out) out[0] = (Object)DXNewString(set_string);
      }

   if (value) {
      DXUIMessage(id,ei.msgbuf);
      DXFree(ei.msgbuf);
   }
   return OK;

error:
      return ERROR;
}

Error
read_and_compare(Object cvalue,Object svalue,Object uvalue,int *on,Object *out) 
{
   char *cstring,*sstring;
   void *p_set,*p_current;
   int items,i,shape[MAXRANK],sp[MAXRANK],rank,r;
   int n,dim;
   Type type,t;
   Category cat,c;

      if (!DXExtractString((Object)cvalue,&cstring)){
         if (!DXGetArrayInfo((Array)cvalue,&items,&type,&cat,&rank,shape))
            return ERROR;
         p_current = DXGetArrayData((Array)cvalue); 
	 /* compare current array with previous set array */
	 if (DXGetArrayInfo((Array)svalue,&i,&t,&c,&r,sp)){
	    if (items==i && type==t && cat==c && rank==r ){
	       if (rank==0) dim=1;
	       else dim=sp[0];
	       *on = compare_arrays((Array)cvalue,(Array)svalue,items,dim,type);
            }
	 }
	 else
	    *on=0; 	/* toggle is unset */

         if (out){
            out[0] = (Object)DXNewArrayV(type,CATEGORY_REAL,rank,shape);
            if(!out[0] || !DXAddArrayData((Array)out[0],0,items,(Pointer)p_current))
               goto error;
         }
      }
      else{
	 if (DXExtractString((Object)svalue,&sstring)){
	       if(!strcmp(cstring,sstring)) 
		  *on=1;
	       else 
		  *on=0;
	       if (out) out[0] = (Object)DXNewString(cstring);
	 }
	 else
	    *on=0;
      }
      return OK;

error:
      return ERROR;
}

int
compare_arrays(Array *a, Array *b,int items,int dim,Type type)
{
   int n,count=0;
   int *a_int,*b_int;
   float *a_f,*b_f;
      
      switch(type){
	 case(TYPE_INT):
	       a_int = (int *)DXGetArrayData((Array)a);
	       b_int = (int *)DXGetArrayData((Array)b);
	       for (n=0; n<items*dim; n++){
	          if (a_int[n] == b_int[n])
	             count++;
	       }
	       break;
	 case(TYPE_FLOAT):
	       a_f = (float *)DXGetArrayData((Array)a);
	       b_f = (float *)DXGetArrayData((Array)b);
	       for (n=0; n<items*dim; n++){
	          if (a_f[n] == b_f[n])
	          count++;
	       }
	       break;
	 default:
	       return(-1);
	 }
	 if (count==items*dim)   	/* arrays are the same */
	    return (1);
	 else
	     return(0);

}
