/**
   * Imports the dialect variant words into a map of the dialect to the dialect variant word. Checks
   * to see if the map is empty before loading, and will only load the words if the map is found to
   * be empty.
   *
   * @param dialectOrLanguageNid the dialect or language nid
   * @throws UnsupportedDialectOrLanguage indicates an unsupported dialect or language
   * @throws IOException signals that an I/O exception has occurred
   */
  private static void lazyInit(int dialectOrLanguageNid)
      throws UnsupportedDialectOrLanguage, IOException {
    if (variantMap == null) {
      initLock.lock();
      try {
        if (variantMap == null) {
          HashMap<Integer, Map<String, String>> initialVariantMap =
              new HashMap<Integer, Map<String, String>>();
          variantSetMap = new HashMap<Integer, Set<String>>();
          ViewCoordinate vc = AppContext.getService(TerminologyStoreDI.class).getMetadataVC();
          TerminologySnapshotDI ts =
              AppContext.getService(TerminologyStoreDI.class).getSnapshot(vc);

          ConceptVersionBI enVariantTextRefsetC =
              Language.EN_VARIANT_TEXT.getStrict(
                  AppContext.getService(TerminologyStoreDI.class).getMetadataVC());
          Collection<? extends RefexChronicleBI<?>> enVariants = enVariantTextRefsetC.getRefexes();
          Set<String> variantSet = new HashSet<String>();
          for (RefexChronicleBI<?> refex : enVariants) {
            if (RefexStringVersionBI.class.isAssignableFrom(refex.getClass())) {
              RefexStringVersionBI<?> variantText = (RefexStringVersionBI<?>) refex.getVersion(vc);
              if (variantText != null) {
                variantSet.add(variantText.getString1());
              }
            }
          }
          variantSetMap.put(Language.EN.getStrict(vc).getNid(), variantSet);

          addDialect(Language.EN_AU, vc, Language.EN_AU_TEXT_VARIANTS, ts, initialVariantMap);
          addDialect(Language.EN_CA, vc, Language.EN_CA_TEXT_VARIANTS, ts, initialVariantMap);
          addDialect(Language.EN_NZ, vc, Language.EN_NZ_TEXT_VARIANTS, ts, initialVariantMap);
          addDialect(Language.EN_UK, vc, Language.EN_UK_TEXT_VARIANTS, ts, initialVariantMap);
          addDialect(Language.EN_US, vc, Language.EN_US_TEXT_VARIANTS, ts, initialVariantMap);
          DialectHelper.variantMap = initialVariantMap;
        }
      } catch (ContradictionException ex) {
        throw new IOException(ex);
      } finally {
        initLock.unlock();
      }
    }
    if (!variantMap.containsKey(dialectOrLanguageNid)
        && !variantSetMap.containsKey(dialectOrLanguageNid)) {
      throw new UnsupportedDialectOrLanguage("nid: " + dialectOrLanguageNid);
    }
  }
  private ComponentWorkflowServiceI getWorkflowService() {
    if (workflowService == null) {
      workflowService = AppContext.getService(ComponentWorkflowServiceI.class);
    }

    assert workflowService != null;

    return workflowService;
  }
  /**
   * Gets a description spec representing the <code>description</code> in the dialect specified by
   * the <code>dialectNid</code>.
   *
   * @param description the description to represent
   * @param dialectNid specifying the dialect of the description spec
   * @param viewCoordinate specifying which version of the description to use
   * @return the generated description spec for the specified dialect
   * @throws UnsupportedDialectOrLanguage indicates an unsupported dialect or language
   * @throws IOException signals that an I/O exception has occurred
   */
  public static DescriptionSpec getDescriptionSpecForDialect(
      DescriptionVersionBI<?> description, int dialectNid, ViewCoordinate viewCoordinate)
      throws UnsupportedDialectOrLanguage, IOException {
    try {
      lazyInit(dialectNid);
      String variantText = makeTextForDialect(description.getText(), dialectNid);

      UUID descUuid =
          UuidT5Generator.getDescUuid(
              description.getText(),
              AppContext.getService(TerminologyStoreDI.class)
                  .getConcept(dialectNid)
                  .getPrimordialUuid(),
              AppContext.getService(TerminologyStoreDI.class)
                  .getConcept(description.getConceptNid())
                  .getPrimordialUuid());

      DescriptionSpec ds =
          new DescriptionSpec(
              new UUID[] {descUuid},
              SpecFactory.get(
                  AppContext.getService(TerminologyStoreDI.class)
                      .getConcept(description.getConceptNid()),
                  viewCoordinate),
              SpecFactory.get(
                  AppContext.getService(TerminologyStoreDI.class)
                      .getConcept(description.getTypeNid()),
                  viewCoordinate),
              variantText);
      ds.setLangText(description.getLang());
      return ds;
    } catch (NoSuchAlgorithmException ex) {
      throw new IOException(ex);
    } catch (UnsupportedEncodingException ex) {
      throw new IOException(ex);
    }
  }
 /**
  * Checks if the enclosing concept of the given <code>description</code> is has any descriptions
  * in the specified dialect, <code>dialectNid</code>. Uses the given <code>viewCoordinate</code>
  * to determine which version of the descriptions to use.
  *
  * @param description the description containing the text to check
  * @param dialectNid the dialect nid specifying the desired dialect
  * @param viewCoordinate the view coordinate specifying which version of the description to use
  * @return <code>true</code>, if no description is found in the specified dialect
  * @throws IOException signals that an I/O exception has occurred
  * @throws ContradictionException if more than one version is found for the given view coordinate
  * @throws UnsupportedDialectOrLanguage indicates an unsupported dialect or language
  */
 public static boolean isMissingDescForDialect(
     DescriptionVersionBI<?> description, int dialectNid, ViewCoordinate viewCoordinate)
     throws IOException, ContradictionException, UnsupportedDialectOrLanguage {
   lazyInit(dialectNid);
   if (!description.getLang().equals("en")) {
     return false;
   }
   if (isTextForDialect(description.getText(), dialectNid)) {
     return false;
   }
   String dialectText = makeTextForDialect(description.getText(), dialectNid);
   ConceptVersionBI concept =
       AppContext.getService(TerminologyStoreDI.class)
           .getConceptVersion(viewCoordinate, description.getConceptNid());
   for (DescriptionVersionBI<?> d : concept.getDescriptionsActive()) {
     if (d.getText().toLowerCase().equals(dialectText.toLowerCase())) {
       return false;
     }
   }
   return true;
 }
  @FXML
  void initialize() {
    assert syncUserName != null
        : "fx:id=\"syncUserName\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert cancelButton != null
        : "fx:id=\"cancelButton\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert password != null
        : "fx:id=\"password\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert fullNameUnique != null
        : "fx:id=\"fullNameUnique\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert roles != null : "fx:id=\"roles\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert layoutPane != null
        : "fx:id=\"layoutPane\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert fullName != null
        : "fx:id=\"fullName\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert okButton != null
        : "fx:id=\"okButton\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert userName != null
        : "fx:id=\"userName\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert workflowUserName != null
        : "fx:id=\"workflowUserName\" was not injected: check your FXML file 'AddUser.fxml'.";
    assert uuid != null : "fx:id=\"uuid\" was not injected: check your FXML file 'AddUser.fxml'.";

    for (RoleOption ro : RoleOption.values()) {
      roles.getItems().add(ro.value());
    }

    upm_ = AppContext.getService(UserProfileManager.class);

    uuidValid_ =
        new ValidBooleanBinding() {
          {
            bind(uuid.textProperty());
          }

          @Override
          protected boolean computeValue() {
            if (uuid.getText().length() == 0 || Utility.isUUID(uuid.getText())) {
              if (uuid.getText().length() > 0
                  && AppContext.getService(TerminologyStoreDI.class)
                      .hasUuid(UUID.fromString(uuid.getText()))) {
                setInvalidReason("If a UUID is specified, it must be unique");
                return false;
              } else {
                clearInvalidReason();
                return true;
              }
            } else {
              setInvalidReason("Invalid uuid");
              return false;
            }
          }
        };

    ErrorMarkerUtils.setupErrorMarkerAndSwap(uuid, layoutPane, uuidValid_);

    userNameValid_ =
        new ValidBooleanBinding() {
          {
            bind(userName.textProperty());
          }

          @Override
          protected boolean computeValue() {
            if (userName.getText().length() > 0 && !upm_.doesProfileExist(userName.getText())) {
              clearInvalidReason();
              return true;
            } else {
              setInvalidReason("The user name is required, and must be unique");
              return false;
            }
          }
        };

    ErrorMarkerUtils.setupErrorMarkerAndSwap(userName, layoutPane, userNameValid_);

    fullNameUniqueValid_ =
        new ValidBooleanBinding() {
          {
            bind(fullNameUnique.textProperty(), uuid.textProperty());
          }

          @Override
          protected boolean computeValue() {
            if (fullNameUnique.getText().length() > 0) {
              UUID userUuid;
              if (uuid.getText().length() > 0) {
                if (uuidValid_.get()) {
                  userUuid = UUID.fromString(uuid.getText());
                } else {
                  setInvalidReason("If a UUID is specified, it must be valid.");
                  return false;
                }
              } else {
                userUuid = GenerateUsers.calculateUserUUID(fullNameUnique.getText());
              }

              if (AppContext.getService(TerminologyStoreDI.class).hasUuid(userUuid)) {
                setInvalidReason("The full name must be unique");
                return false;
              } else {
                clearInvalidReason();
                return true;
              }
            } else {
              setInvalidReason(
                  "The Full Name is required, and must be unique.  If a UUID is specified, it must be valid, and unique");
              return false;
            }
          }
        };

    ErrorMarkerUtils.setupErrorMarkerAndSwap(fullNameUnique, layoutPane, fullNameUniqueValid_);

    okButton.disableProperty().bind(fullNameUniqueValid_.and(userNameValid_).and(uuidValid_).not());

    cancelButton.setCancelButton(true);
    // JavaFX is silly:  https://javafx-jira.kenai.com/browse/RT-39145#comment-434189
    cancelButton.setOnKeyPressed(
        new EventHandler<KeyEvent>() {
          @Override
          public void handle(KeyEvent event) {
            if (event.getCode() == KeyCode.ENTER) {
              event.consume();
              cancelButton.fire();
            }
          }
        });
    cancelButton.setOnAction(
        (event) -> {
          layoutPane.getScene().getWindow().hide();
        });

    okButton.setDefaultButton(true);
    okButton.setOnAction(
        (event) -> {
          try {
            User u = new User();
            u.setFullName(fullName.getText());
            u.setPassword(password.getText());
            u.setSyncUserName(syncUserName.getText());
            u.setWorkflowUserName(workflowUserName.getText());
            u.setUniqueFullName(fullNameUnique.getText());
            u.setUniqueLogonName(userName.getText());
            u.setUUID(uuid.getText());
            for (String roleName : roles.getSelectionModel().getSelectedItems()) {
              u.getRoles().add(RoleOption.fromValue(roleName));
            }
            upm_.createNewUser(u);
            layoutPane.getScene().getWindow().hide();
          } catch (Exception e) {
            logger.error("Error creating user", e);
            AppContext.getCommonDialogs().showErrorDialog("Unexpected error adding user", e);
          }
        });
  }
  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer("");
    try {
      sb.append(" String Value: " + strValue + "(" + primordialUuid + "),");
      sb.append(" Boolean Value: " + booleanValue + ",");
      sb.append(" Float Value: " + floatValue + ",");
      sb.append(" Int Value: " + intValue + ",");
      sb.append(" Long Value: " + longValue + ",");
      sb.append(" Refset Type: " + refsetType + ",");

      try {
        ConceptChronicleBI refset =
            AppContext.getService(TerminologyStoreDI.class).getConcept(UUID.fromString(refsetUuid));
        sb.append(" Refset: " + refset + " (" + refsetUuid + "),");
      } catch (IllegalArgumentException ex) {
      }

      try {
        ConceptChronicleBI c1 =
            AppContext.getService(TerminologyStoreDI.class).getConcept(UUID.fromString(c1Uuid));
        sb.append(" C1: " + c1 + " (" + c1Uuid + "),");
      } catch (IllegalArgumentException ex) {
      }

      try {
        ConceptChronicleBI c2 =
            AppContext.getService(TerminologyStoreDI.class).getConcept(UUID.fromString(c2Uuid));
        sb.append(" C2: " + c2 + " (" + c2Uuid + "),");
      } catch (IllegalArgumentException ex) {
      }

      try {
        ConceptChronicleBI c3 =
            AppContext.getService(TerminologyStoreDI.class).getConcept(UUID.fromString(c3Uuid));
        sb.append(" C3: " + c3 + " (" + c3Uuid + "),");
      } catch (IllegalArgumentException ex) {
      }

      try {
        ConceptChronicleBI c1 =
            AppContext.getService(TerminologyStoreDI.class).getConcept(UUID.fromString(c1Uuid));
        sb.append(" C1: " + c1 + " (" + c1Uuid + "),");
      } catch (IllegalArgumentException ex) {
      }
      sb.append(" DRCOMPONENT FIELDS: {" + super.toString() + "}, ");
      sb.append("\nIdentifiers: [");
      if (identifiers != null) {
        for (DrIdentifier identifier : identifiers) {
          int i = 0;
          sb.append(identifier.toString() + (i == identifiers.size() - 1 ? "" : ","));
          i++;
        }
      }
      sb.append("]");

    } catch (Exception e) {
      e.printStackTrace();
    }
    return sb.toString();
  }