/*
*         OpenPBS (Portable Batch System) v2.3 Software License
*
* Copyright (c) 1999-2000 Veridian Information Solutions, Inc.
* All rights reserved.
*
* ---------------------------------------------------------------------------
* For a license to use or redistribute the OpenPBS software under conditions
* other than those described below, or to purchase support for this software,
* please contact Veridian Systems, PBS Products Department ("Licensor") at:
*
*    www.OpenPBS.org  +1 650 967-4675                  sales@OpenPBS.org
*                        877 902-4PBS (US toll-free)
* ---------------------------------------------------------------------------
*
* This license covers use of the OpenPBS v2.3 software (the "Software") at
* your site or location, and, for certain users, redistribution of the
* Software to other sites and locations.  Use and redistribution of
* OpenPBS v2.3 in source and binary forms, with or without modification,
* are permitted provided that all of the following conditions are met.
* After December 31, 2001, only conditions 3-6 must be met:
*
* 1. Commercial and/or non-commercial use of the Software is permitted
*    provided a current software registration is on file at www.OpenPBS.org.
*    If use of this software contributes to a publication, product, or
*    service, proper attribution must be given; see www.OpenPBS.org/credit.html
*
* 2. Redistribution in any form is only permitted for non-commercial,
*    non-profit purposes.  There can be no charge for the Software or any
*    software incorporating the Software.  Further, there can be no
*    expectation of revenue generated as a consequence of redistributing
*    the Software.
*
* 3. Any Redistribution of source code must retain the above copyright notice
*    and the acknowledgment contained in paragraph 6, this list of conditions
*    and the disclaimer contained in paragraph 7.
*
* 4. Any Redistribution in binary form must reproduce the above copyright
*    notice and the acknowledgment contained in paragraph 6, this list of
*    conditions and the disclaimer contained in paragraph 7 in the
*    documentation and/or other materials provided with the distribution.
*
* 5. Redistributions in any form must be accompanied by information on how to
*    obtain complete source code for the OpenPBS software and any
*    modifications and/or additions to the OpenPBS software.  The source code
*    must either be included in the distribution or be available for no more
*    than the cost of distribution plus a nominal fee, and all modifications
*    and additions to the Software must be freely redistributable by any party
*    (including Licensor) without restriction.
*
* 6. All advertising materials mentioning features or use of the Software must
*    display the following acknowledgment:
*
*     "This product includes software developed by NASA Ames Research Center,
*     Lawrence Livermore National Laboratory, and Veridian Information
*     Solutions, Inc.
*     Visit www.OpenPBS.org for OpenPBS software support,
*     products, and information."
*
* 7. DISCLAIMER OF WARRANTY
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT
* ARE EXPRESSLY DISCLAIMED.
*
* IN NO EVENT SHALL VERIDIAN CORPORATION, ITS AFFILIATED COMPANIES, OR THE
* U.S. GOVERNMENT OR ANY OF ITS AGENCIES BE LIABLE FOR ANY DIRECT OR INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This license will be governed by the laws of the Commonwealth of Virginia,
* without reference to its choice of law rules.
*/



//#include <pbs_config.h>   /* the master config generated by configure */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
#include "pbs_ifl.h"
*/

#include "pbs_error.h"
#include "attribute.h"
#include "attr_req_info.hpp"
#include "pbs_helper.h"

/*
 * decode_attr_req_info()
 *
 * saves the val to the min resource of the complete_req for a queue or server attribute
 *
 * @param patr  - the attribute that should have its req_info set
 * @param name  - name of complete_req limit options
 * @param rescn - name of resource to limit
 * @param val   - limit value
 * @param perm  - permissions, ignored
 *
 * @return PBSE_NONE if the attribute was successfully decoded, or a pbs error code
 */

int  decode_attr_req_info(
    
  pbs_attribute *patr,
  const char    *name,
  const char    *rescn,
  const char    *val,
  int            UNUSED(perm))

  {
  int rc = PBSE_NONE;

  if ((patr == NULL) || (val == NULL) || (name == NULL) || (rescn == NULL))
    return(PBSE_BAD_PARAMETER);

  attr_req_info *cr;

  /* Check to see if there is a value already assigned to patr */
  if ((patr->at_val.at_ptr != NULL) &&
      ((patr->at_flags & ATR_VFLAG_SET) != 0))
    {
    cr = (attr_req_info *)patr->at_val.at_ptr;
    }
  else
    {
    /* No value assigned to patr. This is the first time. Create a new req */
    cr = new attr_req_info();
    patr->at_val.at_ptr = cr;
    }

  if (!strcmp(ATTR_req_infomin, name))
    cr->set_min_limit_value(rescn, val);
  else if (!strcmp(ATTR_req_infomax, name))
    cr->set_max_limit_value(rescn, val);
  else if (!strcmp(ATTR_req_infodefault, name))
    cr->set_default_limit_value(rescn, val);
  else
    {
    delete cr;
    patr->at_val.at_ptr = NULL;
    return(PBSE_BAD_PARAMETER);
    }

  patr->at_flags |= ATR_VFLAG_SET;
  return(rc);
  } // END decode_attr_req_info()

/*
 * encode_attr_req_info()
 *
 * encodes attr's attr_req_info into the list that is phead
 *
 * @param attr   - the attribute which holds a attr_req_info
 * @param phead  - the list where we should encode attr
 * @param atname - the name of the attribute
 * @param rsname - the name of the resource (unused here)
 * @param mode   - the mode (unused here)
 * @param perm   - permissions (unused here)
 * @return PBSE_NONE on success or a pbs error code
 */

