@Override
  public boolean equals(Object object) {
    if (object instanceof RelationSchema) {
      RelationSchema otherSchema = (RelationSchema) object;

      if (!name.equals(otherSchema.getName())) {
        return false;
      }

      if (!attributes.equals(otherSchema.getAttributes())) {
        return false;
      }

      if (!functionalDependencies.equals(otherSchema.getFunctionalDependencies())) {
        return false;
      }
    }

    return true;
  }
  public NormalizationResult normalize(
      RelationSchema relationToNormalize, NormalForm actualNF, NormalForm targetNF) {
    RelationSchema relation = relationToNormalize.getClone();
    RelationSchema backupRelation;

    NormalizationResult result;

    // Pick up lonely Attributes (in no Functional dependency)
    RelationUtils.getInstance().determineAllAttributes(relation);

    // Set primary-key if not present
    if (RelationUtils.getInstance().getPrimaryKey(relation).getAttributes().isEmpty()) {
      Key newPrimaryKey = RelationUtils.getInstance().getKey(relation);
      for (Attribute attribute : relation.getAttributes()) {
        if (newPrimaryKey.getAttributes().contains(attribute)) {
          attribute.setIsPrimaryKey(true);
        }
      }
    }

    backupRelation = relation.getClone();

    normalizationProcedures.clear();
    switch (actualNF) {
      case FIRST:
        switch (targetNF) {
          case SECOND:
            // 1.NF ==> 2.NF
            normalizationProcedures.add(new DecompositionTo2NF());

            break;
          case THIRD:
            // 1.NF ==> 3.NF
            normalizationProcedures.add(new SyntheseTo3NF());
            break;
          case BOYCECODD:
            // 1.NF ==> BCNF
            normalizationProcedures.add(new SyntheseTo3NF());
            normalizationProcedures.add(new DecompositionToBCNF());
            break;
          default:
            throw new IllegalArgumentException();
        }
        break;
      case SECOND:
        switch (targetNF) {
          case THIRD:
            // 2.NF ==> 3.NF
            normalizationProcedures.add(new SyntheseTo3NF());
            break;
          case BOYCECODD:
            // 2.NF ==> BCNF
            normalizationProcedures.add(new SyntheseTo3NF());
            normalizationProcedures.add(new DecompositionToBCNF());
            break;
          default:
            throw new IllegalArgumentException();
        }
        break;
      case THIRD:
        // 3.NF ==> BCNF
        normalizationProcedures.add(new DecompositionToBCNF());
        break;
      default:
        throw new IllegalArgumentException();
    }

    result = startNormalizing(relation, normalizationProcedures, targetNF);

    if (result.getRelations().isEmpty()) {
      result.getRelations().add(backupRelation);
    }

    return result;
  }