/*****************************************************************************
 * Zoltan Library for Parallel Applications                                  *
 * Copyright (c) 2000,2001,2002, Sandia National Laboratories.               *
 * For more info, see the README file in the top-level Zoltan directory.     *  
 *****************************************************************************/
/*****************************************************************************
 * CVS File Information :
 *    $RCSfile: key_params.c,v $
 *    $Author: dneckels $
 *    $Date: 2007/11/28 16:13:50 $
 *    Revision: 1.47 $
 ****************************************************************************/

#include <stdio.h>
#include "zz_const.h"
#include "key_params.h"
#include "params_const.h"
#include "timer_const.h"
#include "zz_rand.h"


#ifdef __cplusplus
/* if C++, define the rest of this header file as extern C */
extern "C" {
#endif


/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
static PARAM_VARS Key_params[] = {
  { "IMBALANCE_TOL", NULL, "FLOAT", 1 },
  { "AUTO_MIGRATE", NULL, "INT", 0 },
  { "OBJ_WEIGHT_DIM", NULL, "INT", 0 },
  { "EDGE_WEIGHT_DIM", NULL, "INT", 0 },
  { "DEBUG_LEVEL", NULL, "INT", 0 },
  { "DEBUG_PROCESSOR", NULL, "INT", 0 },
  { "DETERMINISTIC", NULL, "INT", 0 },
  { "TIMER", NULL, "STRING", 0 },
  { "NUM_GID_ENTRIES", NULL, "INT", 0 },
  { "NUM_LID_ENTRIES", NULL, "INT", 0 },
  { "RETURN_LISTS", NULL, "STRING", 0 },
  { "LB_METHOD", NULL, "STRING", 0 },
  { "TFLOPS_SPECIAL", NULL, "INT", 0 },
  { "COMM_WEIGHT_DIM", NULL, "INT", 0 }, /* For backward compatibility only. */
                                         /* Prefer use of EDGE_WEIGHT_DIM.   */
  { "NUM_GLOBAL_PARTITIONS", NULL, "INT", 0 },
  { "NUM_LOCAL_PARTITIONS", NULL, "INT", 0 },
  { "MIGRATE_ONLY_PROC_CHANGES", NULL, "INT", 0 },
  { "REMAP", NULL, "INT", 0 },
  { "SEED", NULL, "INT", 0 },
  { NULL, NULL, NULL, 0 } };
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* 
 * Handle parameter changes for variables stored in Zoltan structure.
 */

int Zoltan_Set_Key_Param(
ZZ *zz,                         /* Zoltan structure */
const char *name,		/* name of variable */
const char *val,		/* value of variable */
int  idx 			/* index of vector param, -1 if scalar */
)
{
    const char *yo = "Zoltan_Set_Key_Param";
    char msg[256];
    int status;			/* return code */
    PARAM_UTYPE result;		/* value returned from Check_Param */
    int index;			/* index returned from Check_Param */
    int tmp;
    int Export, import;

    status = Zoltan_Check_Param(name, val, Key_params, &result, &index);

    if (status == 0) {

      switch (index) {

      case 0:  		/* Imbalance_Tol */
        if (result.def) 
            result.fval = ZOLTAN_LB_IMBALANCE_TOL_DEF;
	if (result.fval < 1.0) {
	    sprintf(msg, "Invalid Imbalance_Tol value (%g) "
		"being set to %g.", result.fval, ZOLTAN_LB_IMBALANCE_TOL_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.fval = ZOLTAN_LB_IMBALANCE_TOL_DEF;
	}
        if (idx > zz->Obj_Weight_Dim){
          sprintf(msg, "Imbalance_Tol index %d > Obj_Weight_Dim = %d\n",
            idx, zz->Obj_Weight_Dim);
          ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
        }
        else if (idx < -1){
          sprintf(msg, "Invalid Imbalance_Tol index %d\n", idx);
          ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
        }
        else if (idx == -1){
          /* Set all entries to the same value. */
          for (idx=0; idx<zz->LB.Imb_Tol_Len; idx++)
	    zz->LB.Imbalance_Tol[idx] = result.fval;
        }
        else
	  zz->LB.Imbalance_Tol[idx] = result.fval;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 1:		/* Help_Migrate */
        if (result.def)
            result.ival = ZOLTAN_AUTO_MIGRATE_DEF;
	zz->Migrate.Auto_Migrate = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 2:		/* Object weight dim.  */
        if (result.def)
            result.ival = ZOLTAN_OBJ_WEIGHT_DEF;
	if (result.ival < 0) {
	    sprintf(msg, "Invalid Obj_Weight_Dim value (%d) "
		"being set to %d.", result.ival, ZOLTAN_OBJ_WEIGHT_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.ival = ZOLTAN_OBJ_WEIGHT_DEF;
	}
	zz->Obj_Weight_Dim = result.ival;
        if (zz->Obj_Weight_Dim > zz->LB.Imb_Tol_Len){
          /* Resize and reallocate Imb_Tol. */
          zz->LB.Imb_Tol_Len += 10;
          zz->LB.Imbalance_Tol = (float *) ZOLTAN_REALLOC(zz->LB.Imbalance_Tol,
            zz->LB.Imb_Tol_Len * sizeof(float));
        }
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 3: 		/* Edge weight dim.  */
      case 13:
        if (result.def)
            result.ival = ZOLTAN_EDGE_WEIGHT_DEF;
	if (result.ival < 0) {
	    sprintf(msg, "Invalid Edge_Weight_Dim value (%d) "
		"being set to %d.", result.ival, ZOLTAN_EDGE_WEIGHT_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.ival = ZOLTAN_EDGE_WEIGHT_DEF;
	}
	zz->Edge_Weight_Dim = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 4: 		/* Debug level  */
        if (result.def)
            result.ival = ZOLTAN_DEBUG_LEVEL_DEF;
	if (result.ival < 0) {
	    sprintf(msg, "Invalid Debug_Level value (%d) "
		"being set to %d.", result.ival, ZOLTAN_DEBUG_LEVEL_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.ival = ZOLTAN_DEBUG_LEVEL_DEF;
	}
	zz->Debug_Level = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 5: 		/* Debug processor  */
        if (result.def)
            result.ival = ZOLTAN_DEBUG_PROC_DEF;
	if (result.ival < 0 || result.ival > zz->Num_Proc) {
	    sprintf(msg, "Invalid Debug_Processor value (%d) "
		"being set to %d.", result.ival, ZOLTAN_DEBUG_PROC_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.ival = ZOLTAN_DEBUG_PROC_DEF;
	}
	zz->Debug_Proc = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;
       
      case 6: 		/* Deterministic flag */
        if (result.def)
            result.ival = ZOLTAN_DETERMINISTIC_DEF;
	if (result.ival < 0) {
	    sprintf(msg, "Invalid Deterministic value (%d) "
		"being set to %d.", result.ival, ZOLTAN_DETERMINISTIC_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.ival = ZOLTAN_DETERMINISTIC_DEF;
	}
	zz->Deterministic = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 7: 		/* Timer */
	status = Zoltan_Set_Timer_Param(name, val, &tmp);
        zz->Timer = tmp;
        Zoltan_Timer_ChangeFlag(zz->ZTime, zz->Timer);

	if (status==0) status = 3;	/* Don't add to Params field of ZZ */
        break;

      case 8:           /* Num_GID_Entries */
        if (result.def)
            result.ival = ZOLTAN_NUM_ID_ENTRIES_DEF;
        if (result.ival < 1) {
	    sprintf(msg, "Invalid Num_GID_Entries value (%d); "
		"being set to %d.", result.ival, ZOLTAN_NUM_ID_ENTRIES_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
            result.ival = ZOLTAN_NUM_ID_ENTRIES_DEF;
        }
        zz->Num_GID = result.ival;
        status = 3;
        break;

      case 9:           /* Num_LID_Entries */
        if (result.def)
            result.ival = ZOLTAN_NUM_ID_ENTRIES_DEF;
        if (result.ival < 0) {
	    sprintf(msg, "Invalid Num_LID_Entries value (%d); "
		"being set to %d.", result.ival, ZOLTAN_NUM_ID_ENTRIES_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
            result.ival = ZOLTAN_NUM_ID_ENTRIES_DEF;
        }
        zz->Num_LID = result.ival;
        status = 3;
        break;

      case 10:          /* LB.Return_Lists */
        Export = (strstr(result.sval, "EXPORT") != NULL);
        import = (strstr(result.sval, "IMPORT") != NULL);
        if ((Export && import) || (strcmp(result.sval, "ALL") == 0)) {
          tmp = ZOLTAN_LB_ALL_LISTS;  /* Export AND import lists */
          status = 3;
        }
        else if (import){
          tmp = ZOLTAN_LB_IMPORT_LISTS;  /* import lists */
          status = 3;
        }
        else if (Export){
          tmp = ZOLTAN_LB_EXPORT_LISTS;  /* Export lists */
          status = 3;
        }
        else if (strstr(result.sval, "PARTITION")!=NULL) {
          /* list of every object's process/partition assignment */
          tmp = ZOLTAN_LB_COMPLETE_EXPORT_LISTS; 
          status = 3;
        }
        else if (strcmp(result.sval, "NONE")==0) {
          tmp = ZOLTAN_LB_NO_LISTS;      /* no lists */
          status = 3;
        }
        else{
          tmp = ZOLTAN_LB_RETURN_LISTS_DEF;
          sprintf(msg, "Unknown return_lists option %s.", result.sval);
          ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
          status = 2; /* Illegal parameter */
        }
	zz->LB.Return_Lists = tmp;
        break;

      case 11:          /* LB_Method */
        status = Zoltan_LB_Set_LB_Method(zz,result.sval);
        if (status == ZOLTAN_OK)
          status = 3;
        break;

      case 12: 		/* Tflops Special flag */
        if (result.def)
            result.ival = ZOLTAN_TFLOPS_SPECIAL_DEF;
	if (result.ival < 0) {
	    sprintf(msg, "Invalid Tflops Special value (%d) "
		"being set to %d.", result.ival, ZOLTAN_TFLOPS_SPECIAL_DEF);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
	    result.ival = ZOLTAN_TFLOPS_SPECIAL_DEF;
	}
	zz->Tflops_Special = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 14:          /* Num_Global_Partitions */
        if (result.def)
            result.ival = zz->Num_Proc;
        if (result.ival < 1) {
	    sprintf(msg, "Invalid Num_Global_Partitions value (%d); "
		"being set to %d.", result.ival,zz->Num_Proc);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
            result.ival = zz->Num_Proc;
        }
        zz->LB.Num_Global_Parts_Param = result.ival;
        status = 3;
        break;

      case 15:          /* Num_Local_Partitions */
        if (result.def)
            result.ival = -1;
        if (result.ival < -1) {
	    sprintf(msg, "Invalid Num_Local_Partitions value (%d); "
		"being set to %d.", result.ival,-1);
            ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
            result.ival = -1;
        }
        zz->LB.Num_Local_Parts_Param = result.ival;
        status = 3;
        break;

      case 16:		/* Migrate_Only_Proc_Changes */
        if (result.def)
            result.ival = ZOLTAN_MIGRATE_ONLY_PROC_CHANGES_DEF;
	zz->Migrate.Only_Proc_Changes = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 17:		/* LB.Remap */
        if (result.def)
            result.ival = 0;
	zz->LB.Remap_Flag = result.ival;
	status = 3;		/* Don't add to Params field of ZZ */
        break;

      case 18:          /* Seed */
        if (result.def)
            result.ival = Zoltan_Seed();
        Zoltan_Srand(result.ival, NULL);
        status = 3;
        break;
      }  /* end switch (index) */
    }

    return(status);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
 *  Print key parameters.
 */
void Zoltan_Print_Key_Params(ZZ const *zz)
{
  int i;
  for (i=0; i<(zz->Obj_Weight_Dim?zz->Obj_Weight_Dim:1); i++)
    printf("ZOLTAN Parameter %s[%1d] = %f\n", Key_params[0].name, 
         i, zz->LB.Imbalance_Tol[i]);
  printf("ZOLTAN Parameter %s = %s\n", Key_params[1].name, 
         (zz->Migrate.Auto_Migrate ? "TRUE" : "FALSE"));
  printf("ZOLTAN Parameter %s = %d\n", Key_params[16].name, 
         zz->Migrate.Only_Proc_Changes);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[2].name, 
         zz->Obj_Weight_Dim);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[3].name, 
         zz->Edge_Weight_Dim);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[4].name, 
         zz->Debug_Level);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[5].name, 
         zz->Debug_Proc);
  printf("ZOLTAN Parameter %s = %s\n", Key_params[6].name, 
         (zz->Deterministic ? "TRUE" : "FALSE"));
  printf("ZOLTAN Parameter %s = %d ", Key_params[7].name, zz->Timer);
  if (zz->Timer == ZOLTAN_TIME_WALL)
     printf("(wall)");
  else if (zz->Timer == ZOLTAN_TIME_CPU)
     printf("(cpu)");
  printf("\n");
  printf("ZOLTAN Parameter %s = %d\n", Key_params[8].name, 
         zz->Num_GID);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[9].name, 
         zz->Num_LID);
  printf("ZOLTAN Parameter %s = ", Key_params[10].name);
  switch (zz->LB.Return_Lists) {
  case ZOLTAN_LB_ALL_LISTS:
    printf("IMPORT AND EXPORT\n");
    break;
  case ZOLTAN_LB_IMPORT_LISTS:
    printf("IMPORT\n");
    break;
  case ZOLTAN_LB_EXPORT_LISTS:
    printf("EXPORT\n");
    break;
  case ZOLTAN_LB_COMPLETE_EXPORT_LISTS:
    printf("PARTITION ASSIGNMENTS\n");
    break;
  case ZOLTAN_LB_NO_LISTS:
    printf("NONE\n");
    break;
  }
  if (zz->Tflops_Special)   /* print only if set */
     printf("ZOLTAN Parameter %s = %s\n", Key_params[12].name, "TRUE");
  printf("ZOLTAN Parameter %s = %d\n", Key_params[14].name, 
         zz->LB.Num_Global_Parts_Param);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[15].name, 
         zz->LB.Num_Local_Parts_Param);
  printf("ZOLTAN Parameter %s = %d\n", Key_params[17].name, 
         zz->LB.Remap_Flag);
  printf("ZOLTAN Parameter %s = %d (%u)\n", Key_params[18].name, 
         Zoltan_Seed(), Zoltan_Seed());
}

#ifdef __cplusplus
} /* closing bracket for extern "C" */
#endif