int encode_attr_req_info(

  pbs_attribute *attr,
  tlist_head    *phead,
  const char    *atname,
  const char    *UNUSED(rsname),
  int            mode,
  int            perm)

  {
  // if the attribute is empty then nothing should be done
  if ((attr == NULL) ||
      (attr->at_val.at_ptr == NULL))
    return(PBSE_NONE);

  if (atname == NULL)
    return(PBSE_BAD_PARAMETER);


  std::vector<std::string> names;
  std::vector<std::string> values;
  attr_req_info            *ari;
  pbs_attribute            temp;
  int                      rc = PBSE_NONE;

  ari = (attr_req_info *)attr->at_val.at_ptr;

  if (!strcmp(ATTR_req_infomin, atname))
    ari->get_min_values(names, values);
  else if (!strcmp(ATTR_req_infomax, atname))
    ari->get_max_values(names, values);
  else if (!strcmp(ATTR_req_infodefault, atname))
    ari->get_default_values(names, values);
  else
    {
    /* something's not right */
    return(PBSE_BAD_PARAMETER);
    }


  temp.at_flags = ATR_VFLAG_SET;

  for (unsigned int i = 0; i < names.size(); i++)
    {
    temp.at_val.at_str = (char *)values[i].c_str();
    if (( rc = encode_str(&temp, phead, atname, names[i].c_str(), mode, perm )) < 0)
      break;
    }

  return(rc);
  }


void overwrite_attr_req_info(

  pbs_attribute *attr,
  pbs_attribute *new_attr)

  {
  attr_req_info *to_copy = (attr_req_info *)new_attr->at_val.at_ptr;

  if (attr->at_val.at_ptr == NULL)
    {
    attr->at_val.at_ptr = new attr_req_info(*to_copy);
    }
  else
    {
    attr_req_info *cr = (attr_req_info *)attr->at_val.at_ptr;
    *cr = *to_copy;
    attr->at_val.at_ptr = cr;
    }

  attr->at_flags |= ATR_VFLAG_SET;
  } // END overwrite_attr_req_info


/*
 * set_attr_req_info()
 *
 * sets the attribute attr with the value from new_attr
 * @param attr - the attribute being set
 * @param new_attr - the attribute whose value is set in attr
 * @param op - the operation being performed. Right now, only SET and INCR work. INCR only
 * works if attr has no value
 *
 * @return PBSE_NONE on success, or PBSE_INTERNAL on unsupported operations.
 */

int set_attr_req_info(

  pbs_attribute *attr,
  pbs_attribute *new_attr,
  enum batch_op  op)

  {

  if (attr == NULL) 
    return(PBSE_BAD_PARAMETER);

  if ((op != UNSET) && (new_attr == NULL))
    return(PBSE_BAD_PARAMETER);


  if ((attr->at_flags & ATR_VFLAG_SET)
      && (attr->at_val.at_ptr == NULL))
    {
    attr->at_flags &= ~ATR_VFLAG_SET;
    return(PBSE_NONE);
    }

  switch (op)
    {
    case SET:
      {
      if (new_attr->at_val.at_ptr == NULL)
        {
        new_attr->at_flags &= ~ATR_VFLAG_SET;
        return(PBSE_NONE);
        }


      if (attr->at_flags & ATR_VFLAG_SET)
        {
        /* add the new parameters to the exiting parameters */
        std::vector<std::string> min_names, max_names, default_names;
        std::vector<std::string> min_values, max_values, default_values;
        attr_req_info *new_req_info = (attr_req_info *)new_attr->at_val.at_ptr;
        attr_req_info *old_req_info = (attr_req_info *)attr->at_val.at_ptr;
        
        new_req_info->get_max_values(max_names, max_values);
        new_req_info->get_min_values(min_names, min_values);
        new_req_info->get_default_values(default_names, default_values);

        for (unsigned int i = 0; i < max_names.size(); i++)
          {
          old_req_info->set_max_limit_value(max_names[i].c_str(), max_values[i].c_str());
          }

        for (unsigned int i = 0; i < min_names.size(); i++)
          {
          old_req_info->set_min_limit_value(min_names[i].c_str(), min_values[i].c_str());
          }

        for (unsigned int i = 0; i < default_names.size(); i++)
          {
          old_req_info->set_default_limit_value(default_names[i].c_str(), default_values[i].c_str());
          }
        attr->at_flags |= ATR_VFLAG_MODIFY;
        }
      else
        {
        overwrite_attr_req_info(attr, new_attr);
        attr->at_flags |= ATR_VFLAG_SET | ATR_VFLAG_MODIFY;
        }

      break;
      }

    case UNSET:

      free_attr_req_info(attr);
      break;

    default:

      // unsupported
      return(PBSE_INTERNAL);
    }

  return(PBSE_NONE);
  } // END set_attr_req_info()


void free_attr_req_info(

  pbs_attribute *patr)

  {
  if (patr->at_val.at_ptr != NULL)
    {
    attr_req_info *delete_me = (attr_req_info *)patr->at_val.at_ptr;

    delete delete_me;
    patr->at_val.at_ptr = NULL;
    }

  patr->at_flags &= ~ATR_VFLAG_SET;

  } /* free_attr_req_info */
 
