/**
   * Set annotation preferences of users for a given project such as window size, annotation
   * layers,... reading from the file system.
   *
   * @param aUsername The {@link User} for whom we need to read the preference (preferences are
   *     stored per user)
   * @param aRepositoryService the repository service.
   * @param aAnnotationService the annotation service.
   * @param aBModel The {@link BratAnnotatorModel} that will be populated with preferences from the
   *     file
   * @param aMode the mode.
   * @throws BeansException hum?
   * @throws IOException hum?
   */
  public static void setAnnotationPreference(
      String aUsername,
      RepositoryService aRepositoryService,
      AnnotationService aAnnotationService,
      BratAnnotatorModel aBModel,
      Mode aMode)
      throws BeansException, IOException {
    AnnotationPreference preference = new AnnotationPreference();
    BeanWrapper wrapper = new BeanWrapperImpl(preference);
    // get annotation preference from file system
    try {
      Properties props = aRepositoryService.loadUserSettings(aUsername, aBModel.getProject());
      for (Entry<Object, Object> entry : props.entrySet()) {
        String property = entry.getKey().toString();
        int index = property.lastIndexOf(".");
        String propertyName = property.substring(index + 1);
        String mode = property.substring(0, index);
        if (wrapper.isWritableProperty(propertyName) && mode.equals(aMode.getName())) {
          if (AnnotationPreference.class.getDeclaredField(propertyName).getGenericType()
              instanceof ParameterizedType) {
            List<String> value =
                Arrays.asList(
                    StringUtils.replaceChars(entry.getValue().toString(), "[]", "").split(","));
            if (!value.get(0).equals("")) {
              wrapper.setPropertyValue(propertyName, value);
            }
          } else {
            wrapper.setPropertyValue(propertyName, entry.getValue());
          }
        }
      }
      aBModel.setPreferences(preference);

      // Get tagset using the id, from the properties file
      aBModel.getAnnotationLayers().clear();
      if (preference.getAnnotationLayers() != null) {
        for (Long id : preference.getAnnotationLayers()) {
          aBModel.getAnnotationLayers().add(aAnnotationService.getLayer(id));
        }
      } else {
        // If no layer preferences are defined, then just assume all layers are enabled
        List<AnnotationLayer> layers = aAnnotationService.listAnnotationLayer(aBModel.getProject());
        aBModel.setAnnotationLayers(layers);
      }
    }
    // no preference found
    catch (Exception e) {
      // If no layer preferences are defined, then just assume all layers are enabled
      List<AnnotationLayer> layers = aAnnotationService.listAnnotationLayer(aBModel.getProject());
      aBModel.setAnnotationLayers(layers);
    }
  }
  public static void savePreference(BratAnnotatorModel aBModel, RepositoryService aRepository)
      throws FileNotFoundException, IOException {
    AnnotationPreference preference = aBModel.getPreferences();
    ArrayList<Long> layers = new ArrayList<Long>();

    for (AnnotationLayer layer : aBModel.getAnnotationLayers()) {
      layers.add(layer.getId());
    }
    preference.setAnnotationLayers(layers);

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    aRepository.saveUserSettings(username, aBModel.getProject(), aBModel.getMode(), preference);
  }
  /**
   * Fetches the CAS that the user will be able to edit. In AUTOMATION/CORRECTION mode, this is the
   * CAS for the CORRECTION_USER and in CURATION mode it is the CAS for the CURATION user.
   *
   * @param aBratAnnotatorModel the model.
   * @param aDocument the source document.
   * @param jCases the JCases.
   * @param randomAnnotationDocument an annotation document.
   * @return the JCas.
   * @throws UIMAException hum?
   * @throws ClassNotFoundException hum?
   * @throws IOException if an I/O error occurs.
   * @throws BratAnnotationException hum?
   */
  public JCas getMergeCas(
      BratAnnotatorModel aBratAnnotatorModel,
      SourceDocument aDocument,
      Map<String, JCas> jCases,
      AnnotationDocument randomAnnotationDocument)
      throws UIMAException, ClassNotFoundException, IOException, BratAnnotationException {
    JCas mergeJCas = null;
    try {
      if (aBratAnnotatorModel.getMode().equals(Mode.AUTOMATION)
          || aBratAnnotatorModel.getMode().equals(Mode.CORRECTION)) {
        // Upgrading should be an explicit action during the opening of a document at the
        // end
        // of the open dialog - it must not happen during editing because the CAS addresses
        // are used as IDs in the UI
        // repository.upgradeCasAndSave(aDocument, aBratAnnotatorModel.getMode(),
        // aBratAnnotatorModel.getUser().getUsername());
        mergeJCas = repository.readCorrectionCas(aDocument);
      } else {
        // Upgrading should be an explicit action during the opening of a document at the
        // end
        // of the open dialog - it must not happen during editing because the CAS addresses
        // are used as IDs in the UI
        // repository.upgradeCasAndSave(aDocument, aBratAnnotatorModel.getMode(),
        // aBratAnnotatorModel.getUser().getUsername());
        mergeJCas = repository.readCurationCas(aDocument);
      }
    }
    // Create jcas, if it could not be loaded from the file system
    catch (Exception e) {

      if (aBratAnnotatorModel.getMode().equals(Mode.AUTOMATION)
          || aBratAnnotatorModel.getMode().equals(Mode.CORRECTION)) {
        mergeJCas = createCorrectionCas(mergeJCas, aBratAnnotatorModel, randomAnnotationDocument);
      } else {
        mergeJCas =
            createCurationCas(
                aBratAnnotatorModel.getProject(),
                randomAnnotationDocument,
                jCases,
                aBratAnnotatorModel.getAnnotationLayers());
      }
    }
    return mergeJCas;
  }
  public CurationContainer buildCurationContainer(BratAnnotatorModel aBModel)
      throws UIMAException, ClassNotFoundException, IOException, BratAnnotationException {
    CurationContainer curationContainer = new CurationContainer();
    // initialize Variables
    SourceDocument sourceDocument = aBModel.getDocument();
    Map<Integer, Integer> segmentBeginEnd = new HashMap<Integer, Integer>();
    Map<Integer, Integer> segmentNumber = new HashMap<Integer, Integer>();
    Map<String, Map<Integer, Integer>> segmentAdress = new HashMap<String, Map<Integer, Integer>>();
    // get annotation documents

    List<AnnotationDocument> finishedAnnotationDocuments = new ArrayList<AnnotationDocument>();

    for (AnnotationDocument annotationDocument :
        repository.listAnnotationDocuments(aBModel.getDocument())) {
      if (annotationDocument.getState().equals(AnnotationDocumentState.FINISHED)) {
        finishedAnnotationDocuments.add(annotationDocument);
      }
    }

    Map<String, JCas> jCases = new HashMap<String, JCas>();

    AnnotationDocument randomAnnotationDocument = null;
    JCas mergeJCas;

    // get the correction/automation JCas for the logged in user
    if (aBModel.getMode().equals(Mode.AUTOMATION) || aBModel.getMode().equals(Mode.CORRECTION)) {
      jCases = listJcasesforCorrection(randomAnnotationDocument, sourceDocument, aBModel.getMode());
      mergeJCas = getMergeCas(aBModel, sourceDocument, jCases, randomAnnotationDocument);
      String username = jCases.keySet().iterator().next();
      updateSegment(
          aBModel,
          segmentBeginEnd,
          segmentNumber,
          segmentAdress,
          jCases.get(username),
          username,
          aBModel.getPreferences().getWindowSize());

    } else {

      jCases =
          listJcasesforCuration(
              finishedAnnotationDocuments, randomAnnotationDocument, aBModel.getMode());
      mergeJCas = getMergeCas(aBModel, sourceDocument, jCases, randomAnnotationDocument);
      updateSegment(
          aBModel,
          segmentBeginEnd,
          segmentNumber,
          segmentAdress,
          mergeJCas,
          CurationPanel.CURATION_USER,
          aBModel.getPreferences().getCurationWindowSize());
    }

    List<Type> entryTypes = null;

    segmentAdress.put(CurationPanel.CURATION_USER, new HashMap<Integer, Integer>());
    for (Sentence sentence : selectCovered(mergeJCas, Sentence.class, begin, end)) {
      segmentAdress.get(CurationPanel.CURATION_USER).put(sentence.getBegin(), getAddr(sentence));
    }

    if (entryTypes == null) {
      entryTypes = getEntryTypes(mergeJCas, aBModel.getAnnotationLayers(), annotationService);
    }

    // for cross-sentences annotation, update the end of the segment
    if (firstload) {
      updateCrossSentAnnoList(segmentBeginEnd, jCases, entryTypes);
      firstload = false;
    }

    for (Integer begin : segmentBeginEnd.keySet()) {
      Integer end = segmentBeginEnd.get(begin);

      DiffResult diff =
          CasDiff2.doDiffSingle(
              annotationService, aBModel.getProject(), entryTypes, jCases, begin, end);
      SourceListView curationSegment = new SourceListView();
      curationSegment.setBegin(begin);
      curationSegment.setEnd(end);
      if (diff.hasDifferences() || !diff.getIncompleteConfigurationSets().isEmpty()) {
        curationSegment.setSentenceState(SentenceState.DISAGREE);
      } else {
        curationSegment.setSentenceState(SentenceState.AGREE);
      }
      curationSegment.setSentenceNumber(segmentNumber.get(begin));

      for (String username : segmentAdress.keySet()) {
        curationSegment.getSentenceAddress().put(username, segmentAdress.get(username).get(begin));
      }
      curationContainer.getCurationViewByBegin().put(begin, curationSegment);
    }
    return curationContainer;
  }