/**
   * Get Similar authorMap of given author
   *
   * @param authorId
   * @param startPage
   * @param maxresult
   * @param response
   * @return
   */
  @RequestMapping(value = "/similarAuthorList", method = RequestMethod.GET)
  @Transactional
  public @ResponseBody Map<String, Object> getSimilarAuthorList(
      @RequestParam(value = "id", required = false) final String authorId,
      @RequestParam(value = "startPage", required = false) Integer startPage,
      @RequestParam(value = "maxresult", required = false) Integer maxresult,
      final HttpServletResponse response) {
    // create JSON mapper for response
    Map<String, Object> responseMap = new LinkedHashMap<String, Object>();
    if (authorId == null || authorId.equals("")) {
      responseMap.put("status", "error");
      responseMap.put("statusMessage", "authorId null");
      return responseMap;
    }

    if (startPage == null) startPage = 0;
    if (maxresult == null) maxresult = 10;

    // get author
    Author author = persistenceStrategy.getAuthorDAO().getById(authorId);

    if (author == null) {
      responseMap.put("status", "error");
      responseMap.put("statusMessage", "author not found in database");
      return responseMap;
    }

    // get recommended authors based on calculations
    responseMap.putAll(
        researcherFeature
            .getResearcherSimilarauthor()
            .getResearcherSimilarAuthorMap(author, startPage, maxresult));

    return responseMap;
  }
  /**
   * Get academic event tree of given author
   *
   * @param authorId
   * @param startPage
   * @param maxresult
   * @param response
   * @return
   */
  @RequestMapping(value = "/academicEventTree", method = RequestMethod.GET)
  @Transactional
  public @ResponseBody Map<String, Object> getAcademicEventTreeMap(
      @RequestParam(value = "id", required = false) final String authorId,
      final HttpServletResponse response) {
    // create JSON mapper for response
    Map<String, Object> responseMap = new LinkedHashMap<String, Object>();
    if (authorId == null || authorId.equals("")) {
      responseMap.put("status", "error");
      responseMap.put("statusMessage", "authorId null");
      return responseMap;
    }

    // get author
    Author author = persistenceStrategy.getAuthorDAO().getById(authorId);

    if (author == null) {
      responseMap.put("status", "error");
      responseMap.put("statusMessage", "author not found in database");
      return responseMap;
    }

    // get coauthor calculation
    responseMap.putAll(
        researcherFeature.getResearcherAcademicEventTree().getResearcherAcademicEventTree(author));

    return responseMap;
  }
 @RequestMapping(value = "/enrich", method = RequestMethod.GET)
 @Transactional
 public @ResponseBody Map<String, Object> researcherEnrich(
     @RequestParam(value = "id", required = false) final String authorId,
     final HttpServletResponse response)
     throws InterruptedException, IOException, ExecutionException, URISyntaxException,
         ParseException, TimeoutException {
   Author author = persistenceStrategy.getAuthorDAO().getById(authorId);
   publicationCollectionService.enrichPublicationByExtractOriginalSources(
       new ArrayList<Publication>(author.getPublications()), author, true);
   return Collections.emptyMap();
 }
  /**
   * Landing page of researcher page
   *
   * @param sessionId
   * @param response
   * @return
   * @throws InterruptedException
   */
  @RequestMapping(method = RequestMethod.GET)
  @Transactional
  public ModelAndView researcherPage(
      @RequestParam(value = "id", required = false) final String id,
      @RequestParam(value = "name", required = false) String name,
      @RequestParam(value = "add", required = false) final String add,
      final HttpServletResponse response)
      throws InterruptedException {
    ModelAndView model = TemplateHelper.createViewWithLink("researcher", LINK_NAME);

    List<Widget> widgets = new ArrayList<Widget>();

    User user = securityService.getUser();

    if (user != null) {
      List<UserWidget> userWidgets =
          persistenceStrategy
              .getUserWidgetDAO()
              .getWidget(user, WidgetType.RESEARCHER, WidgetStatus.ACTIVE);
      for (UserWidget userWidget : userWidgets) {
        Widget widget = userWidget.getWidget();
        widget.setColor(userWidget.getWidgetColor());
        widget.setWidgetHeight(userWidget.getWidgetHeight());
        widget.setWidgetWidth(userWidget.getWidgetWidth());
        widget.setPosition(userWidget.getPosition());

        widgets.add(widget);
      }
    } else
      widgets.addAll(
          persistenceStrategy
              .getWidgetDAO()
              .getWidget(WidgetType.RESEARCHER, WidgetStatus.DEFAULT));

    // assign the model
    model.addObject("widgets", widgets);
    // assign query
    if (id != null) {
      model.addObject("targetId", id);
      if (name == null) {
        Author author = persistenceStrategy.getAuthorDAO().getById(id);
        if (author != null) name = author.getName();
      }
    }
    if (name != null) model.addObject("targetName", name);
    if (add != null) model.addObject("targetAdd", add);
    return model;
  }
  /**
   * Get basic information of given author
   *
   * @param authorId
   * @param startPage
   * @param maxresult
   * @param response
   * @return
   */
  @RequestMapping(value = "/basicInformation", method = RequestMethod.GET)
  @Transactional
  public @ResponseBody Map<String, Object> getBasicInformationMap(
      @RequestParam(value = "id", required = false) final String authorId,
      final HttpServletResponse response) {
    // create JSON mapper for response
    Map<String, Object> responseMap = new LinkedHashMap<String, Object>();
    if (authorId == null || authorId.equals("")) {
      responseMap.put("status", "error");
      responseMap.put("statusMessage", "authorId null");
      return responseMap;
    }

    // get author
    Author author = persistenceStrategy.getAuthorDAO().getById(authorId);

    if (author == null) {
      responseMap.put("status", "error");
      responseMap.put("statusMessage", "author not found in database");
      return responseMap;
    }

    // get basic information
    responseMap.putAll(
        researcherFeature.getResearcherBasicInformation().getResearcherBasicInformationMap(author));

    // check whether publication is already followed or not
    User user = securityService.getUser();
    if (user != null) {
      UserAuthorBookmark uab =
          persistenceStrategy.getUserAuthorBookmarkDAO().getByUserAndAuthor(user, author);
      if (uab != null) responseMap.put("booked", true);
      else responseMap.put("booked", false);
    }

    return responseMap;
  }
  /**
   * Calculate each default InterestProfile
   *
   * @param author
   * @param interestProfileDefault
   * @param publicationClustersMap
   */
  public void calculateEachInterestProfileDefault(
      Author author,
      Set<Interest> newInterests,
      InterestProfile interestProfileDefault,
      Map<String, PublicationClusterHelper> publicationClustersMap) {
    // get author interest profile
    Calendar calendar = Calendar.getInstance();
    // default profile name [DEFAULT_PROFILENAME]
    String authorInterestProfileName = interestProfileDefault.getName();

    // create new author interest profile for c-value
    AuthorInterestProfile authorInterestProfile = new AuthorInterestProfile();
    authorInterestProfile.setCreated(calendar.getTime());
    authorInterestProfile.setDescription(
        "Interest mining using " + interestProfileDefault.getName() + " algorithm");
    authorInterestProfile.setName(authorInterestProfileName);

    // CorePhrase and WordFreq specific, according to Svetoslav Evtimov thesis
    // yearFactor Map format Map< Language-Year , value >
    // totalYearsFactor Map< Language, value >

    Map<String, Double> yearFactorMap = new HashMap<String, Double>();
    Map<String, Double> totalYearsFactorMap = new HashMap<String, Double>();

    // calculate some weighting factors
    //		if ( interestProfileDefault.getName().toLowerCase().equals( "corephrase" ) ||
    //				interestProfileDefault.getName().toLowerCase().equals( "wordfreq" )	)
    //		{
    //			yearFactorMap = CorePhraseAndWordFreqHelper.calculateYearFactor( publicationClustersMap,
    // 0.25 );
    //			totalYearsFactorMap = CorePhraseAndWordFreqHelper.calculateTotalYearsFactor(
    // publicationClustersMap );
    //		}

    // get the number of active extraction services
    int numberOfExtractionService = applicationService.getExtractionServices().size();

    // loop to each cluster and calculate default profiles
    for (Map.Entry<String, PublicationClusterHelper> publicationClusterEntry :
        publicationClustersMap.entrySet()) {
      PublicationClusterHelper publicationCluster = publicationClusterEntry.getValue();

      if (publicationCluster.getTermMap() == null || publicationCluster.getTermMap().isEmpty())
        continue;

      // prepare variables
      AuthorInterest authorInterest = new AuthorInterest();

      // assign author interest method
      if (interestProfileDefault.getName().toLowerCase().equals("cvalue")) {
        cValueInterestProfile.doCValueCalculation(
            authorInterest, newInterests, publicationCluster, numberOfExtractionService);
      } else if (interestProfileDefault.getName().toLowerCase().equals("corephrase")) {
        Double yearFactor =
            yearFactorMap.get(publicationCluster.getLanguage() + publicationCluster.getYear());
        Double totalYearFactor = totalYearsFactorMap.get(publicationCluster.getLanguage());
        corePhraseInterestProfile.doCorePhraseCalculation(
            authorInterest,
            newInterests,
            publicationCluster,
            yearFactor,
            totalYearFactor,
            numberOfExtractionService);
      } else if (interestProfileDefault.getName().toLowerCase().equals("wordfreq")) {
        Double yearFactor =
            yearFactorMap.get(publicationCluster.getLanguage() + publicationCluster.getYear());
        Double totalYearFactor = totalYearsFactorMap.get(publicationCluster.getLanguage());
        wordFreqInterestProfile.doWordFreqCalculation(
            authorInterest,
            newInterests,
            publicationCluster,
            yearFactor,
            totalYearFactor,
            numberOfExtractionService);
      }
      // Put other default interest profiles
      else if (interestProfileDefault.getName().toLowerCase().equals("lda")) {

      }

      // at the end persist new interests
      // for ( Interest newInterest : newInterests )
      // persistenceStrategy.getInterestDAO().persist( newInterest );

      // check author interest calculation result
      if (authorInterest.getTermWeights() != null && !authorInterest.getTermWeights().isEmpty()) {
        authorInterest.setAuthorInterestProfile(authorInterestProfile);
        authorInterestProfile.addAuthorInterest(authorInterest);
        authorInterestProfile.setInterestProfile(interestProfileDefault);
        // persistenceStrategy.getAuthorInterestProfileDAO().persist( authorInterestProfile );
      }
    }

    // at the end persist
    if (authorInterestProfile.getAuthorInterests() != null
        && !authorInterestProfile.getAuthorInterests().isEmpty()) {
      authorInterestProfile.setAuthor(author);
      author.addAuthorInterestProfiles(authorInterestProfile);
      persistenceStrategy.getAuthorDAO().persist(author);
    }
  }
  /**
   * Calculated derived interest profile (Intersection and/or Union between interest profile) in an
   * author
   *
   * @param author
   * @param interestProfilesDerived
   */
  private void calculateInterestProfilesDerived(
      Author author, List<InterestProfile> interestProfilesDerived) {
    // get authorInterest set on profile
    for (InterestProfile interestProfileDerived : interestProfilesDerived) {

      String[] derivedInterestProfileName = interestProfileDerived.getName().split("\\s+");

      // at list profile name has three segment
      if (derivedInterestProfileName.length < 3) continue;

      // prepare variables
      AuthorInterestProfile authorInterestProfile1 = null;
      AuthorInterestProfile authorInterestProfile2 = null;
      AuthorInterestProfile authorInterestProfileResult = null;
      String operationType = null;

      for (String partOfProfileName : derivedInterestProfileName) {
        // ? sometimes problem on encoding
        if (partOfProfileName.equals("∩")
            || partOfProfileName.equals("?")
            || partOfProfileName.equals("+")
            || partOfProfileName.equals("∪")) {
          if (authorInterestProfileResult != null) {
            authorInterestProfile1 = authorInterestProfileResult;
            authorInterestProfileResult = null;
          }
          if (partOfProfileName.equals("∩")
              || partOfProfileName.equals("?")
              || partOfProfileName.equals("+")) operationType = "INTERSECTION";
          else operationType = "UNION";
        } else {
          if (authorInterestProfile1 == null) {
            authorInterestProfile1 = author.getSpecificAuthorInterestProfile(partOfProfileName);

            if (authorInterestProfile1 == null) {
              logger.error("AuthorInterestProfile " + partOfProfileName + " not found");
              // continue to next derived author profile, if exist
              break;
            }
          } else {
            authorInterestProfile2 = author.getSpecificAuthorInterestProfile(partOfProfileName);

            if (authorInterestProfile2 == null) {
              logger.error("AuthorInterestProfile " + partOfProfileName + " not found");
              // continue to next derived author profile, if exist
              break;
            }
          }

          // calculate and persist
          if (authorInterestProfile1 != null
              && authorInterestProfile2 != null
              && operationType != null) {
            if (operationType.equals("INTERSECTION"))
              authorInterestProfileResult =
                  calculateIntersectionOfAuthorInterestProfiles(
                      authorInterestProfile1, authorInterestProfile2, interestProfileDerived);
            else
              authorInterestProfileResult =
                  calculateUnionOfAuthorInterestProfiles(
                      authorInterestProfile1, authorInterestProfile2, interestProfileDerived);
          }
        }
      }
      // persist result
      if (authorInterestProfileResult != null
          && (authorInterestProfileResult.getAuthorInterests() != null
              && !authorInterestProfileResult.getAuthorInterests().isEmpty())) {
        authorInterestProfileResult.setAuthor(author);
        author.addAuthorInterestProfiles(authorInterestProfileResult);
        persistenceStrategy.getAuthorDAO().persist(author);

        persistenceStrategy.getAuthorInterestProfileDAO().persist(authorInterestProfileResult);
      }
    }
  }