private void updateCategory() throws Exception {
   int id = 0;
   for (LabelGroup group : labelGroups) {
     CCategory groupCategory = null;
     for (CLabel label : group.labels) {
       CCategory labelCategory = label.getCategory();
       if (null == groupCategory && null != labelCategory) {
         groupCategory = labelCategory;
       }
       if (null != groupCategory && !labelCategory.equals(groupCategory)) {
         // TODO generating an exception or warning
         throw new Exception(
             String.format(
                 "Labels in the same group are belong more than one categories: \"%s\" and \"%s\"",
                 groupCategory.getName(), labelCategory.getName()));
       }
     }
     if (null == groupCategory) {
       id++;
       try {
         category = getOwner().getLocalCategoryBox().newCategory(GROUP_FIELD_NAME + id);
       } catch (Exception e) {
         // TODO is it possible?
         e.printStackTrace();
       }
     }
     for (CLabel label : group.labels) {
       label.setCategory(category);
     }
   }
 }
  private void initLabelGroups() {
    if (labelPairs.size() == 0) return;

    List<LabelPair> tempPairs = new ArrayList(labelPairs.size());
    tempPairs.addAll(labelPairs);

    Stack<CLabel> groupStack = new Stack<CLabel>();
    List<LabelPair> trash = new ArrayList<LabelPair>();

    while (tempPairs.size() > 0) {
      LabelPair pair0 = tempPairs.get(0);
      LabelGroup group = newLabelGroup();

      group.addLabel(pair0.label1);
      group.addLabel(pair0.label2);

      groupStack.push(pair0.label1);
      groupStack.push(pair0.label2);

      tempPairs.remove(0);

      while (!groupStack.empty()) {
        CLabel groupedLabel = groupStack.pop();
        Iterator<LabelPair> pairs = tempPairs.iterator();

        while (pairs.hasNext()) {
          LabelPair pair = pairs.next();

          CLabel candidate =
              groupedLabel.equals(pair.label1)
                  ? pair.label2
                  : groupedLabel.equals(pair.label2) ? pair.label1 : null;

          if (null == candidate) continue;

          if (!groupStack.contains(candidate)) {
            groupStack.push(candidate);
            group.labels.add(candidate);
          }
          trash.add(pair);
          pairs.remove();
        }
      }
      tempPairs.removeAll(trash);
      trash.clear();
    }
  }
 @Override
 public int hashCode() {
   int result = label1 != null ? label1.hashCode() : 0;
   result += label2 != null ? label2.hashCode() : 0;
   return result;
 }