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

#include <dxconfig.h>


static Error DoPick(Object, Field, int, int, int, int, Object *);
static Error SetValidity(Object, int);

Error m_PickInvalidate(Object *in, Object *out)
{
  Object o = NULL, leaf=NULL;
  Field pickfield;
  int poke, pick, depth, exclude;
  RGBColor color;
  
  /* 
   * copy the structure of in[0], which is the object in which
   * picking took place 
   */

  if (!in[0]) {
    DXSetError(ERROR_BAD_PARAMETER, "missing input");
    goto error;
  }
  o = (Object)DXCopy(in[0], COPY_STRUCTURE);
  if (!o)
    goto error;
  

  /* 
   * pickfield is expected to be a field
   */

  if (!(DXGetObjectClass(in[1])==CLASS_FIELD)) {
    DXSetError(ERROR_INVALID_DATA,"pickfield must be a field");
    goto error;
  }
 
 
  /* 
   * in[1] is the pick field. 
   * If the pick field is null or an empty field, just return 
   * the copy of the object 
   */

  if (!in[1] || DXEmptyField((Field)in[1])) {
    out[0] = o;
    return OK;
  }
  pickfield = (Field)in[1];
  
  /* 
   * get the exclude param which will be used 
   * to set picked objects, which is in[2] 
   */

  if (in[2]) {
    if (!DXExtractInteger((Object)in[2], &exclude)) {
      DXSetError(ERROR_BAD_PARAMETER,"exclude must be either 0 or 1");
      goto error;
    }
    if ((exclude !=0) &&(exclude != 1)) {
      DXSetError(ERROR_BAD_PARAMETER,"exclude must be either 0 or 1");
      goto error;
    }
  } 
  else {
    exclude = 0;
  }
  
  
  /* 
   * first set all to invalid, to initialize 
   */
  if (exclude==0) {
    if (!SetValidity(o, 0))
      goto error;
  }
  else {
    if (!SetValidity(o, 1))
      goto error;
  }
  
  
  

  /* 
   * are we to selecting a particular poke, or all of them?
   */

  if (!in[3]) {
    poke = -1;
  }
  else {
    if (!DXExtractInteger(in[3], &poke)) {
      DXSetError(ERROR_BAD_PARAMETER,"poke must be a non-negative integer");
      goto error;
    }
    if (poke < 0) {
      DXSetError(ERROR_BAD_PARAMETER,"poke must be a non-negative integer");
      goto error;
    }
  }
  
  
  /* 
   * are we to selecting a particular pick, or all of them?
   */

  if (!in[4]) {
    pick = -1;
  }
  else {
    if (!DXExtractInteger(in[4], &pick)) {
      DXSetError(ERROR_BAD_PARAMETER,"depth must be a non-negative integer");
      goto error;
    }
    if (pick < 0) {
      DXSetError(ERROR_BAD_PARAMETER,"depth must be a non-negative integer");
      goto error;
    }
  }
  
  /* 
   * are we to selecting a depth?
   */

  if (!in[5]) {
    depth = -1;
  }
  else {
    if (!DXExtractInteger(in[5], &depth)) {
      DXSetError(ERROR_BAD_PARAMETER,"depth must be a non-negative integer");
      goto error;
    }
    if (depth < 0) {
      DXSetError(ERROR_BAD_PARAMETER,"depth must be a non-negative integer");
      goto error;
    }
  }
  
 
  /* 
   * traverse the pick object, using the pick structure, 
   * passing the given parameters 
   */ 

  if (!DoPick(o, pickfield, exclude, poke, pick, depth, &leaf))
    goto error;
  
  
  
  /* 
   * successful return 
   */

  out[0] = o;
  out[1] = leaf;
  return OK;
  
  /* 
   * return on error 
   */  

 error:
  DXDelete(o);
  return ERROR;
}




/* 
 * The DoPick routine traverses  the picked object 
 */

