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.dbentity;
  
  import javax.swing.JOptionPane;
  import java.util.ArrayList;
  import java.util.Collection;
  
  import org.apache.cayenne.map.DbEntity;
  import org.apache.cayenne.map.DbRelationship;
  import org.apache.cayenne.map.ObjRelationship;
  import org.apache.cayenne.map.event.RelationshipEvent;
  import org.apache.cayenne.modeler.Application;
  import org.apache.cayenne.modeler.ProjectController;
  import org.apache.cayenne.modeler.util.CayenneTableModel;
  import org.apache.cayenne.modeler.util.ProjectUtil;
  import org.apache.cayenne.project.extension.info.ObjectInfo;
  
  /**
   * Table model for DbRelationship table.
   * 
   */
  public class DbRelationshipTableModel extends CayenneTableModel<DbRelationship> {
  
      // Columns
      static final int NAME = 0;
      static final int TARGET = 1;
      static final int TO_DEPENDENT_KEY = 2;
      static final int CARDINALITY = 3;
      static final int COMMENTS = 4;
  
      protected DbEntity entity;
  
      public DbRelationshipTableModel(DbEntity entity, ProjectController mediator,
              Object eventSource) {
  
          super(mediator, eventSource, new ArrayList<>(entity.getRelationships()));
          this.entity = entity;
      }
  
      /**
       * Returns DbRelationship class.
       */
      public Class getElementsClass() {
          return DbRelationship.class;
      }
  
      public int getColumnCount() {
          return 5;
      }
  
      public String getColumnName(int col) {
          switch (col) {
              case NAME:
                  return "Name";
              case TARGET:
                  return "Target";
              case TO_DEPENDENT_KEY:
                  return "To Dep PK";
              case CARDINALITY:
                  return "To Many";
              case COMMENTS:
                  return "Comment";
              default:
                  return null;
          }
      }
  
      public Class getColumnClass(int col) {
          switch (col) {
              case TARGET:
                  return DbEntity.class;
              case TO_DEPENDENT_KEY:
              case CARDINALITY:
                  return Boolean.class;
              default:
                  return String.class;
          }
      }
  
      public DbRelationship getRelationship(int row) {
          return (row >= 0 && row < objectList.size()) ? objectList.get(row) : null;
      }
  
      public Object getValueAt(int row, int col) {
          DbRelationship rel = getRelationship(row);
          if (rel == null) {
              return null;
          }
  
          switch (col) {
              case NAME:
                  return rel.getName();
              case TARGET:
                  return rel.getTargetEntity();
              case TO_DEPENDENT_KEY:
                  return rel.isToDependentPK() ? Boolean.TRUE : Boolean.FALSE;
              case CARDINALITY:
                  return rel.isToMany() ? Boolean.TRUE : Boolean.FALSE;
              case COMMENTS:
                  return getComment(rel);
              default:
                  return null;
          }
      }
  
      private String getComment(DbRelationship rel) {
          return ObjectInfo.getFromMetaData(mediator.getApplication().getMetaData(), rel, ObjectInfo.COMMENT);
      }
  
      private void setComment(String newVal, DbRelationship rel) {
          ObjectInfo.putToMetaData(mediator.getApplication().getMetaData(), rel, ObjectInfo.COMMENT, newVal);
      }
  
      public void setUpdatedValueAt(Object aValue, int row, int column) {
  
          DbRelationship rel = getRelationship(row);
          // If name column
          if (column == NAME) {
              RelationshipEvent e = new RelationshipEvent(eventSource, rel, entity, rel.getName());
              rel.setName((String) aValue);
              mediator.fireDbRelationshipEvent(e);
              fireTableCellUpdated(row, column);
          } else if (column == TO_DEPENDENT_KEY) {
              boolean flag = (Boolean) aValue;
  
              // make sure reverse relationship "to-dep-pk" is unset.
              if (flag) {
                  DbRelationship reverse = rel.getReverseRelationship();
                  if (reverse != null && reverse.isToDependentPK()) {
                      String message = "Unset reverse relationship's \"To Dep PK\" setting?";
                      int answer = JOptionPane.showConfirmDialog(
                              Application.getFrame(),
                              message);
                      if (answer != JOptionPane.YES_OPTION) {
                          // no action needed
                          return;
                      }
  
                      // unset reverse
                      reverse.setToDependentPK(false);
                  }
              }
  
              rel.setToDependentPK(flag);
              mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
          } else if (column == CARDINALITY) {
              rel.setToMany((Boolean) aValue);
              mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
  
              updateDependentObjRelationships(rel);
          } else if(column == COMMENTS) {
              setComment((String) aValue, rel);
              mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity));
          }
          fireTableRowsUpdated(row, row);
      }
  
      /**
       * Relationship just needs to be removed from the model. It is already removed from
       * the DataMap.
       */
      void removeRelationship(DbRelationship rel) {
          objectList.remove(rel);
          fireTableDataChanged();
      }
  
      void updateDependentObjRelationships(DbRelationship relationship) {
  
          Collection<ObjRelationship> objRelationshipsForDbRelationship = ProjectUtil
                  .findObjRelationshipsForDbRelationship(mediator, relationship);
          for(ObjRelationship objRelationship : objRelationshipsForDbRelationship) {
              objRelationship.recalculateToManyValue();
          }
      }
  
      public boolean isCellEditable(int row, int col) {
          DbRelationship rel = getRelationship(row);
          if (rel == null) {
              return false;
          } else if(col == TARGET) {
              return false;
          } else if (col == TO_DEPENDENT_KEY) {
              return rel.isValidForDepPk();
          }
          return true;
      }
  
      @Override
      public boolean isColumnSortable(int sortCol) {
          return true;
      }
  
      @Override
      public void sortByColumn(int sortCol, boolean isAscent) {
          switch (sortCol) {
              case NAME:
                  sortByElementProperty("name", isAscent);
                  break;
              case TARGET:
                  sortByElementProperty("targetEntityName", isAscent);
                  break;
              case TO_DEPENDENT_KEY:
                  sortByElementProperty("toDependentPK", isAscent);
                  break;
              case CARDINALITY:
                  sortByElementProperty("toMany", isAscent);
                  break;
          }
      }
  }
  