/* ****************************************************************************
*
* paExtendedUsage - print extended synopsis
*/
void paExtendedUsage(void)
{
    char*         spacePad;
    char          string[80];
    PaiArgument*  aP;
    int           optNameMaxLen = 0;
    int           varNameMaxLen = 0;
    int           valsMaxLen    = 0;
    char          format[64];
    char          progNAME[128];
    bool          firstLine = true;

    snprintf(progNAME, sizeof(progNAME), "Extended Usage: %s ", progName);
    spacePad = (char*) strdup(progNAME);
    memset(spacePad, 0x20202020, strlen(spacePad));  /* replace progNAME */

    PA_M(("-------------- Preparing list for Extended usage -----------------"));
    paIterateInit();
    while ((aP = paIterateNext(paiList)) != NULL)
    {
        char  name[128];
        char  vals[128];
        char  defVal[20];
        char  minVal[20];
        char  maxVal[20];
        char  realVal[80];
        char  out[256];
        char  out2[256];

        PA_M(("processing '%s' for extended usage\n", aP->name));

        /* 1. Option Name */
        memset(name, 0, sizeof(name));
        if (PA_IS_OPTION(aP) && (aP->sort == PaOpt))
        {
            snprintf(name, sizeof(name), "[%s]", paFullName(aP, string, sizeof(string)));
        }
        else if (PA_IS_OPTION(aP) && (aP->sort == PaReq))
        {
            snprintf(name, sizeof(name), "%s", paFullName(aP, string, sizeof(string)));
        }
        else if (PA_IS_PARAMETER(aP) && (aP->sort == PaOpt))
        {
            snprintf(name, sizeof(name), "(%s)", aP->description);
        }
        else if (PA_IS_PARAMETER(aP) && (aP->sort == PaReq))
        {
            snprintf(name, sizeof(name), "[%s]", aP->description);
        }
        optNameMaxLen = MAX(strlen(name), (unsigned int) optNameMaxLen);


        /* 2. Variable Name */
        memset(name, 0, sizeof(name));
        if (PA_IS_VARIABLE(aP))
        {
            paEnvName(aP, name, sizeof(name));
            varNameMaxLen = MAX(strlen(name), (unsigned int) varNameMaxLen);
        }


        /* 3. Values */
        getApVals(aP, defVal, sizeof(defVal), minVal, sizeof(minVal), maxVal, sizeof(maxVal), realVal, sizeof(realVal));

        if (aP->hasDefault == false)
        {
            snprintf(name, sizeof(name), "%s", realVal);
        }
        else
        {
            snprintf(name, sizeof(name), "%s /%s/", realVal, defVal);
        }

        if ((aP->hasMinLimit == false) && (aP->hasMaxLimit == false))
        {
            snprintf(vals, sizeof(vals), "%s", name);
        }
        else if (aP->hasMinLimit == false)
        {
            snprintf(vals, sizeof(vals), "%s <= %s", name, escape(out, maxVal));
        }
        else if (aP->hasMaxLimit == false)
        {
            snprintf(vals, sizeof(vals), "%s >= %s", name, escape(out, minVal));
        }
        else
        {
            snprintf(vals, sizeof(vals), "%s <= %s <= %s", escape(out, minVal), name, escape(out2, maxVal));
        }

        valsMaxLen = MAX(strlen(vals), (unsigned int) valsMaxLen);
    }

    snprintf(format, sizeof(format), "%%-%ds %%-%ds %%-%ds %%-%ds %%s\n",
             (int) strlen(progName) + 1,
             optNameMaxLen + 2,
             varNameMaxLen + 2,
             valsMaxLen + 2);

    // paLogOn = true;
    paIterateInit();
    while ((aP = paIterateNext(paiList)) != NULL)
    {
        char  optName[128];
        char  varName[128];
        char  vals[128];
        char  from[128];
        char  defVal[20];
        char  minVal[20];
        char  maxVal[20];
        char  realVal[80];
        char  s[512];

        if (aP->sort == PaHid)
        {
            PA_M(("skipping hidden option '%s'", aP->option));
            continue;
        }

        /* 1. Option Name */
        if (PA_IS_OPTION(aP) && (aP->sort == PaOpt))
        {
            snprintf(optName, sizeof(optName), "[%s]", paFullName(aP, string, sizeof(string)));
        }
        else if (PA_IS_OPTION(aP) && (aP->sort == PaReq))
        {
            snprintf(optName, sizeof(optName), "%s", paFullName(aP, string, sizeof(string)));
        }
        else if (PA_IS_PARAMETER(aP) && (aP->sort == PaOpt))
        {
            snprintf(optName, sizeof(optName), "(%s)", aP->description);
        }
        else if (PA_IS_PARAMETER(aP) && (aP->sort == PaReq))
        {
            snprintf(optName, sizeof(optName), "[%s]", aP->description);
        }
        else
        {
            snprintf(optName, sizeof(optName), " ");
        }


        /* 2. variable name */
        if (PA_IS_VARIABLE(aP))
        {
            paEnvName(aP, varName, sizeof(varName));
        }
        else
        {
            snprintf(varName, sizeof(varName), " ");
        }


        /* 3. Limits */
        if ((aP->type != PaSList) && (aP->type != PaIList))
        {
            char valWithDef[128];
            char fromN[64];

            getApVals(aP, defVal, sizeof(defVal), minVal, sizeof(minVal), maxVal, sizeof(maxVal), realVal, sizeof(realVal));

            if (aP->hasDefault == false)
            {
                snprintf(valWithDef, sizeof(valWithDef), "%s", realVal);
            }
            else
            {
                snprintf(valWithDef, sizeof(valWithDef), "%s /%s/", realVal, defVal);
            }

            if ((aP->hasMinLimit == false) && (aP->hasMaxLimit == false))
            {
                snprintf(vals, sizeof(vals), "%s", valWithDef);
            }
            else if (aP->hasMinLimit == false)
            {
                snprintf(vals, sizeof(vals), "%s <= %s", valWithDef, maxVal);
            }
            else if (aP->hasMaxLimit == false)
            {
                snprintf(vals, sizeof(vals), "%s >= %s", valWithDef, minVal);
            }
            else
            {
                snprintf(vals, sizeof(vals), "%s <= %s <= %s", minVal, valWithDef, maxVal);
            }

            snprintf(from, sizeof(from), "  (%s)", paFromName(aP, fromN, sizeof(fromN)));
        }
        else
        {
            snprintf(vals, sizeof(vals), " ");
            snprintf(from, sizeof(from), " ");
        }

        snprintf(s, sizeof(s), format, (firstLine)? progNAME : spacePad, optName, varName, vals, from);
        strncat(paResultString, s, sizeof(paResultString) - 1);

        firstLine = false;
    }
    // paLogOn = false;

    strncat(paResultString, "\r", sizeof(paResultString) - 1);

    free(spacePad);

    printf("%s\n", paResultString);
    exit(1);
}
/* ****************************************************************************
*
* paOptionsParse - 
*/
int paOptionsParse(PaiArgument* paList, char* argV[], int argC)
{
  PaiArgument*  aP;
  char*         valueP;
  int           argNo         = 0;
  int           param         = 1;
  bool          extendedUsage = false;
  char          w[512];

  LM_ENTRY();
  w[0] = 0;

  PA_M(("incoming arg list of %d args", argC));
  while (++argNo < argC)
  {
    char  e[80];
    char  o[80];
    int   eee;
    int*  eP;

    eP  = &eee;
    *eP = PaNotOk;

    PA_M(("Looking up '%s'", argV[argNo]));
    if ((aP = argFind(paList, argV[argNo], STRICT, NULL)) != NULL)
    {
      valueP = argV[++argNo];
      if (aP->type == PaBoolean)
        --argNo;
    }
    else if ((aP = argFind(paList, argV[argNo], UNSTRICT, NULL)) != NULL)
      valueP = &argV[argNo][strlen(aP->option)];
    else if ((aP = argFind(paList, (char*) "", UNSTRICT, &param)) != NULL)
      valueP = argV[argNo];
    else
    {
      snprintf(w, sizeof(w), "%s '%s' not recognized", optOrPar(argV[argNo]), argV[argNo]);
      PA_W(("Warning: '%s'", w));
      PA_WARNING(PasNoSuchOption, w);
      continue;
    }

    LM_T(LmtPaApVals, ("found option '%s'", aP->name));

    if (aP->varP == (void*) &paUsageVar)
    {
      memset(paResultString, 0, sizeof(paResultString));
      if (extendedUsage == false)
      {
        paUsage();
        return -2;
      }
    }
    else if (aP->varP == (void*) &paVersion)
    {
      paVersionPrint();
      exit(0);
    }
    else if (aP->varP == (void*) &paLogDir)
    {
      if (valueP != NULL)
      {
        snprintf(paLogDir, sizeof(paLogDir), "%s", (char*) valueP);
        printf("log directory: '%s'\n", paLogDir);
      }
    }
    else if (aP->varP == (void*) &paEUsageVar)
      extendedUsage = true;
    else if (aP->varP == (void*) &paHelpVar)
    {
      memset(paResultString, 0, sizeof(paResultString));
      paHelp();
      return -2;
    }

    if (aP->used > 0)
    {
      if ((aP->type != PaSList) && (aP->type != PaIList) && (aP->what != PawParameter))
      {
        snprintf(w, sizeof(w), "multiple use of %s", aP->name);
        PA_WARNING(PasMultipleOptionUse, w);
        continue;
      }
    }

    aP->from = PafArgument;

    if (aP->type == PaBoolean)
    {
      if (strlen(argV[argNo]) != strlen(aP->option))
      {
        char tmp[128];
        snprintf(w, sizeof(w), "boolean option '%s' doesn't take parameters", paFullName(aP, e, sizeof(e)));
        snprintf(tmp, sizeof(tmp), "%c%s", argV[argNo][0], &argV[argNo][2]);
        LM_W(("Changing arg %d from '%s' to '%s'", argNo, argV[argNo], tmp));
        snprintf(argV[argNo], strlen(argV[argNo]), "%s", tmp);
        --argNo;
      }

      *((bool*) aP->varP) = (((bool) ((int) aP->def)) == true)? false : true;

      aP->used++;
      continue;
    }

    if ((argNo >= argC) || (paIsOption(paList, valueP) == true))
    {
      REQUIRE(aP);
      break;
    }

    paFullName(aP, o, sizeof(o));

    switch (aP->type)
    {
    case PaInt:
    case PaIntU:
      *((int*) aP->varP) = (int) (int64_t) paGetVal(valueP, eP);
      if (*eP != PaOk)
      {
        return -1;
      }

      LM_T(LmtPaApVals, ("got value %d for %s", *((int*) aP->varP), aP->name));
      break;

    case PaInt64:
    case PaIntU64:
      *((int64_t*) aP->varP) = (int64_t) paGetVal(valueP, eP);
      if (*eP != PaOk)
      {
        return -1;
      }

      LM_T(LmtPaApVals, ("got value %ul for %s", *((int64_t*) aP->varP), aP->name));
      break;

    case PaChar:
    case PaCharU:
      *((char*)  aP->varP) = (char) (int64_t) paGetVal(valueP, eP);
      if (*eP != PaOk)
      {
        return -1;
      }

      LM_T(LmtPaApVals, ("got value %d for %s", *((char*) aP->varP), aP->name));
      break;

    case PaShort:
    case PaShortU:
      *((int16_t*) aP->varP) = (int16_t) (int64_t) paGetVal(valueP, eP);
      if (*eP != PaOk)
      {
        return -1;
      }

      LM_T(LmtPaApVals, ("got value %d for %s", *((int16_t*) aP->varP), aP->name));
      break;

    case PaFloat:
      *((float*) aP->varP) = baStof(valueP);
      *eP = PaOk;
      LM_T(LmtPaApVals, ("got value %f for %s", *((float*) aP->varP), aP->name));
      break;

    case PaDouble:
      *((double*) aP->varP) = baStof(valueP);
      *eP = PaOk;
      LM_T(LmtPaApVals, ("got value %f for %s", *((double*) aP->varP), aP->name));
      break;

    case PaString:
      strcpy((char*) aP->varP, valueP);
      LM_T(LmtPaApVals, ("got value '%s' for %s", (char*) aP->varP, aP->name));
      *eP = PaOk;
      break;

    case PaIList:
      LM_T(LmtPaIList, ("setting list '%s' to var %s", valueP, aP->name));
      iListFix((int*) aP->varP, valueP, eP);
      break;

    case PaSList:
      LM_T(LmtPaSList, ("setting list '%s' to var %s", valueP, aP->name));
      sListFix((char**) aP->varP, valueP, eP);
      break;

    case PaBoolean:
    case PaLastArg:
      LM_T(LmtPaApVals, ("PaList, PaBoolean, PaLastArg ..."));
      *eP = PaOk;
      break;

    default:
      LM_W(("bad type for option '%s'", aP->name));
    }

    if (*eP != PaOk)
    {
      REQUIRE(aP);
    }

    aP->used++;
    LM_V(("%s used %d times", aP->name, aP->used));
  }


  /* checking that all required arguments are set */
  paIterateInit();
  while ((aP = paIterateNext(paList)) != NULL)
  {
    if ((aP->sort == PaReq) && (aP->used == 0))
    {
      snprintf(w, sizeof(w), "%s required", aP->name);
      PA_WARNING(PasRequiredOption, w);
    }
  }

  if (extendedUsage == true)
  {
    paExtendedUsage();
    return -2;
  }

  LM_EXIT();
  return 0;
}
/* ****************************************************************************
*
* paUsage - print synopsis (to file pointer or to paResultString)
*/
void paUsage(void)
{
    char*         spacePad;
    char          string[512];
    char          s[1024];
    PaiArgument*  aP;
    int           ix       = -1;
    bool          firstUserOptionFound = false;

    LM_T(LmtPaUsage, ("presenting usage"));

    spacePad = (char*) strdup(progName);
    memset(spacePad, 0x20202020, strlen(spacePad));  /* replace progName */

    if (paUsageProgName != NULL)
    {
        snprintf(s, sizeof(s), "Usage: %s ", paUsageProgName);
    }
    else
    {
        snprintf(s, sizeof(s), "Usage: %s ", progName);
    }

    strncat(paResultString, s, sizeof(paResultString) - 1);

    // paLogOn = true;
    paIterateInit();
    PA_M(("------------- presenting usage -------------"));

    bool firstTime = true;
    while ((aP = paIterateNext(paiList)) != NULL)
    {
        char  xName[512];

        PA_M(("Got option '%s'", aP->option));

        ++ix;

        if (aP->sort == PaHid)
        {
            continue;
        }

        if ((aP->isBuiltin == true) && (aP->includeInUsage == false))
        {
            continue;
        }

        if (!firstTime)
        {
            snprintf(s, sizeof(s), "%s        ", spacePad); /* 8 spaces for "Usage:  " */
            strncat(paResultString, s, sizeof(paResultString) - 1);
        }
        firstTime = false;

        if ((aP->isBuiltin == false) && (firstUserOptionFound == false))
        {
            firstUserOptionFound = true;
            strncat(paResultString, "\n",       sizeof(paResultString) - 1 - strlen(paResultString));
            strncat(paResultString, spacePad,   sizeof(paResultString) - 1 - strlen(paResultString));
            strncat(paResultString, "        ", sizeof(paResultString) - 1 - strlen(paResultString));
        }

        if (PA_IS_OPTION(aP) && (aP->sort == PaOpt))
        {
            snprintf(xName, sizeof(xName), "[%s]", paFullName(aP, string, sizeof(string)));
        }
        else if (PA_IS_OPTION(aP) && (aP->sort == PaReq))
        {
            snprintf(xName, sizeof(xName), "%s", paFullName(aP, string, sizeof(string)));
        }
        else if (PA_IS_PARAMETER(aP) && (aP->sort == PaOpt))
        {
            snprintf(xName, sizeof(xName), "[parameter: %s]", aP->description);
        }
        else if (PA_IS_PARAMETER(aP) && (aP->sort == PaReq))
        {
            snprintf(xName, sizeof(xName), "parameter: %s", aP->description);
        }
        else
        {
            snprintf(xName, sizeof(xName), "                    ");
        }

        snprintf(s, sizeof(s), " %s\n", xName);
        strncat(paResultString, s, sizeof(paResultString) - 1);

        PA_M(("parsed arg %d", ix));
    }

    // paLogOn = false;
    free(spacePad);
    PA_M(("presenting usage"));

    printf("%s\n", paResultString);
    exit(0);
}