/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.ui.admin.action;

import gov.va.med.esr.common.model.lookup.SystemParameterType;
import gov.va.med.esr.common.model.system.SystemParameter;
import gov.va.med.esr.ui.ApplicationConstants.MessageKeys;
import gov.va.med.esr.ui.common.util.DateUtils;
import gov.va.med.fw.ui.struts.AbstractForm;
import gov.va.med.fw.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

/**
 * Form used to view/edit System Parameters
 * It also performs form validation
 * @author DNS   KATIKM
 *
 */
public class SystemParametersForm extends AbstractForm {

    private static final long serialVersionUID = -604038258616661348L;
    public static final String NUMERIC_REG_EXP = "^[\\d]+$";
    public static final String NO_SPCL_CHARS_REG_EXP = "^[0-9,a-z,A-Z]+$";
    public static final String CL_VISTA_ROLLOUT_REG_EXP = "^[0-9,a-z,A-Z,\\,]+$";

    private static final String[] nullableParamValues = {
        SystemParameter.AO_TREATMENT_AUTHORITY_EXP_DATE,
        SystemParameter.SWAC_TREATMENT_AUTHORITY_EXP_DATE
       };

    private List id = null;
    private List description = null;
    private List name = null;
    private List type = null;
    private List typeCode = null;
    private List length = null;
    private List unit = null;
    private List value = null;
    private List unitDescription = null;
    private List editable = null;
    private String esrVersion = null;

    public SystemParametersForm() {
        super();
        initialize();
    }

    public String getEsrVersion()
    {
        return esrVersion;
    }

    public void setEsrVersion(String esrVersion)
    {
        this.esrVersion = esrVersion;
    }

    //index based access methods
    public List getIds() {
        return id;
    }
    public String getId(int index) {
        return (String) id.get(index);
    }
    public String getDescription(int index) {
        return (String) description.get(index);
    }
    public String getType(int index) {
        return (String) type.get(index);
    }
    public String getTypeCode(int index) {
        return (String) typeCode.get(index);
    }
    public String getName(int index) {
        return (String) name.get(index);
    }
    public String getLength(int index) {
        return (String) length.get(index);
    }
    public String getUnit(int index) {
        return (String) unit.get(index);
    }
    public String getValue(int index) {
        return (String) value.get(index);
    }
    public void setId(int index, String value) {
        setElement(this.id,index,value);
    }
    public void setDescription(int index, String value) {
        setElement(this.description,index,value);
    }
    public void setType(int index, String value) {
        setElement(this.type,index,value);
    }
    public void setTypeCode(int index, String value) {
        setElement(this.typeCode,index,value);
    }
    public void setName(int index, String value) {
        setElement(this.name,index,value);
    }
    public void setLength(int index, String value) {
        setElement(this.length,index,value);
    }
    public void setUnit(int index, String value) {
        setElement(this.unit,index,value);
    }
    public void setValue(int index, String value) {
        setElement(this.value,index,value);
    }

    public List getDescriptionList() {
        return description;
    }

    public List getIdList() {
        return id;
    }

    public List getLengthList() {
        return length;
    }

    public List getNameList() {
        return name;
    }

    public List getTypeList() {
        return type;
    }

    public List getTypeCodeList() {
        return typeCode;
    }

    public List getUnitList() {
        return unit;
    }

    public List getValueList() {
        return value;
    }

    public void setDescriptionList(List description) {
        this.description = description;
    }

    public void setIdList(List id) {
        this.id = id;
    }

    public void setLengthList(List length) {
        this.length = length;
    }

    public void setNameList(List name) {
        this.name = name;
    }

    public void setTypeList(List type) {
        this.type = type;
    }

    public void setTypeCodeList(List type) {
        this.typeCode = type;
    }

    public void setUnitList(List unit) {
        this.unit = unit;
    }

    public void setValueList(List value) {
        this.value = value;
    }

    public String getUnitDescription(int index) {
        return (String) unitDescription.get(index);
    }

    public void setUnitDescription(int index, String value) {
        setElement(this.unitDescription,index,value);
    }

    public List getUnitDescriptionList() {
        return unitDescription;
    }

    public void setUnitDescriptionList(List unitDescription) {
        this.unitDescription = unitDescription;
    }

    public Boolean getEditable(int index) {
        return (Boolean) editable.get(index);
    }

    public void setEditable(int index, Boolean value) {
        setElement(this.editable,index,value);
    }

    public List getEditableList() {
        return editable;
    }

    public void setEditableList(List editable) {
        this.editable = editable;
    }
    public boolean isNoData()
    {
        return ((id == null) || (id.size() == 0));
    }
    /**
     * Resets all the form data to null.
     */
    public void reset(ActionMapping mapping, HttpServletRequest request)
    {
        super.reset(mapping, request);
        initialize();
    }

    /**
     * Adds systemparameter to the form
     * @param sysParameter
     */
    public void add(SystemParameter sysParameter, Boolean editable) {
        id.add(sysParameter.getEntityKey() == null ? "" : sysParameter.getEntityKey().getKeyValueAsString());
        description.add(sysParameter.getDescription());
        name.add(sysParameter.getName());
        typeCode.add(sysParameter.getType() == null ? "" : sysParameter.getType().getCode());
        type.add(sysParameter.getType() == null ? "" : sysParameter.getType().getDescription());
        value.add(sysParameter.getValue());
        unit.add(sysParameter.getUnit() == null ? "" : sysParameter.getUnit().getCode());
        unitDescription.add(sysParameter.getUnit() == null ? "" : sysParameter.getUnit().getDescription());
        length.add(sysParameter.getDataLength()==null ? "" : sysParameter.getDataLength().toString());
        this.editable.add(editable);
    }

