@RequestMapping(value = "/oauth/delApp/{TOKEN}/{APPID}", method = RequestMethod.GET)
  @Timed
  public ResponseEntity<Void> delApp(
      @PathVariable("TOKEN") String ott,
      @PathVariable("APPID") String appId,
      HttpServletRequest request)
      throws IOException, JAXBException, TokenNotFoundException, TokenAlreadyUsedException {
    log.debug("REST ADD CUSTOM APPS. token [{}]", ott);

    Token token = tokenRepository.findOneByOtt(ott);
    if (token == null) {
      throw new TokenNotFoundException(ott);
    }

    Person person = token.getPerson();
    Application application = token.getApplication();

    Application toDelete = applicationRepository.findOne(new Long(appId));

    RelPersonApplication relPersonApplication =
        relPersonApplicationRepository.findOneByApplicationIsAndTokenIs(toDelete, token);

    log.debug(
        "REST ADD CUSTOM APPS. person [{}], localid [{}], relPersonApplication [{}]",
        person,
        person.getLocalID(),
        relPersonApplication.getId());

    relPersonApplicationRepository.delete(relPersonApplication);

    return ResponseEntity.ok().build();
  }
  @RequestMapping(value = "/oauth/addApp/{TOKEN}/{APPID}", method = RequestMethod.GET)
  @Timed
  public AddAppResponseDTO addApp(
      @PathVariable("TOKEN") String ott,
      @PathVariable("APPID") String appId,
      HttpServletRequest request)
      throws IOException, JAXBException, TokenNotFoundException, TokenAlreadyUsedException {
    AddAppResponseDTO response = new AddAppResponseDTO();
    log.debug("REST ADD CUSTOM APPS. token [{}]", ott);

    Token token = tokenRepository.findOneByOtt(ott);
    if (token == null) {
      throw new TokenNotFoundException(ott);
    }

    Person person = token.getPerson();
    Application application = token.getApplication();

    Application customApp = applicationRepository.findOne(new Long(appId));

    log.debug(
        "REST ADD CUSTOM APPS. person [{}], localid [{}], customApp [{}]",
        person,
        person.getLocalID(),
        customApp.getId());

    RelPersonApplication relPersonApplication = null;
    relPersonApplication = new RelPersonApplication();
    relPersonApplication.setApplication(customApp);
    relPersonApplication.setPerson(person);
    relPersonApplication.setToken(token);
    relPersonApplication.setValid(null);
    relPersonApplication.setLast(true);
    relPersonApplication.setCustom(true);
    relPersonApplicationRepository.save(relPersonApplication);

    ApplicationMinDTO appMinAdded = ApplicationMapper.from(customApp, true, null);
    response.setApp(appMinAdded);

    return response;
  }
  @RequestMapping(value = "/oauth/newApps/{TOKEN}", method = RequestMethod.GET)
  @Timed
  public ListAddAppResponseDTO oauthNewAppForUser(
      @PathVariable("TOKEN") String ott, HttpServletRequest request)
      throws IOException, JAXBException, TokenNotFoundException, TokenAlreadyUsedException {
    ListAddAppResponseDTO response = new ListAddAppResponseDTO();
    log.debug("REST GET CUSTOM APPS. token [{}]", ott);

    Token token = tokenRepository.findOneByOtt(ott);
    if (token == null) {
      throw new TokenNotFoundException(ott);
    }

    Person person = token.getPerson();
    Application application = token.getApplication();

    log.debug("REST GET CUSTOM APPS. person [{}], localid [{}]", person, person.getLocalID());

    List<RelPersonApplication> listApplicationAuth =
        relPersonApplicationRepository.findAllByTokenIsAndValidIsNull(token);
    List<Long> listIdsToExclude = new ArrayList<Long>();
    for (int i = 0; i < listApplicationAuth.size(); i++) {
      listIdsToExclude.add(listApplicationAuth.get(i).getApplication().getId());
    }

    log.debug(
        "REST GET CUSTOM APPS. person [{}], localid [{}], listIds [{}]",
        person,
        person.getLocalID(),
        listIdsToExclude);

    List<Application> listCustomApps = applicationRepository.findAllCustomApps(listIdsToExclude);

    response.setListApp(ApplicationMapper.fromListAppCustom(listCustomApps));

    return response;
  }
  @RequestMapping(value = "/oauth/finish", method = RequestMethod.GET)
  @Timed
  public void oauthUserFinish(
      HttpServletRequest request,
      HttpServletResponse response,
      @RequestParam(value = "code", required = false) String code,
      @RequestParam(value = "state", required = false) String state,
      @RequestParam(value = "error", required = false) String error,
      @RequestParam(value = "error_description", required = false) String errorDescription)
      throws IOException, JAXBException, RelPersonApplicationNotFoundException,
          InterruptedException {

    log.debug(
        "REST OAUTHFINISH START. code [{}],state/relId [{}],error [{}], error_description [{}]",
        code,
        state,
        error,
        errorDescription);

    RelPersonApplication relPersonApplication =
        relPersonApplicationRepository.findOne(new Long(state));
    if ((relPersonApplication == null) || (relPersonApplication.getValid() != null)) {
      String relPersonApplicationId = "-1";
      if (relPersonApplication != null)
        relPersonApplicationId = relPersonApplication.getId().toString();
      throw new RelPersonApplicationNotFoundException(relPersonApplicationId);
    }

    Application application = relPersonApplication.getApplication();
    Person person = relPersonApplication.getPerson();
    Token token = relPersonApplication.getToken();

    // invalido token
    if (token.getDateUsed() == null) {
      token.setDateUsed(DateTime.now());
      tokenRepository.save(token);
    }

    if (error != null) {
      log.info(
          "REST OAUTHFINISH {}. localId [{}],appId [{}],error [{}], error_description [{}]",
          error,
          person.getLocalID(),
          application.getApplicationID(),
          error,
          errorDescription);
      if (error.equals("access_denied")) {
        relPersonApplication.setDenied(true);
        relPersonApplication.setDateDenied(DateTime.now());
        relPersonApplication.setValid(true);
      } else {
        relPersonApplication.setValid(false);
      }
      relPersonApplication.setErrorDescription(error);
      relPersonApplication.setDateReleased(DateTime.now());
      relPersonApplicationRepository.save(relPersonApplication);

    } else {

      String callBackUrl = getCallbackOrcidURL(request);
      OrcidOAuthClient clientOrcid =
          new OrcidOAuthClient(
              application.getApplicationID(),
              application.getApplicationSecret(),
              callBackUrl,
              orcidApiType);
      log.info(
          "REST OAUTHFINISH REQUEST ACCESSTOKEN. localId [{}],appId [{}], appSecret [{}]. orcidApiType [{}]",
          person.getLocalID(),
          application.getApplicationID(),
          application.getApplicationSecret(),
          orcidApiType);
      OrcidAccessToken tokenOrcid = clientOrcid.getAccessToken(code);
      log.info(
          "REST OAUTHFINISH ACCESSTOKEN RELEASED. localId [{}],appId [{}],accessToken [{}], orcid [{}]",
          person.getLocalID(),
          application.getApplicationID(),
          tokenOrcid.getAccess_token(),
          tokenOrcid.getOrcid());
      relPersonApplication.setDateReleased(DateTime.now());
      relPersonApplication.setOauthAccessToken(tokenOrcid.getAccess_token());
      relPersonApplication.setValid(true);
      relPersonApplication.setDenied(false);
      if ((person.getOrcid() == null)
          || ((tokenOrcid.getOrcid() != null)
              && (!person.getOrcid().equals(tokenOrcid.getOrcid())))) {
        person.setOrcid(tokenOrcid.getOrcid());
        person.setOrcidReleaseDate(DateTime.now());
      }
      relPersonApplicationRepository.save(relPersonApplication);
      personRepository.save(person);

      // async
      orcidService.sendNotify(relPersonApplication);
    }

    List<RelPersonApplication> listApplicationAuth =
        relPersonApplicationRepository.findAllByTokenIsAndValidIsNull(token);

    if (listApplicationAuth.size() > 0) {
      Application applicationAuthorize = listApplicationAuth.get(0).getApplication();

      String callBackUrl = getCallbackOrcidURL(request);
      OrcidOAuthClient clientOrcid =
          new OrcidOAuthClient(
              applicationAuthorize.getApplicationID(),
              applicationAuthorize.getApplicationSecret(),
              callBackUrl,
              orcidApiType);

      List<OrcidAuthScope> orcidScopes = clientOrcid.getListAllScope();
      String urlToRedirect =
          clientOrcid.getAuthzCodeRegisterRequest(
              listApplicationAuth.get(0).getId().toString(),
              orcidScopes,
              person.getFirstName(),
              person.getLastName(),
              person.getEmail());

      log.debug(
          "REST OAUTHFINISH REDIRECT TO APP. listApp [{}], appId [{}], token [{}], urlRedirect [{}]",
          listApplicationAuth.size(),
          applicationAuthorize.getApplicationID(),
          listApplicationAuth.get(0).getToken().getOtt(),
          urlToRedirect);
      response.sendRedirect(urlToRedirect);
    } else {
      String urlToRedirect = token.getUrlCallback();
      if ((urlToRedirect == null) || (urlToRedirect.isEmpty())) {
        Application appRequest = token.getApplication();
        urlToRedirect = appRequest.getUrlCallback();
      }
      if (urlToRedirect.contains("?")) urlToRedirect = urlToRedirect + "&";
      else urlToRedirect = urlToRedirect + "?";
      urlToRedirect = urlToRedirect + "ott=" + token.getOtt();
      RelPersonApplication resultRel =
          relPersonApplicationRepository.findOneByPersonIsAndApplicationIsAndTokenIs(
              token.getPerson(), token.getApplication(), token);
      String resultCode = null;
      if ((resultRel != null)
          && (resultRel.getValid())
          && ((resultRel.getDenied() == null) || (resultRel.getDenied() == false))) {
        resultCode = "001";
      } else if (resultRel.getDenied()) {
        resultCode = ResultCode.ERROR_USER_DENIED.getCode();
      } else {
        resultCode = ResultCode.ERROR_ORCID_FOR_USER_MISSING.getCode();
      }
      urlToRedirect = urlToRedirect + "&result-code=" + resultCode;
      log.debug(
          "REST OAUTHFINISH FINISH. token [{}], urlToRedirect: [{}], resultCode [{}]",
          token.getOtt(),
          urlToRedirect,
          resultCode);
      response.sendRedirect(urlToRedirect);
    }
    return;
  }
  @RequestMapping(value = "/oauth/apps/{TOKEN}", method = RequestMethod.GET)
  @Timed
  public GetLandingPageResponseDTO oauthAppForUser(
      @PathVariable("TOKEN") String ott, HttpServletRequest request)
      throws IOException, JAXBException, TokenNotFoundException, TokenAlreadyUsedException {
    GetLandingPageResponseDTO response = new GetLandingPageResponseDTO();
    log.debug("REST GET APPS. token [{}]", ott);

    Token token = tokenRepository.findOneByOtt(ott);
    if (token == null) {
      throw new TokenNotFoundException(ott);
    }

    Person person = token.getPerson();
    Application application = token.getApplication();

    log.debug("REST GET APPS. person [{}], localid [{}]", person, person.getLocalID());

    // qual è l'organizzazione dell'utente?
    String orgUnit = null;
    if (application.getAllOrg()) orgUnit = token.getOrgUnit();
    else orgUnit = application.getOrgUnit();

    List<RelPersonApplication> listApplicationAuth =
        relPersonApplicationRepository.findAllByTokenIsAndValidIsNull(token);
    String urlRegisterOrcid = null;
    String urlLoginOrcid = null;
    if (listApplicationAuth.size() > 0) {
      Application applicationAuthorize = listApplicationAuth.get(0).getApplication();

      String callBackUrl = getCallbackOrcidURL(request);
      OrcidOAuthClient clientOrcid =
          new OrcidOAuthClient(
              applicationAuthorize.getApplicationID(),
              applicationAuthorize.getApplicationSecret(),
              callBackUrl,
              orcidApiType);

      List<OrcidAuthScope> orcidScopes = clientOrcid.getListAllScope();
      urlRegisterOrcid =
          clientOrcid.getAuthzCodeRegisterRequest(
              listApplicationAuth.get(0).getId().toString(),
              orcidScopes,
              person.getFirstName(),
              person.getLastName(),
              person.getEmail());
      urlLoginOrcid =
          clientOrcid.getAuthzCodeLoginRequest(
              listApplicationAuth.get(0).getId().toString(),
              orcidScopes,
              person.getFirstName(),
              person.getLastName(),
              person.getEmail());
      ;
    }
    String urlHelp = null;
    if ((application.getHelpURL() != null) && (!application.getHelpURL().isEmpty())) {
      urlHelp = application.getHelpURL();
    } else if ((application.getHelpMail() != null) && (!application.getHelpMail().isEmpty())) {
      urlHelp =
          "mailto:" + application.getHelpMail() + "?Subject=ORCID Support " + person.getLocalID();
    }

    // List<Application> applicationForUser =
    // applicationRepository.findAllByOrgUnitOrAllOrgIsTrue(orgUnit);
    response.setFirstname(person.getFirstName());
    response.setLastname(person.getLastName());
    response.setUrlRegisterOrcid(urlRegisterOrcid);
    response.setUrlLoginOrcid(urlLoginOrcid);
    response.setUrlHelp(urlHelp);
    response.setListApp(ApplicationMapper.fromListRelApp(listApplicationAuth));

    return response;
  }
  @RequestMapping(value = "/oauth/{TOKEN}", method = RequestMethod.GET)
  @Timed
  public void oauthUser(
      @PathVariable("TOKEN") String ott, HttpServletRequest request, HttpServletResponse response)
      throws IOException, JAXBException, TokenNotFoundException, TokenAlreadyUsedException {
    log.debug("REST OAUTH START. token [{}]", ott);

    Token token = tokenRepository.findOneByOtt(ott);
    if (token == null) {
      throw new TokenNotFoundException(ott);
    }
    // if( token.getDateUsed() !=null){
    //	throw new TokenAlreadyUsedException(ott);
    // }

    Person person = token.getPerson();
    Application application = token.getApplication();

    // qual è l'organizzazione dell'utente?
    String orgUnit = null;
    if (application.getAllOrg()) orgUnit = token.getOrgUnit();
    else orgUnit = application.getOrgUnit();

    List<Application> applicationForUser =
        applicationRepository.findAllByOrgUnitOrAllOrgIsTrue(orgUnit);
    Map<Long, Application> applicationForUserMap = new HashMap<Long, Application>();
    for (Application i : applicationForUser) applicationForUserMap.put(i.getId(), i);

    List<RelPersonApplication> listApplicationAuth =
        relPersonApplicationRepository.findAllByPersonIsAndLastIsTrue(person);
    Map<Long, RelPersonApplication> mapRelOld = new HashMap<Long, RelPersonApplication>();
    // Set old application access key invalid
    for (int i = 0; i < listApplicationAuth.size(); i++) {
      RelPersonApplication applicationAuthorize = listApplicationAuth.get(i);
      applicationAuthorize.setValid(false);
      applicationAuthorize.setLast(false);
      relPersonApplicationRepository.save(applicationAuthorize);
      mapRelOld.put(applicationAuthorize.getApplication().getId(), applicationAuthorize);
      if ((applicationAuthorize.getCustom() == true)
          && (applicationForUserMap.get(applicationAuthorize.getApplication().getId()) == null)) {
        applicationForUser.add(applicationAuthorize.getApplication());
      }
    }

    // token.setDateUsed(DateTime.now());
    // tokenRepository.save(token);

    Application applicationAuthorize = null;
    RelPersonApplication relPersonApplication = null;

    // Create new access key record
    for (int i = 0; i < applicationForUser.size(); i++) {
      applicationAuthorize = applicationForUser.get(i);
      relPersonApplication = new RelPersonApplication();
      relPersonApplication.setApplication(applicationAuthorize);
      relPersonApplication.setPerson(person);
      relPersonApplication.setToken(token);
      if (mapRelOld.get(applicationAuthorize.getId()) != null) {
        RelPersonApplication relOld = mapRelOld.get(applicationAuthorize.getId());
        relPersonApplication.setDateReleased(relOld.getDateReleased());
        relPersonApplication.setOauthAccessToken(relOld.getOauthAccessToken());
        relPersonApplication.setCustom(relOld.getCustom());
      } else {
        relPersonApplication.setCustom(false);
      }
      relPersonApplication.setValid(null);
      relPersonApplication.setLast(true);

      relPersonApplicationRepository.save(relPersonApplication);
    }

    String urlToRedirect = getLandingPageURL(request, ott);

    log.info(
        "REST OAUTH REDIRECT TO APP. listApp [{}], appId [{}], token [{}], urlRedirect [{}]",
        applicationForUser.size(),
        applicationAuthorize.getApplicationID(),
        ott,
        urlToRedirect);
    log.debug("REST OAUTH FINISH. token [{}], urlToRedirect [{}]", ott, urlToRedirect);

    response.sendRedirect(urlToRedirect);
    return;
  }
  @RequestMapping(
      value = "/user/id/{TOKEN}",
      method = RequestMethod.GET,
      produces = MediaType.APPLICATION_JSON_VALUE)
  @Timed
  public GetUserIdResponseDTO getUserId(@PathVariable("TOKEN") String tokenString)
      throws TokenNotFoundException, OrcidForUserMissingException, ApplicationlIDDifferentException,
          OrcidDeniedForApplicationException {
    log.debug("REST GET-USER-ID START. token [{}]", tokenString);

    Token token = tokenRepository.findOneByOtt(tokenString);
    if (token == null) {
      throw new TokenNotFoundException(tokenString);
    }

    String currentLogin = SecurityUtils.getCurrentLogin();
    if (!currentLogin.equals(token.getApplication().getApplicationID())) {
      throw new ApplicationlIDDifferentException(
          currentLogin, token.getApplication().getApplicationID());
    }

    RelPersonApplication relPersonApplication =
        relPersonApplicationRepository.findOneByPersonIsAndApplicationIsAndTokenIs(
            token.getPerson(), token.getApplication(), token);
    if (token.getPerson().getOrcid() == null) {
      if (relPersonApplication == null) {
        throw new OrcidForUserMissingException(token.getPerson().getLocalID());
      } else if (relPersonApplication.getDenied()) {
        throw new OrcidDeniedForApplicationException(token.getPerson().getLocalID());
      } else if (!relPersonApplication.getValid()) {
        throw new OrcidForUserMissingException(token.getPerson().getLocalID());
      }
    }

    GetUserIdResponseDTO response = new GetUserIdResponseDTO();
    if (relPersonApplication != null)
      response.setOrcidAccessToken(relPersonApplication.getOauthAccessToken());
    response.setOrcid(token.getPerson().getOrcid());
    response.setResultCode("001");

    log.debug(
        "REST GET-USER-ID END. token [{}], orcid [{}]", tokenString, token.getPerson().getOrcid());
    return response;
  }
  @RequestMapping(
      value = "/user/{LOCALID}/ticket",
      method = RequestMethod.POST,
      produces = MediaType.APPLICATION_JSON_VALUE)
  @Timed
  public ResponseEntity<GetTicketResponseDTO> getTicket(
      @RequestBody GetTicketRequestDTO jsonGetTicket, @PathVariable("LOCALID") String localID)
      throws ApplicationNotFoundException, LocalIDDifferentException, LocalIdMissingException,
          ApplicationIdMissingException, ApplicationlIDDifferentException,
          OrgIdIsOnlyForPublicAppException, OrgIdIsMissingException {
    log.debug("REST GETTICKET START. localid [{}], appid [{}]", localID, jsonGetTicket.getAppId());

    checkGetTicketInput(localID, jsonGetTicket);

    Application application =
        applicationRepository.findOneByApplicationID(jsonGetTicket.getAppId());
    if (application == null) {
      throw new ApplicationNotFoundException(jsonGetTicket.getAppId());
    }

    Person person = personRepository.findOneByLocalID(localID);
    if (person == null) {
      // create new person
      person = new Person();
      person.setLocalID(localID);
    }
    // update persona name surname mail
    if (jsonGetTicket.getFirstname() != null && !jsonGetTicket.getFirstname().isEmpty())
      person.setFirstName(jsonGetTicket.getFirstname());
    if (jsonGetTicket.getLastname() != null && !jsonGetTicket.getLastname().isEmpty())
      person.setLastName(jsonGetTicket.getLastname());
    if (jsonGetTicket.getMail() != null && !jsonGetTicket.getMail().isEmpty())
      person.setEmail(jsonGetTicket.getMail());
    personRepository.save(person);

    if ((jsonGetTicket.getOrgId() != null)
        && (!jsonGetTicket.getOrgId().isEmpty())
        && (!application.getAllOrg())) {
      // if app isn't for all org must not specify org-id
      throw new OrgIdIsOnlyForPublicAppException(application.getApplicationID());
    } else if (application.getAllOrg()
        && ((jsonGetTicket.getOrgId() == null) || (jsonGetTicket.getOrgId().isEmpty()))) {
      // if app is for all org must specify org-id
      throw new OrgIdIsMissingException(application.getApplicationID());
    }

    // create token
    Token token = new Token();
    token.setApplication(application);
    token.setPerson(person);
    token.setOrgUnit(jsonGetTicket.getOrgId());
    token.setUrlCallback(jsonGetTicket.getUrlCallback());
    token.setDateReleased(DateTime.now());
    tokenRepository.save(token);
    token.setOtt(generateTokenData(token.getId().toString()));
    tokenRepository.save(token);

    // search if person-app have an access-token
    RelPersonApplication relPersonApplication =
        relPersonApplicationRepository.findOneByPersonIsAndApplicationIsAndLastIsTrue(
            person, application);
    String orcid = person.getOrcid();
    String apiKey = null;

    GetTicketResponseDTO response = new GetTicketResponseDTO();
    response.setToken(token.getOtt());
    if ((relPersonApplication != null)
        && ((relPersonApplication.getDenied() == null)
            || (relPersonApplication.getDenied() == false))) {
      apiKey = relPersonApplication.getOauthAccessToken();
      response.setOrcidAccessToken(apiKey);
    }
    response.setOrcid(person.getOrcid());
    if ((orcid != null) && (apiKey != null)) response.setResultCode(ResultCode.SUCCESS.getCode());
    else response.setResultCode(ResultCode.SUCCESS_ALREADY_EXISTS.getCode());

    log.info(
        "REST GETTICKET NEW TICKET.appid [{}], localid [{}], token [{}], resultCode [{}]",
        jsonGetTicket.getAppId(),
        localID,
        token.getOtt(),
        response.getResultCode());
    log.debug(
        "REST GETTICKET END. localid [{}], token [{}], resultCode [{}]",
        localID,
        token.getOtt(),
        response.getResultCode());
    return new ResponseEntity<GetTicketResponseDTO>(response, HttpStatus.OK);
  }