/**
   * 키 컬럼의의 조건을 relational type을 분석합니다.
   *
   * <p>상대방 컬럼이 NULL을 허용하면 자신은 없을수도 있음.
   *
   * @param soCol source table
   * @rapap taCol target table
   * @return
   */
  public static RelationKind calcRelationCol(Column soCol, Column taCol) {
    if ("YES".equals(taCol.getNull()) || "YES".equals(soCol.getNull())) {

      if (PublicTadpoleDefine.isPK(soCol.getKey())) return RelationKind.ZERO_OR_ONE;
      else return RelationKind.ZERO_OR_MANY;

    } else {

      if (PublicTadpoleDefine.isPK(soCol.getKey())) return RelationKind.ONLY_ONE;
      else return RelationKind.ONE_OR_MANY;
    }
  }
  @Override
  protected void handleDrop() {
    String[] arrayDragSourceData = null;
    try {
      arrayDragSourceData =
          StringUtils.splitByWholeSeparator(
              ((String) getCurrentEvent().data), PublicTadpoleDefine.DELIMITER);

      int sourceDBSeq = Integer.parseInt(arrayDragSourceData[0]);
      if (userDB.getSeq() != sourceDBSeq) {
        MessageDialog.openError(
            null, "Error", Messages.TableTransferDropTargetListener_1); // $NON-NLS-1$
        return;
      }
    } catch (Exception e) {
      logger.error("dragger error", e); // $NON-NLS-1$
      MessageDialog.openError(
          null, "Error", "Draging exception : " + e.getMessage()); // $NON-NLS-1$
      return;
    }

    String tableName = arrayDragSourceData[1];
    String refTableNames = "'" + tableName + "',"; // $NON-NLS-1$ //$NON-NLS-2$

    // 이미 editor 상에 테이블 정보를 가져온다.
    Map<String, Table> mapDBTables = new HashMap<String, Table>();
    for (Table table : db.getTables()) {
      mapDBTables.put(table.getName(), table);
      refTableNames += "'" + table.getName() + "',"; // $NON-NLS-1$ //$NON-NLS-2$
    }
    refTableNames = StringUtils.chompLast(refTableNames, ","); // $NON-NLS-1$

    // 이미 등록되어 있는 것이 아니라면
    if (mapDBTables.get(tableName) == null) {
      // 테이블 모델 생성
      Table tableModel = tadpoleFactory.createTable();
      tableModel.setName(tableName);
      tableModel.setDb(db);

      if (userDB.getDBDefine() == DBDefine.SQLite_DEFAULT) {
        tableModel.setComment("");
      } else {
        String tableComment = arrayDragSourceData[2];
        tableComment = StringUtils.substring("" + tableComment, 0, 10);
        tableModel.setComment(tableComment);
      }

      tableModel.setConstraints(new Rectangle(getDropLocation().x, getDropLocation().y, -1, -1));

      try {
        // 컬럼 모델 생성
        for (TableColumnDAO columnDAO : getColumns(tableName)) {
          Column column = tadpoleFactory.createColumn();

          column.setDefault(columnDAO.getDefault());
          column.setExtra(columnDAO.getExtra());
          column.setField(columnDAO.getField());
          column.setNull(columnDAO.getNull());
          column.setKey(columnDAO.getKey());
          column.setType(columnDAO.getType());

          String strComment = columnDAO.getComment();
          if (strComment == null) strComment = "";
          else strComment = StringUtils.substring("" + strComment, 0, 10);
          column.setComment(strComment);

          column.setTable(tableModel);
          tableModel.getColumns().add(column);
        }
        mapDBTables.put(tableName, tableModel);
        RelationUtil.calRelation(
            userDB,
            mapDBTables,
            db,
            refTableNames); // RelationUtil.getReferenceTable(userDB, refTableNames));

      } catch (Exception e) {
        logger.error("GEF Table Drag and Drop Exception", e); // $NON-NLS-1$

        Status errStatus =
            new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e); // $NON-NLS-1$
        ExceptionDetailsErrorDialog.openError(
            PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
            "Error",
            Messages.TadpoleModelUtils_2,
            errStatus); //$NON-NLS-1$
      }

      transferFactory.setTable(tableModel);
    } else {
      transferFactory.setTable(mapDBTables.get(tableName));
    }

    super.handleDrop();
  }
  /**
   * 테이블 관계를 구성합니다.
   *
   * @param userDB
   * @param mapDBTables
   * @param db
   * @throws Exception
   */
  public static void calRelation(
      UserDBDAO userDB,
      Map<String, Table> mapDBTables,
      DB db,
      List<ReferencedTableDAO> referenceTableList)
      throws Exception {

    RdbFactory tadpoleFactory = RdbFactory.eINSTANCE;

    // 디비에서 관계 정보를 찾아서 넣어준다.
    for (ReferencedTableDAO refTabDAO : referenceTableList) {
      Table soTabMod = mapDBTables.get(refTabDAO.getTable_name());
      Table tarTabMod = mapDBTables.get(refTabDAO.getReferenced_table_name());

      // 소스테이블에 인덱스가 없고, 타겟 테이블이 있으면 추가한다.
      if (soTabMod != null && tarTabMod != null) {

        // 이미 추가된 relation인지 검사합니다.
        boolean isAlrealyAppend = false;
        for (Relation relation : soTabMod.getOutgoingLinks()) {

          if (relation.getConstraint_name() != null && refTabDAO.getConstraint_name() != null) {
            if (relation.getConstraint_name().equals(refTabDAO.getConstraint_name())) {
              isAlrealyAppend = true;
              break;
            }
          }
        }
        for (Relation relation : soTabMod.getIncomingLinks()) {

          if (relation.getConstraint_name() != null && refTabDAO.getConstraint_name() != null) {
            if (relation.getConstraint_name().equals(refTabDAO.getConstraint_name())) {
              isAlrealyAppend = true;
              break;
            }
          }
        }

        // TODO 현재 자신의 테이블을 키로 가자고 있는 항목은 다음과 같은 이유로 제거 합니다.
        // java.lang.RuntimeException: Cycle detected in graph
        if (refTabDAO.getTable_name().equals(refTabDAO.getReferenced_table_name())) continue;

        // 이미 추가 되어 있는가?
        if (isAlrealyAppend) continue;

        // 새롭게 추가될 요소 이면.
        Relation relation = tadpoleFactory.createRelation();
        /* 저장시 아래와 같은 오류가 발생하여 추가한 코드
         * 여유를 가지고 디버깅을 해봐야 하는코드
         *
         * org.eclipse.emf.ecore.resource.Resource$IOWrappedException:
         * The object 'com.hangum.tadpole.model.impl.RelationImpl@5e44efa0 (source_kind: ONLY_ONE, target_kind: ONE_MANY, column_name: country_id, referenced_column_name: country_id, bendpoint: [], constraint_name: null)'
         * is not contained in a resource.
         */
        relation.setDb(db);

        relation.setConstraint_name(refTabDAO.getConstraint_name());

        relation.setColumn_name(refTabDAO.getColumn_name());
        relation.setReferenced_column_name(refTabDAO.getReferenced_column_name());

        /*
         * 위의 경우의 수를 이용하여 릴레이션을 생성합니다.
         */
        Map<String, Column> sourceColumnsMap = new HashMap<String, Column>();
        Map<String, Column> targetColumnMap = new HashMap<String, Column>();
        for (Column column : soTabMod.getColumns()) sourceColumnsMap.put(column.getField(), column);
        for (Column column : tarTabMod.getColumns()) targetColumnMap.put(column.getField(), column);

        // source 컬럼 정보
        Column col = sourceColumnsMap.get(refTabDAO.getColumn_name());

        // target 컬럼 정보
        Column colR = targetColumnMap.get(refTabDAO.getReferenced_column_name());
        if (logger.isDebugEnabled()) {
          if (col == null || colR == null) {
            logger.debug(
                "###[table index]###############################################################################");
            logger.debug(db.getUrl() + ":" + refTabDAO.toString());
            logger.debug(
                "###[table index]###############################################################################");
          }
        }
        if (col == null || colR == null) continue;

        //				logger.debug("\t [source ]" + col.getField() + " [key]" + col.getKey());
        //				logger.debug("\t [target ]" + colR.getField() + " [key]" + colR.getKey());
        relation.setSource_kind(calcRelationCol(col, colR));
        relation.setTarget_kind(calcRelationCol(colR, col));

        // 관계형성
        soTabMod.getIncomingLinks().add(relation);
        tarTabMod.getOutgoingLinks().add(relation);

        relation.setSource(soTabMod);
        relation.setTarget(tarTabMod);
      } // if(souceModel != null && targetModel != null
    } // for
  }