    /**
     * Validates form data after submission
     * To highligh the system parameter name, parameter name is passed as field name
     */
    public ActionMessages validateForm(ActionMapping mapping, HttpServletRequest request)
    {
        // Get the list of existing messages and resources
        ActionMessages messages = getActionMessages(request);

        List sysParameters = getValueList();
        List sysParameterUnitList = getUnitList();

        for (int i=0; i<sysParameters.size(); i++) {

           // CCR9936 -- if value is not required, skip validation
           if (!isRequired(getName(i),getValue(i)))
           continue;

           //Validate system parameter value/type/length
           String parameterValue = getValue(i);
           String parameterType=getUnit(i);
            if ((StringUtils.isEmpty(parameterValue) || parameterValue.trim().length() == 0)) {
                //required error
                messages.add(getName(i),
                new ActionMessage(MessageKeys.ERRORS_VALUE_IS_REQUIRED, getName(i)));
                continue;
            }

            String trimmedValue = parameterValue.trim();
            int length = Integer.parseInt(getLength(i));
            if (length < trimmedValue.length()) {
                //maximum allowed length error
                messages.add(getName(i),
                        new ActionMessage(MessageKeys.ERRORS_MAXLENGTH, getName(i),getLength(i)));
                continue;
            }

            if(SystemParameter.DATE_UNIT.equalsIgnoreCase(parameterType)){
            	Date date = null;
                try {
                    date = DateUtils.getDate(trimmedValue);
                }catch (Exception e){}
                if (date == null){
                    messages.add(getName(i),
                            new ActionMessage(MessageKeys.ERRORS_DATE, getName(i)));
                    continue;
                }
            }

            else if (SystemParameter.ESR_IMPLEMENTATION_DATE.equals(getName(i))) {
                Date date = null;
                try {
                    date = DateUtils.getDate(trimmedValue);
                }catch (Exception e){}
                if (date == null){
                    messages.add(getName(i),
                            new ActionMessage(MessageKeys.ERRORS_DATE, getName(i)));
                    continue;
                }
            }
            else if (SystemParameter.CL_VISTA_ROLLOUT_INDICATOR.equals(getName(i)) && !trimmedValue.matches(CL_VISTA_ROLLOUT_REG_EXP)) {
                //validate the value for CL_VISTA_ROLLOUT_INDICATOR  site station numbers separated by comma
            	 messages.add(getName(i), new ActionMessage(MessageKeys.ERRORS_CL_VISTA_ROLLOUT, getName(i)));
                 continue;
              }

            //check for special characters if any
            else if (!trimmedValue.matches(NO_SPCL_CHARS_REG_EXP)) {
                messages.add(getName(i),
                        new ActionMessage(MessageKeys.ERRORS_SPCL_CHARS_NOT_ALLOWED, getName(i)));
                continue;
            }

            //check for numeric value
            if (SystemParameterType.CODE_NUMERIC.getName().equals(getTypeCode(i)) &&
                    !trimmedValue.matches(NUMERIC_REG_EXP)) {
                //validate the value for numeric
                messages.add(getName(i), new ActionMessage(MessageKeys.ERRORS_NUMERIC, getName(i)));
                continue;
            }

            //validate cut off date to MMDD
            if (SystemParameter.IVM_DM_IY_CUTOFF_DATE.equals(getName(i))) {
                //Min length 4 Maximum Length 4
                if (trimmedValue.length() < 4){
                    messages.add(getName(i),new ActionMessage(MessageKeys.ERRORS_MINLENGTH, getName(i),"4"));
                }
                //Validate partial date for numeric values
                else if (!trimmedValue.matches(NUMERIC_REG_EXP) || !isValidPartialDate(trimmedValue)){
                    messages.add(getName(i), new ActionMessage(MessageKeys.ERRORS_PARTIAL_DATE, getName(i),trimmedValue));
                }
            }
            //Validate system parameter units (required) only for SSA_SSN_VERIFICATION_FREQUENCY
            //Others are read only or does not require units
            else if (SystemParameter.SSA_SSN_VERIFICATION_FREQUENCY.equals(getName(i))){
                if (StringUtils.isEmpty((String)sysParameterUnitList.get(i))) {
                    messages.add(getName(i),
                            new ActionMessage(MessageKeys.ERRORS_UNIT_IS_REQUIRED, getName(i)));
                }
            }
        }

        //Return the updated Action Messages
        return messages;
    }

    private boolean isValidPartialDate(String mmdd){
        String dateString =
            mmdd.substring(0,2)+ "/" + mmdd.substring(2) + "/" + String.valueOf(DateUtils.getCurrentYear());
        Date date = null;
        try {
             date = DateUtils.getDate(dateString);
        }catch (Exception e){
            //ignore exception
        }
        return date == null ? false : true;
    }

    /**
     * Initialize the form and Create initial arrays for all lists
     */
    private void initialize() {
        id = new ArrayList ();
        description = new ArrayList ();
        name = new ArrayList ();
        type = new ArrayList ();
        typeCode = new ArrayList ();
        length = new ArrayList ();
        unit = new ArrayList ();
        value = new ArrayList ();
        unitDescription = new ArrayList ();
        editable = new ArrayList ();
        esrVersion = null;
    }

    private boolean isRequired(String parameterValue, String incomingValue)
    {
      for (int i=0; i<nullableParamValues.length; i++) {
        if (nullableParamValues[i].equals(parameterValue)) {
        	if(incomingValue != null && !incomingValue.equals("")){
        		return true;
        	}
        	else{
        		return false;
        	}
        }
      }
      return true;
    }

    private boolean isRequired(String parameterValue)
    {
      for (int i=0; i<nullableParamValues.length; i++) {
        if (nullableParamValues[i].equals(parameterValue)) {
          return false;
        }
      }
      return true;
    }


}
