/***********************************************************************/
/* 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 <stdio.h>
#include <dx/dx.h>

extern Field _dxfMakeRGBColorMap(Field);
extern FILE *_dxfopen_dxfile(char *name,char *auxname,char **outname,char *ext);
extern Error _dxfclose_dxfile(FILE *fp,char *filename);
static FILE *openfile(char *filename);
static Error addarray(Field f, int rank, int shape0, char *component);
static Error scale_positions(Field *f,float min, float max);
typedef struct map {
   float level;
   float value;
} Map;
typedef struct hsvo {
   Map *map;
   char *name;
   int count;
   int minmax;
} HSVO;
extern Field _dxfeditor_to_hsv(Array huemap,Array satmap,Array valmap);
extern Field _dxfeditor_to_opacity(Array a );

Object 
DXImportCM(char *filename, char **fieldname)
{
    Group g = NULL;
    Field rgb=NULL,hsv=NULL,of=NULL;
    FILE *fp = NULL;
    double min, max;
    int i, n, nitems,minmax;
    double level, value;
    int color=1,opacity=1;
    int num_op,offset=0;
    float wrap, x, y;   /* wrap, x, y not used */
    HSVO maps[4];
    Array a[4];
    char *hname = "hue positions";
    char *sname = "sat positions";
    char *vname = "val positions";
    char *oname = "opacity positions";

    /* find the file and fopen it */
    fp = openfile(filename);
    if (!fp)
	return NULL;
   
    for (i=0; i<4; i++)
       a[i]=NULL;

    /* Are there any fieldnames (only colormap and opacity allowed) */
    if (fieldname != NULL){
      color=0;
      opacity=0;
      if (!strcmp(fieldname[0],"colormap") || 
		(fieldname[1] && !strcmp(fieldname[1],"colormap"))) 
	 color=1;
      if (!strcmp(fieldname[0],"opacitymap") ||
		(fieldname[1] && !strcmp(fieldname[1],"opacitymap")))
	 opacity=1;
      if (color==0 && opacity==0){
        DXSetError(ERROR_BAD_PARAMETER,"fieldname must be colormap or opacitymap");
        goto error;
      }
    }

    /* read min, max */
    if (fscanf(fp, "%lg %lg", &min, &max) != 2)
	goto error;
   
    /* set up HSVO struct */
    maps[0].name = &hname[0];
    maps[1].name = &sname[0];
    maps[2].name = &vname[0];
    maps[3].name = &oname[0];

    /* read the data, fill map structure and control point arrays */
    for (n=0; n<4; n++){
       a[n] = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 2);
       if (!a[n])
          goto error;
       /* read npts each field: hue, sat, value, opacity */
       if (fscanf(fp, "%d", &nitems) != 1)
	   goto badformat;
       maps[n].count = nitems;
       if(nitems > 0){
	  if (!DXAddArrayData(a[n],0,nitems,NULL))
            goto error;
          maps[n].map = (Map *)DXGetArrayData(a[n]);
          minmax=0;
          for (i=0; i<nitems; i++) {
	    if (fscanf(fp, "%lg %lg %g %g %g", &level, &value, &wrap, &x, &y)
			!= 5)
	       goto badformat;
            /* put these in the xxx positions arrays */
            maps[n].map[i].level = (float)level;
	    maps[n].map[i].value = (float)value;
          }
       }
       else
	  a[n]=NULL;
    }

    if (color){
   /* make the colormap field using the control points */
    hsv = (Field)_dxfeditor_to_hsv(a[0],a[1],a[2]);
    if (!hsv) 
       goto error;
    rgb = (Field)_dxfMakeRGBColorMap((Field)hsv);
    DXDelete((Object)hsv);
    if (!rgb)
	  goto error;
   
    /* scale the positions of rgb to the min and max */
    if (!scale_positions(&rgb,(float)min,(float) max))
       goto error;
    for(n=0; n<3; n++){
       if (maps[n].count > 0){
	   if(!DXSetComponentValue((Field)rgb,maps[n].name,(Object)a[n]))
             goto error;
           a[n]=NULL;
       }
    }
    if (!DXEndField(rgb))
       goto error;
    }

    if (opacity){
       /* make the opacity field using the control points */
       of = (Field)_dxfeditor_to_opacity(a[3]);
       if (!of)
          goto error;
    
       /* scale the positions of rgb to the min and max */
       if (!scale_positions(&of,(float)min,(float) max))
          goto error;
    
       if (maps[3].count > 0){ 
	  if (!DXSetComponentValue((Field)of,maps[3].name,(Object)a[3]))
             goto error;
	  a[3]=NULL;
       }
       if (!DXEndField(of))
          goto error;
    }

    /* depending on fieldname, make either one or both fields.
     * don't put them into the group until you know you want them 
     * both, because the thing going back should be unreferenced
     * and it gets hard once it's been in a group.
     */
   if (fieldname == NULL || (color && opacity)){
      g = DXNewGroup();
      if (!DXSetMember((Group)g,"colormap",(Object)rgb))
         goto error;
      if (!DXSetMember((Group)g,"opacitymap",(Object)of))
         goto error;
   }

  done:
      _dxfclose_dxfile(fp,filename);
      if (g) return (Object)g;
      if (color) return (Object)rgb;
      if (opacity) return (Object)of;

  badformat:
    DXSetError(ERROR_INVALID_DATA, "file not in colormap format");
    /* fall thru */

  error:
    _dxfclose_dxfile(fp,filename);
    for (i=0; i<4; i++)
       if (a[i]) DXDelete((Object)a[i]);
    if (rgb) DXDelete((Object)rgb);
    if (of) DXDelete((Object)of);
    if (g) DXDelete((Object)g);
    return NULL;
}

static FILE *
openfile(char *filename)
{
    FILE *fp = NULL;
    char *outname;

    outname = NULL;
    /* getenv(the net path?) */
    fp = _dxfopen_dxfile(filename,NULL,&outname,".cm");
    if (!fp) {
	DXSetError(ERROR_BAD_PARAMETER, "#12240", filename);
	return NULL;
    }
    DXFree(outname);    
    return fp;
}

static Error 
addarray(Field f, int rank, int shape0, char *component)
{
    Array a = NULL;

    if (rank == 0)
	a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, rank);
    
    else if (rank == 1)
	a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, rank, shape0);
    
    else {
	DXSetError(ERROR_INTERNAL, "bad rank creating colormap field");
	return ERROR;
    }
    
    if (!a)
	return ERROR;
    
    if (!DXSetComponentValue(f, component, (Object)a))
	return ERROR;
    
    return OK;
}

/* scale the positions array to new min and max from normalized space */
static Error
scale_positions(Field *f,float min, float max)
{
   int i,num;
   Array a;
   float *pts;

   a = (Array)DXGetComponentValue((Field)*f,"positions");
   if (!DXGetArrayInfo((Array)a,&num,NULL,NULL,NULL,NULL))
      goto error;
   pts = (float *)DXGetArrayData(a);
   if (!pts)
      goto error;
   for (i=0; i<num; i++)
      pts[i] = pts[i] *(max-min) +min;
   
   DXChangedComponentValues((Field)*f,"positions");
   /*DXSetComponentValue((Field)*f,"positions",(Object)a);
    */

   if (!DXEndField(*f))
      goto error;

   return OK;

error:
   return ERROR;
}

static Error
_dxfExportCM(Object o, char *filename)
{
    /* find the positions min/max, nbins */

    /* if there are original components, format them */

    /* if not, convert to hsv 1-for-1 and output them */

    return OK;
}
