content: /*****************************************************************
   *   Licensed to the Apache Software Foundation (ASF) under one
   *  or more contributor license agreements.  See the NOTICE file
   *  distributed with this work for additional information
   *  regarding copyright ownership.  The ASF licenses this file
   *  to you under the Apache License, Version 2.0 (the
   *  "License"); you may not use this file except in compliance
   *  with the License.  You may obtain a copy of the License at
   *
   *    https://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing,
   *  software distributed under the License is distributed on an
   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   *  KIND, either express or implied.  See the License for the
   *  specific language governing permissions and limitations
   *  under the License.
   ****************************************************************/
  
  package org.apache.cayenne.modeler.editor;
  
  import org.apache.cayenne.configuration.event.ProcedureParameterEvent;
  import org.apache.cayenne.dba.TypesMapping;
  import org.apache.cayenne.map.Procedure;
  import org.apache.cayenne.map.ProcedureParameter;
  import org.apache.cayenne.modeler.ProjectController;
  import org.apache.cayenne.modeler.util.CayenneTableModel;
  import org.apache.cayenne.modeler.util.ProjectUtil;
  
  import javax.swing.JOptionPane;
  import java.util.ArrayList;
  
  public class ProcedureParameterTableModel extends CayenneTableModel<ProcedureParameter> {
  
      public static final int PARAMETER_NUMBER    = 0;
      public static final int PARAMETER_NAME      = 1;
      public static final int PARAMETER_DIRECTION = 2;
      public static final int PARAMETER_TYPE      = 3;
      public static final int PARAMETER_LENGTH    = 4;
      public static final int PARAMETER_PRECISION = 5;
  
      public static final String IN_PARAMETER     = "IN";
      public static final String OUT_PARAMETER    = "OUT";
      public static final String IN_OUT_PARAMETER = "INOUT";
  
      public static final String[] PARAMETER_DIRECTION_NAMES = { "", IN_PARAMETER, OUT_PARAMETER, IN_OUT_PARAMETER };
  
      private static final int[] PARAMETER_INDEXES = {
              PARAMETER_NUMBER,
              PARAMETER_NAME,
              PARAMETER_DIRECTION,
              PARAMETER_TYPE,
              PARAMETER_LENGTH,
              PARAMETER_PRECISION
      };
  
      private static final String[] PARAMETER_NAMES = { "No.", "Name", "Direction", "Type", "Max Length", "Precision" };
  
      protected Procedure procedure;
  
      public ProcedureParameterTableModel(Procedure procedure, ProjectController mediator, Object eventSource) {
          super(mediator, eventSource, new ArrayList<>(procedure.getCallParameters()));
          this.procedure = procedure;
      }
  
      /**
       * Returns procedure parameter at the specified row.
       * Returns NULL if row index is outside the valid range.
       */
      public ProcedureParameter getParameter(int row) {
          return (row >= 0 && row < objectList.size()) ? objectList.get(row) : null;
      }
  
      @Override
      public void setUpdatedValueAt(Object newVal, int rowIndex, int columnIndex) {
          ProcedureParameter parameter = getParameter(rowIndex);
          if (parameter == null) {
              return;
          }
  
          String value = (String)newVal;
          ProcedureParameterEvent event = new ProcedureParameterEvent(eventSource, parameter);
          switch (columnIndex) {
              case PARAMETER_NAME :
                  event.setOldName(parameter.getName());
                  setParameterName(value, parameter);
                  fireTableCellUpdated(rowIndex, columnIndex);
                  break;
              case PARAMETER_DIRECTION :
                  setParameterDirection(value, parameter);
                  break;
              case PARAMETER_TYPE :
                  setParameterType(value, parameter);
                  break;
              case PARAMETER_LENGTH :
                  setMaxLength(value, parameter);
                  break;
              case PARAMETER_PRECISION :
                  setPrecision(value, parameter);
                  break;
          }
          mediator.fireProcedureParameterEvent(event);
      }
  
      protected void setPrecision(String newVal, ProcedureParameter parameter) {
          if (newVal == null || newVal.trim().length() <= 0) {
              parameter.setPrecision(-1);
          } else {
              try {
                  parameter.setPrecision(Integer.parseInt(newVal));
              } catch (NumberFormatException ex) {
                  JOptionPane.showMessageDialog(
                      null,
                      "Invalid precision (" + newVal + "), only numbers are allowed.",
                      "Invalid Precision Value",
                      JOptionPane.ERROR_MESSAGE);
              }
          }
      }
  
      protected void setMaxLength(String newVal, ProcedureParameter parameter) {
          if (newVal == null || newVal.trim().length() <= 0) {
              parameter.setMaxLength(-1);
          } else {
              try {
                  parameter.setMaxLength(Integer.parseInt(newVal));
              } catch (NumberFormatException ex) {
                  JOptionPane.showMessageDialog(
                          null,
                          "Invalid Max Length (" + newVal + "), only numbers are allowed",
                          "Invalid Maximum Length",
                          JOptionPane.ERROR_MESSAGE);
              }
          }
      }
  
      protected void setParameterType(String newVal, ProcedureParameter parameter) {
          parameter.setType(TypesMapping.getSqlTypeByName(newVal));
      }
  
      protected void setParameterDirection(String direction, ProcedureParameter parameter) {
          if (ProcedureParameterTableModel.IN_PARAMETER.equals(direction)) {
              parameter.setDirection(ProcedureParameter.IN_PARAMETER);
          } else if (ProcedureParameterTableModel.OUT_PARAMETER.equals(direction)) {
              parameter.setDirection(ProcedureParameter.OUT_PARAMETER);
          } else if (ProcedureParameterTableModel.IN_OUT_PARAMETER.equals(direction)) {
              parameter.setDirection(ProcedureParameter.IN_OUT_PARAMETER);
          }
      }
  
      protected void setParameterName(String newVal, ProcedureParameter parameter) {
          ProjectUtil.setProcedureParameterName(parameter, newVal.trim());
      }
  
      @Override
      public Class getElementsClass() {
          return ProcedureParameter.class;
      }
  
      @Override
      public int getColumnCount() {
          return PARAMETER_INDEXES.length;
      }
  
      @Override
      public Object getValueAt(int rowIndex, int columnIndex) {
          ProcedureParameter parameter = getParameter(rowIndex);
  
          if (parameter == null) {
              return "";
          }
  
          switch (columnIndex) {
              case PARAMETER_NUMBER :
                  return getParameterNumber(rowIndex, parameter);
              case PARAMETER_NAME :
                  return getParameterName(parameter);
              case PARAMETER_DIRECTION :
                  return getParameterDirection(parameter);
              case PARAMETER_TYPE :
                  return getParameterType(parameter);
              case PARAMETER_LENGTH :
                  return getParameterLength(parameter);
              case PARAMETER_PRECISION :
                  return getParameterPrecision(parameter);
              default :
                  return "";
          }
      }
  
      protected String getParameterNumber(int rowIndex, ProcedureParameter parameter) {
          boolean hasReturnValue = parameter.getProcedure().isReturningValue();
  
          if (hasReturnValue) {
              return (rowIndex == 0) ? "R" : "" + rowIndex;
          } else {
              return "" + (rowIndex + 1);
          }
      }
  
      protected String getParameterPrecision(ProcedureParameter parameter) {
          return (parameter.getPrecision() >= 0)
              ? String.valueOf(parameter.getPrecision())
              : "";
      }
  
      protected String getParameterLength(ProcedureParameter parameter) {
          return (parameter.getMaxLength() >= 0)
              ? String.valueOf(parameter.getMaxLength())
              : "";
      }
  
      protected String getParameterType(ProcedureParameter parameter) {
          return TypesMapping.getSqlNameByType(parameter.getType());
      }
  
      protected String getParameterDirection(ProcedureParameter parameter) {
          int direction = parameter.getDirection();
          return PARAMETER_DIRECTION_NAMES[direction == -1 ? 0 : direction];
      }
  
      protected String getParameterName(ProcedureParameter parameter) {
          return parameter.getName();
      }
  
      @Override
      public String getColumnName(int col) {
          return PARAMETER_NAMES[col];
      }
  
      @Override
      public Class<?> getColumnClass(int col) {
          return String.class;
      }
  
      /**
       * Suppressed ordering operations defined in a superclass.
       * Since stored procedure parameters are positional,
       * no reordering is allowed.
       */
      public void orderList() {
          // NOOP
      }
  
      @Override
      public boolean isCellEditable(int row, int col) {
          return col != PARAMETER_NUMBER;
      }
  
      @Override
      public boolean isColumnSortable(int sortCol) {
          return false;
      }
  
      @Override
      public void sortByColumn(int sortCol, boolean isAscent) {
      }
  }
  