package eu.dnetlib.openaire.rest;

import com.google.gson.*;
import eu.dnetlib.data.claims.entity.Claim;
import eu.dnetlib.data.claims.entity.Notification;
import eu.dnetlib.data.claims.handler.*;
import eu.dnetlib.data.claims.sql.SQLStoreException;
import eu.dnetlib.data.claims.utils.ClaimValidationException;
import eu.dnetlib.data.emailSender.EmailSender;
import eu.dnetlib.data.jobManager.Job;
import org.apache.commons.validator.EmailValidator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.XML;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;


/**
 * Created by kiatrop on 15/4/2016.
 */
@Component
@CrossOrigin(origins = "*")
@Path("/claimsService")
public class ClaimsService {

    private static final Logger logger = LogManager.getLogger(ClaimsService.class);

    @Autowired
    private FetchClaimHandler fetchClaimHandler = null;

    @Autowired
    private FetchProjectHandler fetchProjectHandler= null;

    @Autowired
    private FetchNotificationHandler fetchNotificationHandler = null;

    @Autowired
    private NotificationHandler notificationHandler = null;


    @Autowired
    private ClaimHandler claimHandler = null;

    @Autowired
    private DirectIndexHandler directIndexHandler = null;

    @Autowired
    public Authorization authorization = null;

    @Autowired
    private String defaultFrequencyInHours;

    @Autowired
    private EmailSender emailSender;

    private BlockingQueue<Job> jobQueue;
    private ExecutorService executorService;
    private List<Job> jobWorkingOrCompleted;