static
  Error
  DoPick(Object o, Field pickfield, int exclude, int pokes, int picks, 
         int depth, Object *out)
{
  int pokecount, pickcount, poke, pick, i, pathlength;
  int vertexid, elementid, *path, numitems, index, validity;
  Object current;
  Matrix matrix;
  Array a, newcolors=NULL, oldcolors;
  char *depatt;
  RGBColor *newcolors_ptr, oldcolor;
  int pokemin, pokemax;
  int pickmin, pickmax;
  int thisdepth;





  /* 
   * find out how many pokes there are 
   */

  DXQueryPokeCount(pickfield, &pokecount);
 
  /* 
   * The user has specified to mark all pokes 
   */

  if (pokes < 0) {
      pokemin = 0, pokemax = pokecount-1;
  }

  /* 
   * The user has specified a poke larger than the number present 
   */

  else if (pokes > pokecount-1) {
      DXSetError(ERROR_BAD_PARAMETER,
                 "only %d pokes are present", pokecount);
      return OK;
  }

  /*
   * Consider only the given poke
   */

  else
      pokemin = pokemax = pokes;



  
  /* 
   * for each poke... 
   */

  for (poke=pokemin; poke<=pokemax; poke++) {
    
    /* 
     * find out how many picks there are in this poke
     */

    if (!DXQueryPickCount(pickfield, poke, &pickcount))
      goto error;

    /*
     * The user has specified that we are to consider all of the picks
     */

    if (picks < 0) {
	pickmin = 0, pickmax = pickcount-1;
    }
   
    /* 
     * Warning if this particular poke does not contain that many picks
     */

    else if (picks > pickcount-1) {
	DXWarning("poke %d contains only %d picks", poke, pickcount);
    }

    else {
	pickmin = pickmax = picks;
  
	/* 
	 * for each pick ... 
	 */

	for (pick=pickmin; pick<=pickmax; pick++) {
      
	  /* 
	   * for the given pickfield, the current poke number, and the 
	   * current pick number,  get the traversal path "path", the length
	   * of the traversal path "pathlength", and the id's of the 
	   * picked element and the picked vertex
	   */ 

	  DXQueryPickPath(pickfield, poke, pick, &pathlength, &path,
						&elementid, &vertexid);
      
	  /* 
	   * initialize current to the picked object, and matrix to the
	   * identity matrix
	   */ 

	  current = o;
	  matrix = Identity;
	  if (depth != -1 && pathlength > depth)
	    thisdepth = depth;
	  else
	    thisdepth = pathlength;
	  
	  /* 
	   * iterate through the pick path 
	   */

	  for (i=0; i<thisdepth; i++) {
	    current = DXTraversePickPath(current, path[i], &matrix);
	    if (!current)
	      goto error;
	  }

	  /* 
	   * current is now the field level of the picked object, and we have
	   * the element and vertex id's of the picked object 
	   */
	  

	    /* 
	     * we are simply to invalidate the entire field
	     */ 

            if (exclude == 0)
              validity =  1;
            else 
              validity =  0;
	    if (!SetValidity(current, validity))
	      goto error;
 
            /* return the object */
            *out = current;
	  }
      }
  }
  
  return OK;
  
 error:
  DXDelete((Object)newcolors);
  return ERROR;
}





/* 
 * This routine simply sets all colors to the given color in object o 
 */

static Error SetValidity(Object o, int validity)
{
  Object subo;
  int i;
  InvalidComponentHandle handle=NULL;


  switch (DXGetObjectClass(o)) {
    
    
  case (CLASS_GROUP):

    /* 
     * if o is a group, call SetValidity recursively on its children 
     */

    for (i=0; subo = DXGetEnumeratedMember((Group)o, i, NULL); i++) 
      if (!SetValidity(subo, validity))
         goto error;
    break;
    
    
  case (CLASS_XFORM):

    /* 
     * if o is an xform, call SetValidity on its child
     */

    DXGetXformInfo((Xform)o, &subo, NULL);
    if (!SetValidity(subo, validity))
       goto error;
    break;
    
    
  case (CLASS_CLIPPED):

    /* 
     * if o is an clipped object, call SetValidity on its child 
     */

    DXGetClippedInfo((Clipped)o, &subo, NULL);
    if (!SetValidity(subo, validity))
       goto error;
    break;
    

  case (CLASS_FIELD):

    /* 
     * if o is a field, set the validity 
     */
    
    if (DXEmptyField((Field)o))
      return OK;
    

    
    if (DXGetComponentValue((Field)o, "connections")) {
      handle = DXCreateInvalidComponentHandle(o, NULL, "connections");
      if (!handle)
         goto error;
      if (validity==0) {
        if (!DXSetAllInvalid(handle))
          goto error;
      }
      else {
        if (!DXSetAllValid(handle))
          goto error;
      }
    }
    else {
      handle = DXCreateInvalidComponentHandle(o, NULL, "positions");
      if (!handle)
         goto error;
      if (validity==0) {
        if (!DXSetAllInvalid(handle))
          goto error;
      }
      else {
        if (!DXSetAllValid(handle))
          goto error;
      }
    }
    if (!DXSaveInvalidComponent((Field)o, handle))
       goto error;
    
    break;
  }
  
  
  /* 
   * successful return, or return on error 
   */


  DXFreeInvalidComponentHandle(handle);
  return OK;
 error:
  DXFreeInvalidComponentHandle(handle);
  return ERROR;
}
