package org.xcolab.client.proposals;
import org.springframework.core.ParameterizedTypeReference;
import org.xcolab.client.activities.ActivitiesClient;
import org.xcolab.client.contest.ContestClient;
import org.xcolab.client.contest.exceptions.ContestNotFoundException;
import org.xcolab.client.contest.pojo.Contest;
import org.xcolab.client.contest.pojo.ContestType;
import org.xcolab.client.contest.pojo.phases.ContestPhase;
import org.xcolab.client.members.pojo.Member;
import org.xcolab.client.proposals.exceptions.ProposalNotFoundException;
import org.xcolab.client.proposals.pojo.Proposal;
import org.xcolab.client.proposals.pojo.ProposalDto;
import org.xcolab.client.proposals.pojo.ProposalVersion;
import org.xcolab.client.proposals.pojo.ProposalVersionDto;
import org.xcolab.client.proposals.pojo.group.GroupDto;
import org.xcolab.client.proposals.pojo.group.Group_;
import org.xcolab.client.proposals.pojo.tiers.ProposalReference;
import org.xcolab.client.proposals.pojo.tiers.ProposalReferenceDto;
import org.xcolab.util.clients.CoLabService;
import org.xcolab.util.enums.activity.ActivityEntryType;
import org.xcolab.util.exceptions.ReferenceResolutionException;
import org.xcolab.util.http.caching.CacheKeys;
import org.xcolab.util.http.caching.CacheName;
import org.xcolab.util.http.client.RestResource;
import org.xcolab.util.http.client.RestResource1;
import org.xcolab.util.http.client.RestService;
import org.xcolab.util.http.client.types.TypeProvider;
import org.xcolab.util.http.dto.DtoUtil;
import org.xcolab.util.http.exceptions.EntityNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class ProposalClient {
private static final Map<RestService, ProposalClient> instances = new HashMap<>();
private final RestService proposalService;
private final RestResource<ProposalDto, Long> proposalResource;
private final RestResource<Long, Long> proposalThreadIdResource;
private final RestResource<Long, Long> proposalIdResource;
private final RestResource1<ProposalVersionDto, Long> proposalVersionResource;
private final RestResource1<ProposalReferenceDto, Long> proposalReferenceResource;
private final RestResource<GroupDto, Long> groupResource;
//TODO: methods that use this should be in the service!
private final ContestClient contestClient;
private final ActivitiesClient activitiesClient;
private ProposalClient(RestService proposalService) {
this.proposalService = proposalService;
proposalResource = new RestResource1<>(
proposalService, "proposals", ProposalDto.TYPES);
proposalIdResource = new RestResource1<>(
proposalService, "proposalIds", new TypeProvider<>(Long.class,
new ParameterizedTypeReference<List<Long>>() {
})
);
proposalThreadIdResource = new RestResource1<>(
proposalService, "proposalThreadIds", new TypeProvider<>(Long.class,
new ParameterizedTypeReference<List<Long>>() {
})
);
proposalVersionResource = new RestResource1<>(proposalService,
"proposalVersions", ProposalVersionDto.TYPES);
proposalReferenceResource = new RestResource1<>(proposalService,
"proposalReference", ProposalReferenceDto.TYPES);
groupResource = new RestResource1<>(proposalService, "groups", GroupDto.TYPES);
contestClient = ContestClient.fromService(proposalService.withServiceName(CoLabService.CONTEST.getServiceName()));
RestService activitiesService = proposalService.withServiceName(CoLabService.ACTIVITY.getServiceName());
activitiesClient = ActivitiesClient.fromService(activitiesService);
}
public static ProposalClient fromService(RestService proposalService) {
return instances
.computeIfAbsent(proposalService, k -> new ProposalClient(proposalService));
}
public Proposal createProposal(Proposal proposal) {
return proposalResource
.create(new ProposalDto(proposal))
.execute().toPojo(proposalService);
}
public List<Proposal> listProposals(long contestId) {
return listProposals(0, Integer.MAX_VALUE, contestId, null, null, null);
}
public List<Proposal> listProposals(int start, int limit, Long contestId, Boolean visible,
Long contestPhaseId, Integer ribbon) {
return listProposals(start, limit, null, contestId, null,
null, visible, contestPhaseId, ribbon);
}
public List<Proposal> listProposals(int start, int limit, String filterText, Long contestId,
List<Long> contestTypeIds, List<Long> contestTierIds, Boolean visible, Long contestPhaseId,
Integer ribbon) {
return DtoUtil.toPojos(proposalResource.list()
.addRange(start, limit)
.optionalQueryParam("filterText", filterText)
.optionalQueryParam("contestIds", contestId)
.optionalQueryParam("contestTypeIds", contestTypeIds)
.optionalQueryParam("contestTierIds", contestTierIds)
.optionalQueryParam("visible", visible)
.optionalQueryParam("contestPhaseId", contestPhaseId)
.optionalQueryParam("ribbon", ribbon)
.execute(), proposalService);
}
public List<Proposal> getProposalsByCurrentContests(List<Long> contestTypeIds, List<Long> contestTierIds,
String filterText) {
return DtoUtil.toPojos(proposalResource.list()
.addRange(0, Integer.MAX_VALUE)
.optionalQueryParam("filterText", filterText)
.optionalQueryParam("contestTypeIds", contestTypeIds)
.optionalQueryParam("contestTierIds", contestTierIds)
.optionalQueryParam("visible", true)
.withCache(CacheName.MISC_SHORT)
.execute(), proposalService);
}
public List<Long> listProposalIds(int start, int limit, Long contestId,
Boolean visible, Long contestPhaseId, Integer ribbon) {
return proposalIdResource.list()
.addRange(start, limit)
.optionalQueryParam("contestId", contestId)
.optionalQueryParam("visible", visible)
.optionalQueryParam("contestPhaseId", contestPhaseId)
.optionalQueryParam("ribbon", ribbon)
.execute();
}
public List<Long> listThreadIds(int start, int limit, Long contestId,
Boolean visible, Long contestPhaseId, Integer ribbon) {
return proposalThreadIdResource.list()
.addRange(start, limit)
.optionalQueryParam("contestId", contestId)
.optionalQueryParam("visible", visible)
.optionalQueryParam("contestPhaseId", contestPhaseId)
.optionalQueryParam("ribbon", ribbon)
.execute();
}
public List<Proposal> getProposalsInContestPhase(Long contestPhaseId) {
return listProposals(0, Integer.MAX_VALUE, null, true, contestPhaseId, null);
}
public List<Proposal> getAllProposals() {
return listProposals(0, Integer.MAX_VALUE, null, true, null, null);
}
public List<Proposal> getProposalsInContest(Long contestPK) {
ContestPhase cp = contestClient.getActivePhase(contestPK);
return listProposals(0, Integer.MAX_VALUE, null, true, cp.getContestPhasePK(), null);
}
public List<Member> getProposalMembers(Long proposalId) {
return proposalResource.service(proposalId, "allMembers", Member.TYPES.getTypeReference())
.getList();
}
public void removeUserFromProposalTeam(Long proposalId, Long memberUserId) {
proposalResource.service(proposalId, "removeUserFromProposalTeam", Boolean.class)
.queryParam("memberUserId", memberUserId)
.delete();
}
public Boolean isUserInProposalTeam(Long proposalId, Long memberUserId) {
return proposalResource.service(proposalId, "isUserInProposalTeam", Boolean.class)
.queryParam("memberUserId", memberUserId)
.get();
}
public List<Proposal> getActiveProposalsInContestPhase(Long contestPhaseId, CacheName cacheName) {
return DtoUtil.toPojos(proposalResource.list()
.addRange(0, Integer.MAX_VALUE)
.optionalQueryParam("visible", true)
.optionalQueryParam("contestPhaseId", contestPhaseId)
.withCache(CacheKeys.withClass(ProposalDto.class)
.withParameter("contestPhaseId", contestPhaseId).asList(), cacheName)
.execute(), proposalService);
}
public List<Proposal> getActiveProposalsInContestPhase(Long contestPhaseId) {
return getActiveProposalsInContestPhase(contestPhaseId, CacheName.PROPOSAL_LIST);
}
public Proposal createProposal(long authorId, long contestPhaseId, boolean publishActivity) {
return proposalResource.service("createProposal", ProposalDto.class)
.queryParam("authorId", authorId)
.queryParam("contestPhaseId", contestPhaseId)
.queryParam("publishActivity", publishActivity)
.post().toPojo(proposalService);
}
public List<Proposal> getContestIntegrationRelevantSubproposals(Long proposalId) {
return DtoUtil.toPojos(proposalResource.service(proposalId, "contestIntegrationRelevantSubproposal",
ProposalDto.TYPES.getTypeReference()).getList(), proposalService);
}
public List<Proposal> getLinkingProposalsForUser(long userId) {
final List<Proposal> userProposals = getMemberProposals(userId);
List<Proposal> linkingProposals = new ArrayList<>();
for (Proposal proposal : userProposals) {
linkingProposals.addAll(getLinkingProposals(proposal.getProposalId()));
}
return linkingProposals;
}
public List<Proposal> getMemberProposals(Long userId) {
return DtoUtil.toPojos(proposalResource.service("getMemberProposals", ProposalDto.TYPES.getTypeReference())
.queryParam("userId", userId)
.getList(), proposalService);
}
public List<Proposal> getLinkingProposals(long proposalId) {
List<ProposalReference> proposalReferences = getProposalReference(null, proposalId);
List<Proposal> linkingProposals = new ArrayList<>();
for (ProposalReference proposalReference : proposalReferences) {
try {
final Proposal proposal = getProposal(proposalReference.getProposalId());
if (!linkingProposals.contains(proposal)) {
linkingProposals.add(proposal);
}
} catch (ProposalNotFoundException ignored) {
}
}
return linkingProposals;
}
public Proposal getProposal(long proposalId) throws ProposalNotFoundException {
return getProposal(proposalId, false);
}
public Proposal getProposal(long proposalId, boolean includeDeleted)
throws ProposalNotFoundException {
try {
return proposalResource.get(proposalId)
.queryParam("includeDeleted", includeDeleted)
.withCache(CacheKeys.withClass(ProposalDto.class)
.withParameter("proposalId", proposalId)
.withParameter("includeDeleted", includeDeleted).build(),
CacheName.MISC_REQUEST)
.executeChecked().toPojo(proposalService);
} catch (EntityNotFoundException e) {
throw new ProposalNotFoundException(proposalId);
}
}
public List<ProposalReference> getProposalReference(Long proposalId, Long subProposalId) {
return DtoUtil.toPojos(proposalReferenceResource.list()
.optionalQueryParam("proposalId", proposalId)
.optionalQueryParam("subProposalId", subProposalId)
.execute(), proposalService);
}
public List<Proposal> getSubproposals(Long proposalId, Boolean includeProposalsInSameContest) {
return DtoUtil.toPojos(proposalResource
.service(proposalId, "getSubproposals", ProposalDto.TYPES.getTypeReference())
.queryParam("includeProposalsInSameContest", includeProposalsInSameContest)
.getList(), proposalService);
}
public List<Proposal> getLinkingProposalsForProposalID(Long proposalId) {
return DtoUtil.toPojos(proposalResource.service(proposalId, "listProposalLinks", ProposalDto.TYPES.getTypeReference())
.getList(),proposalService);
}
public Integer getProposalMaterializedPoints(Long proposalId) {
return proposalResource.service(proposalId, "materializedPoints", Integer.class).get();
}
public Integer getNumberOfProposalsForJudge(Long userId, Long contestPhaseId) {
return proposalResource.service("numberOfProposalsForJudge", Integer.class)
.queryParam("userId", userId)
.queryParam("contestPhaseId", contestPhaseId)
.get();
}
public ProposalReference getProposalReferenceByProposalIdSubProposalId(Long proposalId,
Long subProposalId) {
List<ProposalReference> list = DtoUtil.toPojos(proposalReferenceResource.list()
.optionalQueryParam("proposalId", proposalId)
.optionalQueryParam("subProposalId", subProposalId)
.execute(), proposalService);
if (list != null && !list.isEmpty()) {
return list.get(0);
} else {
return null;
}
}
public boolean updateProposal(Proposal proposal) {
return proposalResource
.update(new ProposalDto(proposal), proposal.getProposalId())
.cacheKey(CacheKeys.withClass(ProposalDto.class)
.withParameter("proposalId", proposal.getProposalId())
.withParameter("includeDeleted", false).build())
.execute();
}
public boolean deleteProposal(long proposalId) {
return proposalResource.delete(proposalId).execute();
}
public ProposalVersion getProposalVersionByProposalIdVersion(Long proposalId, Integer version) {
return proposalVersionResource.service("getByProposalIdVersion", ProposalVersionDto.class)
.queryParam("proposalId", proposalId)
.queryParam("version", version)
.get()
.toPojo(proposalService);
}
public List<ProposalVersion> getProposalVersionsGroupedVersionsByContest(Long proposalId, Long contestId, int start, int end) {
return DtoUtil.toPojos(proposalVersionResource.service("getGroupedVersionsByContest", ProposalVersionDto.TYPES.getTypeReference())
.queryParam("proposalId", proposalId)
.queryParam("contestId", contestId)
.queryParam("start", start)
.queryParam("end", end)
.getList(),proposalService);
}
public Integer countProposalVersionsGroupedVersionsByContest(Long proposalId, Long contestId) {
return proposalVersionResource.service("countGroupedVersionsByContest", Integer.class)
.queryParam("proposalId", proposalId)
.queryParam("contestId", contestId)
.get();
}
public Integer countProposalVersions(Long proposalId) {
return proposalVersionResource.service("count", Integer.class)
.optionalQueryParam("proposalId", proposalId)
.get();
}
public ProposalVersion getProposalVersionByProposal(Long proposalId) {
return proposalVersionResource.service("getByProposalIdVersion", ProposalVersionDto.class)
.queryParam("proposalId", proposalId)
.get()
.toPojo(proposalService);
}
public List<ProposalVersion> getAllProposalVersions(Long proposalId) {
return DtoUtil.toPojos(proposalVersionResource.list()
.optionalQueryParam("proposalId", proposalId)
.execute(), proposalService);
}
public ContestType getContestTypeFromProposalId(Long proposalId) {
try {
Contest contest = getCurrentContestForProposal(proposalId);
return contestClient.getContestType(contest.getContestTypeId());
} catch (ContestNotFoundException e) {
throw ReferenceResolutionException.toObject(Contest.class, "")
.fromObject(Proposal.class, proposalId);
}
}
public Contest getCurrentContestForProposal(Long proposalId) throws ContestNotFoundException {
Long contestPhaseId = getLatestContestPhaseIdInProposal(proposalId);
ContestPhase contestPhase = contestClient.getContestPhase(contestPhaseId);
return contestClient.getContest(contestPhase.getContestPK());
}
public Long getLatestContestPhaseIdInProposal(Long proposalId) {
return proposalResource.service(proposalId, "getLatestContestPhaseIdInProposal", Long.class)
.get();
}
public Contest getLatestContestInProposal(Long proposalId) throws ContestNotFoundException {
return contestClient
.getContest(getLatestContestPhaseInProposal(proposalId).getContestPK());
}
public ContestPhase getLatestContestPhaseInProposal(Long proposalId) {
Long contestPhaseId = getLatestContestPhaseIdInProposal(proposalId);
return contestClient.getContestPhase(contestPhaseId);
}
public void populateTableWithProposal(long proposalId) {
proposalReferenceResource.service("populateTableWithProposal", Boolean.class)
.queryParam("proposalId", proposalId)
.get();
}
public boolean isMemberSubscribedToProposal(long proposalId, long userId) {
return activitiesClient.isSubscribedToActivity(userId,
ActivityEntryType.PROPOSAL.getPrimaryTypeId(), proposalId, 0, "");
}
public void subscribeMemberToProposal(long proposalId, long userId) {
subscribeMemberToProposal(proposalId, userId, false);
}
private void subscribeMemberToProposal(long proposalId, long userId, boolean automatic) {
activitiesClient.addSubscription(userId, ActivityEntryType.PROPOSAL, proposalId, null);
}
public void unsubscribeMemberFromProposal(long proposalId, long userId) {
unsubscribeMemberFromProposal(proposalId, userId, false);
}
private void unsubscribeMemberFromProposal(long proposalId, long userId, boolean automatic) {
activitiesClient.deleteSubscription(userId, ActivityEntryType.PROPOSAL, proposalId, null);
}
public Group_ createGroup(Group_ group) {
return groupResource.create(new GroupDto(group)).execute().toPojo(proposalService);
}
public boolean updateGroup(Group_ group) {
return groupResource.update(new GroupDto(group), group.getGroupId()).execute();
}
private static String convertListToGetParameter(List<Long> list, String parameterName) {
if(list.isEmpty()){
return "";
}
String parameterList = "";
for(int i=0; i<list.size()-2; i++) {
parameterList += list.get(i) + "&" + parameterName + "=";
}
parameterList += list.get(list.size()-1);
return parameterList;
}
}