    ClaimsService(){
        jobQueue = new LinkedBlockingQueue<>();
        jobWorkingOrCompleted =  Collections.synchronizedList(new ArrayList<Job>());
        executorService = Executors.newFixedThreadPool(10);
        executorService.execute(new Runnable() {
            @Override
            public void run() {

                while (true) {
                    try {
                        Job job = jobQueue.take();
                        if (job.getStatus() != null && job.getStatus().equals(Job.STATUS.PENDING)) {
                            job.setStatus(Job.STATUS.WORKING);
                            synchronized (jobWorkingOrCompleted) {
                                jobWorkingOrCompleted.add(job);
                            }
                            logger.debug("accept job " + job.getId() + " " + job.getCreatedAt());
                            try {
                            if (job.getType() != null) {
                                if (job.getType().equals(Job.TYPE.CLAIM)) {
                                    addBulkClaims(job);
                                } else if (job.getType().equals(Job.TYPE.FEED)) {
                                    feedBulkRecords(job);
                                }
                            }
                            // Mark the job as completed
                            synchronized (jobWorkingOrCompleted) {
                                for (Job j : jobWorkingOrCompleted) {
                                    if (job.getId().equals(j.getId())) {
                                        j.setStatus(Job.STATUS.COMPLETE);
                                    }
                                }
                            }
                            logger.debug("complete job " + job.getId());
                            } catch (Exception e) {
                                logger.error("Exception working on a job: " + job.getId(), e);
                                synchronized (jobWorkingOrCompleted) {
                                    for (Job j : jobWorkingOrCompleted) {
                                        if (job.getId().equals(j.getId())) {
                                            j.setStatus(Job.STATUS.FAILED);
                                        }
                                    }
                                }
                                e.printStackTrace();
                            }
                        }
                        //clean old jobs
                        try {
                                for (int i = jobWorkingOrCompleted.size() - 1; i >= 0; i--) {
                                        Job j = jobWorkingOrCompleted.get(i);
                                        if (!j.getStatus().equals(Job.STATUS.PENDING) && j.isOld()) {
                                        jobWorkingOrCompleted.remove(j);
                                    }
                                }

                        }catch (Exception e){
                            logger.error( "Error cleaning up old jobs", e);
                            e.printStackTrace();
                        }

                    } catch(InterruptedException e){
                        logger.error("Thread interrupted exception", e);
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });
    }

    @GET
    @Path("jobStatus/{jobId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getJobStatus(@PathParam("jobId") String jobId,
                                 @CookieParam("openAIRESession") String  cookie) {
        if((cookie == null || cookie.isEmpty()) || (!authorization.isRegistered(cookie)  && !authorization.isClaimCurator(cookie))){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        synchronized (jobWorkingOrCompleted) {
            for (Job job : jobWorkingOrCompleted) {
                if (job.getId().equals(jobId)) {
                    return Response.status(Response.Status.OK).entity(composeMessage("success", "200", "Job status is " + job.getStatus(), null,
                                    new Gson().toJson(job)))
                            .type(MediaType.APPLICATION_JSON)
                            .build();
                }
            }
        }
        for (Job job : jobQueue) {
            if (job.getId().equals(jobId)) {
                return Response.status(Response.Status.OK).entity(composeMessage("success","200","Job status is "+ job.getStatus(), null,
                                new Gson().toJson(job)))
                        .type(MediaType.APPLICATION_JSON)
                        .build();
            }
        }
        return Response.status(Response.Status.NOT_FOUND).entity(composeMessage("error","404","Job not found"))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
    @GET
    @Path("getQueueStatus")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getQueueStatus() throws InterruptedException {
        if(jobQueue.size()>1){
            Thread.sleep(3000);
            if(jobQueue.size()>1){
                return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("The service may be stucked.")
                        .type(MediaType.TEXT_HTML)
                        .build();
            }
        }
        return  Response.status(Response.Status.OK).entity("OK")
                .type(MediaType.TEXT_HTML)
                .build();


    }
    @GET
    @Path("submitTestJob")
    @Produces(MediaType.APPLICATION_JSON)
    public Response submitTestJob( @HeaderParam("Origin") String origin,
                                   @CookieParam("openAIRESession") String  cookie) {
        if((cookie == null || cookie.isEmpty()) || (!authorization.isRegistered(cookie)  && !authorization.isClaimCurator(cookie))){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        Job  job = new Job();

        jobQueue.add(job);
        logger.debug("submit job " + job.getId());
        return Response.status(Response.Status.OK).entity("Job submitted: " + job.getId())
                .type(MediaType.TEXT_HTML)
                .build();
    }
    @GET
    @Path("jobsStatus")
    @Produces(MediaType.TEXT_HTML)
    public Response getJobsStatus( @HeaderParam("Origin") String origin,
                                   @CookieParam("openAIRESession") String  cookie) {
        if((cookie == null || cookie.isEmpty()) || (!authorization.isRegistered(cookie)  && !authorization.isClaimCurator(cookie))){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        Date d = new Date();

        String s;
        s = "Job  completed/ working size:" + jobWorkingOrCompleted.size() + "<br>";
        synchronized (jobWorkingOrCompleted) {
            for (Job job : jobWorkingOrCompleted) {
                s += job.getId() + " Job status: " + job.getStatus() + " " + job.getCreatedAt() + "<br>";
            }
        }
        s+= "Job size:" + jobQueue.size() + "<br>";
        s+= "remainingCapacity: "+ jobQueue.remainingCapacity() + "<br>";
        for (Job job : jobQueue) {
            s += job.getId() + " Job status: " + job.getStatus() +" " + job.getCreatedAt() +  "<br>";
        }
        s+="<br>" + d;
        return Response.status(Response.Status.OK).entity(s)
                .type(MediaType.TEXT_HTML)
                .build();
    }
    @Path("clearCompletedJobs")
    @Produces(MediaType.TEXT_HTML)
    public Response clearCompletedJobs( @HeaderParam("Origin") String origin,
                                   @CookieParam("openAIRESession") String  cookie) {
        if((cookie == null || cookie.isEmpty()) || (!authorization.isRegistered(cookie)  && !authorization.isClaimCurator(cookie))){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        String s = "";
        synchronized (jobWorkingOrCompleted) {
            Integer size = jobWorkingOrCompleted.size();
             s = "Job  completed/ working size:" + size + "<br>";
            jobWorkingOrCompleted.clear();

            s += "Cleared " + size + " jobs <br>" + new Date();
        }
        return Response.status(Response.Status.OK).entity(s)
                .type(MediaType.TEXT_HTML)
                .build();
    }
    @Path("clearPendingJobs")
    @Produces(MediaType.TEXT_HTML)
    public Response clearPendingJobs( @HeaderParam("Origin") String origin,
                                        @CookieParam("openAIRESession") String  cookie) {
        if((cookie == null || cookie.isEmpty()) || (!authorization.isRegistered(cookie)  && !authorization.isClaimCurator(cookie))){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        Integer size = jobQueue.size();
        String s = "Job  Queue size:" + size   +  "<br>";
        jobQueue.clear();

        s+="Cleared "+ size +" jobs <br> " + new Date();
        return Response.status(Response.Status.OK).entity(s)
                .type(MediaType.TEXT_HTML)
                .build();
    }
    @GET
    @Path("projects/{projectId}/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getProjectClaims(@PathParam("projectId") String projectId,
                                     @DefaultValue("0") @QueryParam("offset") int offset,
                                     @DefaultValue("20") @QueryParam("limit") int limit,
                                     @DefaultValue("") @QueryParam("keyword") String keyword,
                                     @DefaultValue("") @QueryParam("sortby") String orderby,
                                     @DefaultValue("true") @QueryParam("descending") boolean descending,
                                     @DefaultValue("") @QueryParam("types") List<String> types,
                                     
                                     @CookieParam("openAIRESession") String  cookie,
                                     @Context HttpServletRequest request) {

        if( cookie == null || cookie.isEmpty() ){
            authorization.logStatus(cookie);
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        if(authorization.isClaimCurator(cookie)) {

            int total = -1;

            if (projectId == null || projectId.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","Project id cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            List<Claim> claims = null;
            try {
                claims = fetchClaimHandler.fetchClaimsByProject(projectId, limit, offset, keyword, orderby, descending, types,false);
                total = fetchClaimHandler.countClaimsByProject(projectId, keyword, types);

            } catch (SQLStoreException|Exception e) {  //TODO check this with exception
                logger.error("Could not fetch claims for project with id " + projectId, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                        " for projects with id " + projectId + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();

            }

            return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
        }

        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
    @GET
    @Path("organizations/{organizationId}/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getOrganizationClaims(@PathParam("organizationId") String organizationId,
                                     @DefaultValue("0") @QueryParam("offset") int offset,
                                     @DefaultValue("20") @QueryParam("limit") int limit,
                                     @DefaultValue("") @QueryParam("keyword") String keyword,
                                     @DefaultValue("") @QueryParam("sortby") String orderby,
                                     @DefaultValue("true") @QueryParam("descending") boolean descending,
                                          @DefaultValue("false") @QueryParam("mine") boolean mine,
                                          @DefaultValue("") @QueryParam("types") List<String> types,

                                     @CookieParam("openAIRESession") String  cookie,
                                     @Context HttpServletRequest request) {

        if( cookie == null || cookie.isEmpty() ){
            authorization.logStatus(cookie);
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
//TODO add for organization managers
        if(authorization.isClaimCurator(cookie)) {
            UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
            String userMail = mine?userInfo.getEmail():null;

            int total = -1;

            if (organizationId == null || organizationId.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","organization id cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            List<Claim> claims = null;
            try {
                claims = fetchClaimHandler.fetchClaimsByOrganization(organizationId, limit, offset, keyword, orderby, descending, types,false, userMail);
                total = fetchClaimHandler.countClaimsByOrganization(organizationId, keyword, types, userMail);

            } catch (SQLStoreException|Exception e) {  //TODO check this with exception
                logger.error("Could not fetch claims for organization with id " + organizationId, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                        " for organization with id " + organizationId + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();

            }

            return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
        }

        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
    @GET
    @Path("projects/{projectId}/all_claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllProjectClaims(@PathParam("projectId") String projectId,
                                        @DefaultValue("-1") @QueryParam("offset") int offset,
                                        @DefaultValue("-1") @QueryParam("limit") int limit,
                                        @DefaultValue("") @QueryParam("keyword") String keyword,
                                        @DefaultValue("") @QueryParam("sortby") String orderby,
                                        @DefaultValue("true") @QueryParam("descending") boolean descending,
                                        @DefaultValue("") @QueryParam("types") List<String> types,
                                        
                                        @CookieParam("openAIRESession") String  cookie,
                                        @Context HttpServletRequest request) {
        if( cookie == null || cookie.isEmpty() ){
            authorization.logStatus(cookie);
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
//        if(authorization.isProjectCurator(userInfo)) {
        String userMail = userInfo.getEmail();

        int total = -1;

        if (projectId == null || projectId.isEmpty()) {
            return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","Project id cannot be empty."))
                    .type(MediaType.APPLICATION_JSON).build();
        }

        List<Claim> claims = null;
        try {
            boolean forbidden = true;
            if(authorization.isProjectCurator(userInfo)) {
                forbidden = false;
            } else {
                List<String> contact_emails = fetchProjectHandler.fetchContactEmailsByProjectId(projectId);
                logger.debug(contact_emails);
                if(contact_emails != null && contact_emails.contains(userMail)) {
                    forbidden = false;
                }
            }

            if(forbidden){
                return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                        .type(MediaType.APPLICATION_JSON)
                        .build();
            }else{
                if(offset == -1 && limit == -1) {
                    // when offset and limit are -1 fetch claims with null values, to ignore paging and limit clause
                    claims = fetchClaimHandler.fetchClaimsByProject(projectId, null, null, keyword, orderby, descending, types, true);
                } else {
                    claims = fetchClaimHandler.fetchClaimsByProject(projectId, limit, offset, keyword, orderby, descending, types, true);
                }
                total = fetchClaimHandler.countClaimsByProject(projectId, keyword, types);

                return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
            }

        } catch (SQLStoreException|Exception e) {
            logger.error("Could not fetch claims for project with id " + projectId, e);
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                    " for projects with id " + projectId + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();
        }
    }
/*
    @GET
    @Path("project/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getProjectClaimsBycookie(@QueryParam("projectcookie") String projectcookie,
                                     @DefaultValue("-1") @QueryParam("offset") int offset,
                                     @DefaultValue("-1") @QueryParam("limit") int limit,
                                     @DefaultValue("") @QueryParam("keyword") String keyword,
                                     @DefaultValue("") @QueryParam("sortby") String orderby,
                                     @DefaultValue("true") @QueryParam("descending") boolean descending,
                                     @DefaultValue("") @QueryParam("types") List<String> types,
                                     
                                     @CookieParam("openAIRESession") String  cookie,
                                     @Context HttpServletRequest request) {


        if( cookie == null || cookie.isEmpty() ){
            authorization.logStatus(cookie,cookie);
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
//        if(authorization.isProjectCurator(userInfo)) {
            String userMail = userInfo.getEmail();

            int total = -1;

            if (projectcookie == null || projectcookie.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","Project cookie cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            List<Claim> claims = null;
            try {
                String projectId = null;
                if(authorization.isProjectCurator(userInfo)) {
                    projectId = fetchProjectHandler.fetchProjectIdBycookie(projectcookie);
                } else {
                    projectId = fetchProjectHandler.fetchProjectIdBycookieAndEmail(projectcookie, userMail);
                }
                //String projectId = fetchProjectHandler.fetchProjectIdBycookie(projectcookie,userMail);
                if(projectId == null){
                    return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                            .type(MediaType.APPLICATION_JSON)
                            .build();
                }else{
                    if(offset == -1 && limit == -1) {
                        // when offset and limit are -1 fetch claims with null values, to ignore paging and limit clause
                        claims = fetchClaimHandler.fetchClaimsByProject(projectId, null, null, keyword, orderby, descending, types, true);
                    } else {
                        claims = fetchClaimHandler.fetchClaimsByProject(projectId, limit, offset, keyword, orderby, descending, types, true);
                    }
                    total = fetchClaimHandler.countClaimsByProject(projectId, keyword, types);

                    return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
                }

            } catch (SQLStoreException|Exception e) {
                logger.error("Could not fetch claims for project cookie " + projectcookie, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                        " for projects with cookie " + projectcookie + ".", e)).type(MediaType.APPLICATION_JSON).build();
            }
//        }

//        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
//                .type(MediaType.APPLICATION_JSON)
//                .build();
    }
*/

    @GET
    @Path("/contexts/{contextId}/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getContextClaims(@PathParam("contextId") String contextId,
                                     @DefaultValue("0") @QueryParam("offset") int offset,
                                     @DefaultValue("20") @QueryParam("limit") int limit,
                                     @DefaultValue("") @QueryParam("keyword") String keyword,
                                     @DefaultValue("") @QueryParam("sortby") String orderby,
                                     @DefaultValue("true") @QueryParam("descending") boolean descending,
                                     @DefaultValue("false") @QueryParam("mine") boolean mine,
                                     @DefaultValue("") @QueryParam("types") List<String> types,
                                     
                                     @CookieParam("openAIRESession") String  cookie,
                                     @Context HttpServletRequest request) {
        if( cookie == null || cookie.isEmpty() ){
            authorization.logStatus(cookie);
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if(authorization.isCommunityCurator(userInfo) || authorization.isClaimCurator(cookie) || this.emailSender.getManagerUtils().isCommunityManager(contextId, userInfo.getEmail() )) {
            String userMail = mine?userInfo.getEmail():null;
            int total = -1;
            if (contextId == null || contextId.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","Context id cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }
            logger.debug("Types are " + types);
            List<Claim> claims = null;

            try {
                claims = fetchClaimHandler.fetchClaimsByContext(contextId, limit, offset, keyword, orderby, descending, types,false, userMail);
                total = fetchClaimHandler.countClaimsByContext(contextId, keyword, types, userMail);

            } catch (SQLStoreException|Exception e) {
                logger.error("Could not fetch claims for context with id " + contextId, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                        " for context with id " + contextId + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();
            }

            return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
        }

        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }


    @GET
    @Path("/results/{resultId}/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getResultClaims(@PathParam("resultId") String resultId,
                                    @DefaultValue("0") @QueryParam("offset") int offset,
                                    @DefaultValue("20") @QueryParam("limit") int limit,
                                    @DefaultValue("") @QueryParam("keyword") String keyword,
                                    @DefaultValue("") @QueryParam("sortby") String orderby,
                                    @DefaultValue("true") @QueryParam("descending") boolean descending,
                                    @DefaultValue("") @QueryParam("types") List<String> types,
                                    
                                    @CookieParam("openAIRESession") String  cookie,
                                    @Context HttpServletRequest request) {


        if( cookie == null || cookie.isEmpty() ){
            authorization.logStatus(cookie);
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        if(authorization.isClaimCurator(cookie)) {

            int total = -1;
            if (resultId == null || resultId.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","Context id cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            List<Claim> claims = null;
            try {
                claims = fetchClaimHandler.fetchClaimsByResult(resultId, limit, offset, keyword, orderby, descending, types,false);
                total = fetchClaimHandler.countClaimsByResult(resultId, keyword, types);

            } catch (SQLStoreException|Exception e) {
                logger.error("Could not fetch claims for result with id " + resultId, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                        " for result with id " + resultId + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();
            }

            return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
        }

        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }


    @GET
    @Path("/users/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getUserClaims(@DefaultValue("0") @QueryParam("offset") int offset,
                                  @DefaultValue("20") @QueryParam("limit") int limit,
                                  @DefaultValue("") @QueryParam("keyword") String keyword,
                                  @DefaultValue("") @QueryParam("sortby") String orderby,
                                  @DefaultValue("true") @QueryParam("descending") boolean descending,
                                  @DefaultValue("") @QueryParam("types") List<String> types,
                                  
                                  @CookieParam("openAIRESession") String  cookie,
                                  @Context HttpServletRequest request) {
        logger.error( " " + cookie +" " +request.getCookies().length + " " );


        if( cookie == null || cookie.isEmpty() ){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if(authorization.isRegistered(userInfo)) {
            String userMail = userInfo.getEmail();
            logger.debug("User is registerd "  );
            int total = -1;
            EmailValidator emailValidator = EmailValidator.getInstance();

            if (userMail == null || userMail.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            if (!emailValidator.isValid(userMail)) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail is not valid."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            List<Claim> claims = null;
            try {
                logger.debug("About to fetch claims"  );
                claims = fetchClaimHandler.fetchClaimsByUser(userMail, limit, offset, keyword, orderby, descending, types,false);
                total = fetchClaimHandler.countClaimsByUser(userMail, keyword, types);

            } catch (SQLStoreException|Exception e) {
                logger.error("Could not fetch claims for user with mail " + userMail, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims" +
                        " for user with e-mail " + userMail + ".", e.getMessage(),null)).type(MediaType.APPLICATION_JSON).build();
            }

            return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();
        }
        logger.debug("User is *NOT* registerd "  );
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    @GET
    @Path("/claims/{claimId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getClaimsById(@PathParam("claimId") String claimId,
                                  @DefaultValue("0") @QueryParam("offset") int offset,
                                  @DefaultValue("20") @QueryParam("limit") int limit,
                                  
                                  @CookieParam("openAIRESession") String  cookie,
                                  @Context HttpServletRequest request) {


        if( cookie == null || cookie.isEmpty() ){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        if(authorization.isRegistered(cookie)) {

            List<Claim> claims = null;

            int total = -1;
            if (claimId == null || claimId.isEmpty()) {
                try {
                    claims = fetchClaimHandler.fetchAllClaims(limit, offset,false, null);
                    total = fetchClaimHandler.countAllClaims("", new ArrayList<String>(), null);

                    return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).type(MediaType.APPLICATION_JSON).build();

                } catch (SQLStoreException|Exception e) {
                    logger.error("Could not fetch claims.", e);
                    return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims.", e.getMessage(),null))
                            .type(MediaType.APPLICATION_JSON).build();
                }
            }

            try {
                Claim claim = fetchClaimHandler.fetchClaimById(claimId,false);
                if (claim == null) {
                    return Response.status(Response.Status.NOT_FOUND).entity(composeMessage("error","404","Cannot find claim with id " + claimId + "."))
                            .type(MediaType.APPLICATION_JSON).build();
                }

                return Response.status(200).entity(composeDataResponse(claim)).build();

            } catch (SQLStoreException|Exception e) {
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claim " +
                        "with id " + claimId + " id.", e.getMessage(),null)).type(MediaType.APPLICATION_JSON).build();
            }
        }
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    @GET
    @Path("/claims")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllClaims(@DefaultValue("0") @QueryParam("offset") int offset,
                                 @DefaultValue("20") @QueryParam("limit") int limit,
                                 @DefaultValue("") @QueryParam("keyword") String keyword,
                                 @DefaultValue("date") @QueryParam("sortby") String orderby,
                                 @DefaultValue("true") @QueryParam("descending") boolean descending,
                                 @DefaultValue("false") @QueryParam("mine") boolean mine,
                                 @DefaultValue("") @QueryParam("types") List<String> types,
                                 
                                 @HeaderParam("Origin") String origin,
                                 @CookieParam("openAIRESession") String  cookie,
                                 @Context HttpServletRequest request) {


        logger.debug("Header  \"Origin\" has value  " + origin);



        if( cookie == null || cookie.isEmpty() ){
            logger.debug("User is not  authorized - Eroor 403");

            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        if(authorization.isClaimCurator(cookie)) {
            UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
            String userMail = mine?userInfo.getEmail():null;
            logger.debug("User is authorized ! !");
            List<Claim> claims = null;

            int total = -1;
            try {
                claims = fetchClaimHandler.fetchAllClaims(limit, offset, keyword, orderby, descending, types,false, userMail);
                total = fetchClaimHandler.countAllClaims(keyword, types, userMail);

                return Response.status(200).entity(composeDataResponse(request, claims, total, offset, limit)).build();

            } catch (SQLStoreException|Exception e) {
                logger.error("Could not fetch claims.", e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to fetch claims.", e.getMessage(), null))
                        .type(MediaType.APPLICATION_JSON).build();
            }
        }

        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access"))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    @DELETE
    @Path("/claims/bulk")
    @Produces(MediaType.APPLICATION_JSON)
    public Response deleteBulkClaims(@QueryParam("claimId") List<String> claimIds,
                                     
                                     @HeaderParam("Origin") String origin,
                                     @CookieParam("openAIRESession") String  cookie){



        if(!authorization.hasBasicAuthorization(origin, cookie)){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }


        ArrayList<String> deletedIds= new ArrayList<String>();
        ArrayList<String> notFoundIds= new ArrayList<String>();

        if (claimIds == null || claimIds.size() == 0) {
            return Response.status(Response.Status.NOT_FOUND).entity(composeMessage("error", "404","Claim ids cannot be empty."/*,deletedIds,notFoundIds*/))
                    .type(MediaType.APPLICATION_JSON).build();
        }

        logger.debug("Trying to delete claims with ids: " + claimIds.toString() + ".");
        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        for (String claimId : claimIds) {
            try {

                if (authorization.isRegistered(userInfo)) {
                    if (authorization.isClaimCurator(userInfo) || authorization.isCommunityCurator(userInfo) || userInfo.getEmail().equals(fetchClaimHandler.fetchClaimById(claimId,false).getUserMail())) {
                        if (claimHandler.deleteClaim(claimId)) {
                            //TODO check if we should delete the record file
                            deletedIds.add(claimId);
                        } else {
                            notFoundIds.add(claimId);
                        }
                    } else {
                        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to delete."))
                                .type(MediaType.APPLICATION_JSON)
                                .build();
                    }
                } else {
                    return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                            .type(MediaType.APPLICATION_JSON)
                            .build();
                }
            } catch (SQLStoreException|Exception e) {
                logger.error("Fail to delete claim with id " + claimId + ".", e);
                notFoundIds.add(claimId);
            }
        }
        logger.debug("Successfully deleted " + deletedIds.size() + " from " + claimIds.size()  +". Deleted claims with ids: " + deletedIds.toString() + ".");
        if (claimIds.size() == notFoundIds.size()) {
            return Response.status(Response.Status.NOT_FOUND).entity(composeMessage("error","404","Claim ids cannot be empty."/*,deletedIds,notFoundIds*/))
                    .type(MediaType.APPLICATION_JSON).build();
        } else if (claimIds.size() == notFoundIds.size()) {
            return Response.status(204).entity(compose204BulkDeleteMessage(deletedIds,notFoundIds)).type(MediaType.APPLICATION_JSON).build();
        } else {
            return Response.status(204).entity(compose204BulkDeleteMessage(deletedIds,notFoundIds)).type(MediaType.APPLICATION_JSON).build();
        }
    }

    @POST
    @Path("/claims")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response addClaim(String input, @Context HttpServletRequest request,
                             
                             @HeaderParam("Origin") String origin,
                             @CookieParam("openAIRESession") String  cookie) {


        if(!authorization.hasBasicAuthorization(origin, cookie)){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if(authorization.isRegistered(userInfo)) {
            JsonObject jsonObject = new JsonParser().parse(input).getAsJsonObject();

            String claimedBy = userInfo.getEmail();
            logger.info("claimedBy " + claimedBy);

            EmailValidator emailValidator = EmailValidator.getInstance();
            if (!emailValidator.isValid(claimedBy)) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail is invalid."))
                        .type(MediaType.APPLICATION_JSON).build();
            }


            try {
                String claimId = this.getInfoAndBuildClaim(jsonObject,claimedBy);
                return Response.status(200).entity(compose201PostMessage(request, claimId)).type(MediaType.APPLICATION_JSON).build();

            } catch (ClaimValidationException ve) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","The given ids are wrong.", ve.getMessage(), null))
                        .type(MediaType.APPLICATION_JSON).build();

            } catch (SQLStoreException|Exception e) {
                logger.error("Fail to add new claim.", e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","403","Fail to add new claim.", e.getMessage(), null))
                        .type(MediaType.APPLICATION_JSON).build();
            }
        }
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access."))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    @POST
    @Path("/claims/bulk")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createBulkClaimsJob(String input, @Context HttpServletRequest request,
                                  @HeaderParam("Origin") String origin,
                                  @CookieParam("openAIRESession") String  cookie) {
        if(!authorization.hasBasicAuthorization(origin, cookie)){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if(authorization.isRegistered(userInfo)) {
          Job job = new Job();

            job.setType(Job.TYPE.CLAIM);
            job.setInputArray(new JsonParser().parse(input).getAsJsonArray());
            job.setUser(userInfo.getEmail());
            jobQueue.add(job);
            logger.debug("submit job " + job.getId());
            return Response.status(200).entity(composeMessage("success","200","job submitted!", null, new Gson().toJson(job))).type(MediaType.APPLICATION_JSON).build();

        }
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                .type(MediaType.APPLICATION_JSON)
                .build();

    }
    private void addBulkClaims(Job job) {

        int code200 = 0;
        int code400 = 0;
        int code500 = 0;

        for (JsonElement je : job.getInputArray()) {
            JsonObject jsonObject = je.getAsJsonObject();
            EmailValidator emailValidator = EmailValidator.getInstance();
            if (!emailValidator.isValid(job.getUser())) {
                jsonObject.addProperty("error", "user");
                logger.error("no valid user");
                code400++;
                job.getErrorInClaims().add(jsonObject);
            }
            try {
                String claimId = this.getInfoAndBuildClaim(jsonObject, job.getUser());
                job.getInsertedIds().add(claimId);
                code200++;

            } catch (ClaimValidationException ve) {
                jsonObject.addProperty("error", "validation");
                job.getErrorInClaims().add(jsonObject);
                code400++;

            } catch (SQLStoreException | Exception e) {
                logger.error("Fail to add new claim.", e);
                jsonObject.addProperty("error", "insertion");
                job.getErrorInClaims().add(jsonObject);
                code500++;
            }
        }
        if (job.getInputArray().size() == code500) {
            job.setCode(500);
            job.setMessage("Fail to add new claims");
        } else if (code200 > 0) {
            job.setCode(200);
            job.setMessage("ok");
        } else {
            job.setCode(400);
            job.setMessage("claims not saved for some ids");
        }


    }
    @POST
    @Path("/curate/bulk")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response curateBulkClaims(String input, @Context HttpServletRequest request,
                                     
                                     @HeaderParam("Origin") String origin,
                                     @CookieParam("openAIRESession") String  cookie) {


        if(!authorization.hasBasicAuthorization(origin, cookie)){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if (authorization.isRegistered(userInfo)) {
            ArrayList<String> insertedIds = new ArrayList<String>();
            JsonArray errorInClaims = new JsonArray();
            int code200 = 0;
            int code400 = 0;
            int code500 = 0;
            JsonArray jsonArray = new JsonParser().parse(input).getAsJsonArray();
            String curatedBy =userInfo.getEmail();

            for (JsonElement je : jsonArray) {
                JsonObject jsonObject = je.getAsJsonObject();

                String id = jsonObject.get("id").getAsString();
                logger.info("id " + id);

                Boolean approved = jsonObject.get("approved").getAsBoolean();
                logger.info("approved " + approved);
                EmailValidator emailValidator = EmailValidator.getInstance();
                if (!emailValidator.isValid(curatedBy)) {
                    jsonObject.addProperty("error", "user");
                    //                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail is invalid."))
                    //                        .type(MediaType.APPLICATION_JSON).build();
                    code400++;
                    errorInClaims.add(jsonObject);
                }

                try {
                    claimHandler.updateClaimCurationInfo(curatedBy,id, approved);
                    insertedIds.add(id);
                    code200++;

                } catch (SQLStoreException|Exception e) {
                    jsonObject.addProperty("error", "insertion");
                    errorInClaims.add(jsonObject);
                    code500++;
                }
            }
            if (jsonArray.size() == code500) {
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","500","Fail to update claims."/*, insertedIds, errorInClaims*/))
                        .type(MediaType.APPLICATION_JSON).build();
            } else if (code200 > 0) {
                return Response.status(200).entity(compose201BulkInsertMessage(insertedIds, errorInClaims)).type(MediaType.APPLICATION_JSON).build();
            } else {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","404","The given ids are wrong."/*, insertedIds, errorInClaims*/))
                        .type(MediaType.APPLICATION_JSON).build();
            }
        }
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                .type(MediaType.APPLICATION_JSON)
                .build();

    }
    @POST
    @Path("/feed/bulk")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createBulkRecordsJob(String input, @Context HttpServletRequest request,
                                    @HeaderParam("Origin") String origin,
                                    @CookieParam("openAIRESession") String  cookie) {

        if(!authorization.hasBasicAuthorization(origin, cookie)){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        if (authorization.isRegistered(cookie)) {
            Job  job = new Job();
            job.setType(Job.TYPE.FEED);
            job.setInputArray(new JsonParser().parse(input).getAsJsonArray());
            jobQueue.add(job);
            logger.debug("submit job " + job.getId());
            return Response.status(200).entity(composeMessage("success","200","job submitted!", null, new Gson().toJson(job))).type(MediaType.APPLICATION_JSON).build();
        }
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                .type(MediaType.APPLICATION_JSON)
                .build();

    }
    private void feedBulkRecords(Job job) {

            int code200 = 0;
            int code400 = 0;
            int code500 = 0;
            for (JsonElement je : job.getInputArray()) {
                JsonObject jsonObject = je.getAsJsonObject();
                Boolean inserted = directIndexHandler.insertRecord(new Gson().toJson(jsonObject.get("record")));
                if (inserted) {
                    job.getInsertedIds().add(jsonObject.get("id").getAsString());
                    code200++;
                } else {
                    job.getErrorInClaims().add(jsonObject.get("id").getAsString());
                    code400++;
                }


            }
            if (job.getInputArray().size() == code500) {
                job.setCode(500);
                job.setMessage("Fail to add new claims");
            } else if (code200 > 0) {
                job.setCode(200);
                job.setMessage("ok");
            } else {
                job.setCode(400);
                job.setMessage("some records couldn't be saved");
            }
    }

    @GET
    @Path("/users/notification")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getUserEmailNotificationPreferences(@QueryParam("communityId") String openaireId,
                                                        
                                                        @CookieParam("openAIRESession") String  cookie,
                                                        @Context HttpServletRequest request) {

        if( cookie == null || cookie.isEmpty() ){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }

        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if(authorization.isRegistered(userInfo)) {
            String userMail = userInfo.getEmail();
            logger.debug("User is registerd "  );

            EmailValidator emailValidator = EmailValidator.getInstance();

            if (userMail == null || userMail.isEmpty()) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail cannot be empty."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            if (!emailValidator.isValid(userMail)) {
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail is not valid."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            List<Notification> notifications = null;
            try {
                if(openaireId != null) {
//                    CommunityUtils communityInfo = this.emailSender.getCommunityUtils().getCommunityInfo(openaireId);
                    if(this.emailSender.getManagerUtils().isCommunityManager(openaireId, userMail) || authorization.isCommunityCurator(userInfo)) {

                        Notification notification = null;
                        logger.debug("About to fetch notification");
                        notification = fetchNotificationHandler.fetchNotification(openaireId, userMail);

                        if (notification != null) {
                            notifications = new ArrayList<Notification>();
                            notification.setOpenaireName(openaireId);
                            notifications.add(notification);
                        }
                    }else{
                        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                                .type(MediaType.APPLICATION_JSON)
                                .build();
                    }
                } else {
                    Map<String, String> projectIdsAndNames = fetchProjectHandler.fetchProjectIdsAndNamesByProjectManagerMail(userMail);
                    if(projectIdsAndNames != null) {
                        for (Map.Entry<String, String> projectIdAndName : projectIdsAndNames.entrySet()) {
                            Notification notification = null;
                            logger.debug("About to fetch notification");
                            notification = fetchNotificationHandler.fetchNotification(projectIdAndName.getKey(), userMail);

                            if (notifications == null) {
                                notifications = new ArrayList<Notification>();
                            }
                            if(notification == null) {
                                notification = new Notification(projectIdAndName.getKey(), projectIdAndName.getValue(), userMail, Integer.parseInt(defaultFrequencyInHours), true);
                            } else {
                                notification.setOpenaireName(projectIdAndName.getValue());
                            }
                            notifications.add(notification);
                            logger.debug(notification);
                            logger.debug("notification openaireId:"+notification.getOpenaireId());
                            logger.debug(notifications.size());
                        }
                    }
                }

            } catch (SQLStoreException|Exception e) {
                logger.error("Could not fetch notification preferences for user with mail " + userMail, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("error","403","Fail to fetch notification preferences" +
                        " for user with e-mail " + userMail + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();
            }

            if (notifications == null || notifications.isEmpty()) {
                return Response.status(Response.Status.NOT_FOUND).entity(composeMessage("error","404","There are no notifications for user with mail " + userMail)).type(MediaType.APPLICATION_JSON).build();
            }

            return Response.status(200).entity(composeDataResponse(notifications)).build();

        }
        logger.debug("User is *NOT* registerd "  );
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    @POST
    @Path("/users/notification/save")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response saveOrUpdateUserEmailNotificationPreferences(String input, @Context HttpServletRequest request,
                                                                 
                                                                 @HeaderParam("Origin") String origin,
                                                                 @CookieParam("openAIRESession") String  cookie) {


        if(!authorization.hasBasicAuthorization(origin, cookie)){
            return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. Maybe you are not registered."))
                    .type(MediaType.APPLICATION_JSON)
                    .build();
        }
        UserInfo userInfo = authorization.getUserHandler().getUserInfo(cookie);
        if (authorization.isRegistered(userInfo)) {
            ArrayList<String> insertedIds = new ArrayList<String>();
            JsonArray errorInClaims = new JsonArray();
            int code200 = 0;
            int code400 = 0;
            int code500 = 0;
            JsonObject jsonObject = new JsonParser().parse(input).getAsJsonObject();

            String userMail =userInfo.getEmail();

            String openaireId = jsonObject.get("openaireId").getAsString();
            logger.info("openaireId " + openaireId);

            boolean notify = jsonObject.get("notify").getAsBoolean();
            logger.info("notify "+notify);

            int frequency = jsonObject.get("frequency").getAsInt();
            logger.info("frequency " + frequency);

            EmailValidator emailValidator = EmailValidator.getInstance();
            if (!emailValidator.isValid(userMail)) {
                jsonObject.addProperty("error", "user");
                return Response.status(Response.Status.BAD_REQUEST).entity(composeMessage("error","400","User e-mail is invalid."))
                        .type(MediaType.APPLICATION_JSON).build();
            }

            try {
                boolean continueProcedure = false;
                List<String> managers = null;
                try {
                    managers = fetchProjectHandler.fetchContactEmailsByProjectId(openaireId);
                } catch (Exception e) {
                    e.printStackTrace();
                } catch (SQLStoreException e) {
                    e.printStackTrace();
                }
                if(managers != null && managers.contains(userMail)) {
                    continueProcedure = true;
                } else {
//                    CommunityUtils communityInfo = this.emailSender.getCommunityUtils().getCommunityInfo(openaireId);
                    if(this.emailSender.getManagerUtils().isCommunityManager(openaireId, userMail) || authorization.isCommunityCurator(userInfo) ) {
                        continueProcedure = true;
                    }
                }

                if(continueProcedure) {
                    Notification notification = null;
                    logger.debug("About to fetch notification");
                    notification = fetchNotificationHandler.fetchNotification(openaireId, userMail);

                    if (notification == null) {
                        logger.debug("About to insert notification");
                        notificationHandler.buildAndInsertNotification(openaireId, userMail, frequency, notify);
                    } else {
                        logger.debug("About to update notification");
                        notificationHandler.updateNotificationPreferences(openaireId, userMail, frequency, notify);
                    }
                } else {
                    return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered."))
                            .type(MediaType.APPLICATION_JSON)
                            .build();
                }
            } catch (SQLStoreException|Exception e) {
                logger.error("Could not save or update notification preferences for user with mail " + userMail, e);
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(composeMessage("fail","500","Fail to fetch notification preferences" +
                        " for user with e-mail " + userMail + ".", e.getMessage(), null)).type(MediaType.APPLICATION_JSON).build();
            }

            return Response.status(200).entity(composeMessage("ok","200","Save or Update for notification successful", null, null)).type(MediaType.APPLICATION_JSON).build();
        }
        return Response.status(Response.Status.FORBIDDEN).entity(composeMessage("error","403","Forbidden: You don't have permission to access. You are not registered.", null,null))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    private String xml2Json(List<String> input) {
        StringBuilder builder = new StringBuilder();
        for(String category: input) {
            builder.append(category);
        }
        return builder.toString();
    }
    private String composeMessage(String status,String code, String message) {
        return composeMessage(status,code,message, null, null);
    }
    private String composeMessage(String status,String code, String message, String description, String data) {
        return  "{ \"status\" : \"" + status + "\", \"code\" : \"" + code + "\", \"message\" : \"  " + message +" \"" +
                (description !=null?(", \"description\" : \"" + description  +" \""):"") +
        (data !=null?(", \"data\" : " + data  +""):"")
                + " }";
    }
     private  String compose204BulkDeleteMessage(List<String> deletedIds, List<String> notFoundIds){
        return " { \"status\" : \"success\", \"code\": \"204\", "+ "\"deletedIds\" : " + new Gson().toJson(deletedIds) +","+  "\"notFoundIds\" : " + new Gson().toJson(notFoundIds) + "}";
    }


    private  String compose201PostMessage(@Context HttpServletRequest request, String claimId){
        String url = request.getRequestURL().toString();
        //String query = request.getQueryString();

        return " { \"status\" : \"success\", \"code\": \"201\", \"link\": \"" + url  +"/"+ claimId +"\" }";
    }
    private  String compose201BulkInsertMessage(List<String> insertedIds, JsonArray errorInClaims){
        //String url = request.getRequestURL().toString();
        //String query = request.getQueryString();

        return " { \"status\" : \"success\", \"code\": \"201\","+ "\"insertedIds\" : " + new Gson().toJson(insertedIds) +","+  "\"errorInClaims\" : " + new Gson().toJson(errorInClaims)+ "}";
    }
    private String composeDataResponse(HttpServletRequest request, List<Claim> claims, int total, int offset, int limit) {
        if(offset != -1 && limit != -1) {   // if offset and limit are -1, no paging in the response
            return " { \"status\" : \"success\", \"code\": \"200\",  "+composeTotalResults(total)+", " + composePaging(request, total, offset, limit) + ", "
                    + "\"data\" : " + new Gson().toJson(claims) + " }";
        } else {
            return " { \"status\" : \"success\", \"code\": \"200\",  "+composeTotalResults(total)+", "
                    + "\"data\" : " + new Gson().toJson(claims) + " }";
        }
    }

    private String composeDataResponse(String xml) {
        return " { \"status\" : \"success\", \"code\": \"200\", "
                + "\"data\" : " + XML.toJSONObject(xml).toString() + " }";
    }

    private String composeDataResponse(Claim claim) {
        return " { \"status\" : \"success\", \"code\": \"200\", " + "\"data\" : " + new Gson().toJson(claim) + " }";
    }

    private String composeDataResponse(List<Notification> notifications) {
        return " { \"status\" : \"success\", \"code\": \"200\", " + "\"data\" : " + new Gson().toJson(notifications) + " }";
    }

    private static String composePaging(HttpServletRequest request, int total, int currentOffset, int limit) {
        logger.info("total " + total);
        logger.info("currentOffset " + currentOffset);
        logger.info("limit " + limit);

        String url = request.getRequestURL().toString();
        //String query = request.getQueryString();

        String first = url+"?offset=0&limit=20";

        int previousPage;
        int nextPage;
        int lastPage;

        if (total <= limit) {
            lastPage = 0;
        } else {
            if(total%limit == 0) {
                lastPage = total/limit-1;
            } else {
                lastPage = total/limit ;
            }
        }
        String last = url+"?offset=" + lastPage + "&limit=20";

        if (currentOffset-1 <= 0) {
            previousPage = 0;
        } else {
            previousPage = currentOffset-1;
        }
        String previous = url+"?offset=" + previousPage + "&limit=20";

        if (currentOffset+1 >= lastPage) {
            nextPage = lastPage;

        } else {
            nextPage = currentOffset + 1;
        }
        String next = url+"?offset=" + nextPage + "&limit=20";

        return "\"paging\": [" +  "{\"rel\":\"first\", \"href\":\"" + first +"\"}, {\"rel\":\"last\", \"href\":\"" + last + "\"}, {\"rel\":\"previous\", \"href\": \"" + previous + "\"}, {\"rel\":\"next\", \"href\":\"" +  next +"\"}"+ "]";
    }
    private String composeTotalResults(int total) {
        return "\"total\": \""+total+"\"";
    }

    public static void main(String[] args) {

/*
         EmailValidator emailValidator = EmailValidator.getInstance();
         System.out.println(emailValidator.isValid("jate@gdddd"));

         InternetAddress emailAddr = null;
         try {
             emailAddr = new InternetAddress("jate@gdddd");
             emailAddr.validate();
         } catch (AddressException e) {
             System.out.println("false");
         }
         System.out.println("true");

         ArrayList<String> insertedIds= new ArrayList<String>();
         insertedIds.add("1");
         insertedIds.add("2");
         insertedIds.add("3");
         System.out.println(helloWorldService.composeMessage("error","403","hello"));

*/
//         BasicConfigurator.configure();
//         ApplicationContext context = new ClassPathXmlApplicationContext("eu/dnetlib/openaire/rest/springContext-claims-authorization.xml");
//
//         Authorization authorization =  context.getBean(Authorization.class);
//         UserHandler userHandler = context.getBean(UserHandler.class);
//         System.out.println(authorization.getAdminRoles());
//         authorization.isClaimCurator("eyJraWQiOiJvaWRjIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwOTMxNzMwMTMyODMzNjMyQG9wZW5taW50ZWQuZXUiLCJhenAiOiIyNGU4MzE3Ni0xMzEyLTRiYTMtYmMwYi1mZmVlYmVhMTYwM2UiLCJpc3MiOiJodHRwczpcL1wvYWFpLm9wZW5taW50ZWQuZXVcL29pZGNcLyIsImV4cCI6MTQ5ODQ4NTk3NiwiaWF0IjoxNDk4NDcxNTc2LCJqdGkiOiJkMWRlZjc1Yi00MTEyLTRiZDktYTIyNi0wZThhOWI2M2Y3MWQifQ.WVYOb_yO8OaxIIt2jRYEDQBhGGFRDTBw3DgtVV_smuN5yx1ScCj6aehLu3JKPSArme4m2SGF4TEGhpwNJkwhM2WapGtxmtuCmCzYIo_QlC1Yki9hr2OT2rXMcQsJCiKaBSf6pLue6Sn78GMB5yaUTvOQHRgidXGiZXH5lsuZUx15Q6Equ_wzond_rgP9mRheRkTyIFuvvg4PuzmudBc11Ty863vIIQtoWF7_p98zTbHxiNF9lLPwzPZKxDoQ8JeayQEC-jsWVLgxmp-h0jG_Ko5jFVVJeeosqMMucOrs2FT_NKHVYVqB6VVh0C6nOufeiLrNDeMUlDT4dAvKD2zE9w");

    }

//    @GET
//    @Path("email-notifications")
//    public void forceSendEmailNotifications() {
//        emailSender.run();
//    }

    @GET
    @Path("test-email")
    public void testEmail() {
        ArrayList<String> list = new ArrayList<String>();
        list.add("konstantinagalouni@gmail.com");
        list.add("argirok@di.uoa.gr");
        emailSender.send("openaire_id_test", "openaire_name_test", "community", list);
    }

    private String getvalueOf(JsonObject jsonObject, String field){
        String value = (jsonObject.get(field) != null && !jsonObject.get(field).isJsonNull())?jsonObject.get(field).getAsString():null;
        logger.info(field + ": " + value);
        return value;


    }
    private String getvalueOfDefault(JsonObject jsonObject, String field, String defaultValue){
        String value = this.getvalueOf(jsonObject, field);
        logger.debug("Field:"+field+"->"+value+"<-");
        return (value!=null && !value.equals("")?value:defaultValue);
    }

    private String getInfoAndBuildClaim(JsonObject jsonObject, String claimedBy ) throws SQLStoreException, Exception {
        String claimedInDashboard = getvalueOfDefault(jsonObject, "claimedInDashboard", null);

        String sourceId = getvalueOf(jsonObject, "sourceId");
        String sourceType = getvalueOf(jsonObject, "sourceType");
        String sourceCollectedFrom = getvalueOf(jsonObject, "sourceCollectedFrom");
        String sourceAccessRights = getvalueOf(jsonObject, "sourceAccessRights");
        String sourceEmbargoEndDate = getvalueOfDefault(jsonObject, "sourceEmbargoEndDate", null);

        String targetId = getvalueOf(jsonObject, "targetId");
        String targetType = getvalueOf(jsonObject, "targetType");
        String targetCollectedFrom = getvalueOf(jsonObject, "targetCollectedFrom");
        String targetAccessRights = getvalueOf(jsonObject, "targetAccessRights");
        String targetEmbargoEndDate = getvalueOfDefault(jsonObject, "targetEmbargoEndDate", null);

        String idSuffix = getvalueOfDefault(jsonObject, "idSuffix", "");


        logger.debug("Claimed in"+claimedInDashboard);
        return claimHandler.buildAndInsertClaim(claimedBy, sourceType, sourceId, sourceCollectedFrom, sourceAccessRights, sourceEmbargoEndDate, targetType, targetId, targetCollectedFrom, targetAccessRights, targetEmbargoEndDate,claimedInDashboard, idSuffix);
    }
    
  
}
