package org.xcolab.points;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.ext.portlet.model.PointType;
import com.ext.portlet.model.PointsDistributionConfiguration;
import com.ext.portlet.model.Proposal;
import com.ext.portlet.service.PointsDistributionConfigurationLocalServiceUtil;
import com.ext.portlet.service.ProposalLocalServiceUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.model.User;

public enum ReceiverLimitationStrategy {
	ANY_USER(new ReceiverLimitationTargetsPickerAlgorithm() {

		@Override
		public List<PointsTarget> getPointTargets(Proposal proposal, PointType pointType, DistributionStrategy distributionStrategy) throws SystemException {
			// check if there is any configuration, if there is create appropriate targets
			List<PointsTarget> targets = new ArrayList<PointsTarget>();
			if (distributionStrategy == DistributionStrategy.USER_DEFINED) {
				for (PointsDistributionConfiguration pdc: PointsDistributionConfigurationLocalServiceUtil.findByProposalPointType(proposal, pointType)) {
					if (pdc.getTargetUserId() > 0) {
						PointsTarget target = new PointsTarget();
						target.setUserId(pdc.getTargetUserId());
						target.setPercentage(pdc.getPercentage());
						targets.add(target);
					}
				}
			}
			return targets;
		}
		
	}), 
	
	ANY_NON_TEAM_MEMBER(new ReceiverLimitationTargetsPickerAlgorithm() {

		@Override
		public List<PointsTarget> getPointTargets(Proposal proposal,
				PointType pointType, DistributionStrategy distributionStrategy) throws PortalException, SystemException {
			List<PointsTarget> targets = new ArrayList<PointsTarget>();
			
			if (distributionStrategy == DistributionStrategy.USER_DEFINED) {
				for (PointsDistributionConfiguration pdc: PointsDistributionConfigurationLocalServiceUtil.findByProposalPointType(proposal, pointType)) {
					if (pdc.getTargetUserId() > 0 && !ProposalLocalServiceUtil.isUserAMember(proposal.getProposalId(), pdc.getTargetUserId())) {
						PointsTarget target = new PointsTarget();
						target.setUserId(pdc.getTargetUserId());
						target.setPercentage(pdc.getPercentage());
						targets.add(target);
					}
				}
			}
			return targets;
		}
		
	}),
	ANY_TEAM_MEMBER(new ReceiverLimitationTargetsPickerAlgorithm() {

		@Override
		public List<PointsTarget> getPointTargets(Proposal proposal,
				PointType pointType, DistributionStrategy distributionStrategy) throws PortalException, SystemException {
			List<PointsTarget> targets = new ArrayList<PointsTarget>();
			
			if (distributionStrategy == DistributionStrategy.USER_DEFINED) {
				for (PointsDistributionConfiguration pdc: PointsDistributionConfigurationLocalServiceUtil.findByProposalPointType(proposal, pointType)) {
					if (pdc.getTargetUserId() > 0 && ProposalLocalServiceUtil.isUserAMember(proposal.getProposalId(), pdc.getTargetUserId())) {
						PointsTarget target = new PointsTarget();
						target.setUserId(pdc.getTargetUserId());
						target.setPercentage(pdc.getPercentage());
						targets.add(target);
					}
				}
				if (targets.isEmpty()) {
					// there is no configuration for specific users, distribute equally
					List<User> members = ProposalLocalServiceUtil.getMembers(proposal.getProposalId());
					for (User u: members) {
						PointsTarget target = new PointsTarget();
						target.setUserId(u.getUserId());
						target.setPercentage(1.0d / members.size());
						targets.add(target);
					}
				}
			}
			else if (distributionStrategy == DistributionStrategy.EQUAL_DIVISION) {
				List<User> members = ProposalLocalServiceUtil.getMembers(proposal.getProposalId());
				for (User u: members) {
					PointsTarget target = new PointsTarget();
					target.setUserId(u.getUserId());
					target.setPercentage(1.0d / members.size());
					targets.add(target);
				}
			}
			return targets;
		}
		
	}),  
	SUBPROPOSALS(new ReceiverLimitationTargetsPickerAlgorithm() {

		@Override
		public List<PointsTarget> getPointTargets(Proposal proposal,
				PointType pointType, DistributionStrategy distributionStrategy) throws SystemException, PortalException {
			List<PointsTarget> targets = new ArrayList<PointsTarget>();
			
			Collection<Proposal> subProposals = ProposalLocalServiceUtil.getSubproposals(proposal.getProposalId());
			Set<Long> proposalIds = new HashSet<Long>();
			for (Proposal p: subProposals) {
				proposalIds.add(p.getProposalId());
			}
			if (distributionStrategy == DistributionStrategy.USER_DEFINED) {
				for (PointsDistributionConfiguration pdc: PointsDistributionConfigurationLocalServiceUtil.findByProposalPointType(proposal, pointType)) {
					if (pdc.getTargetSubProposalId() > 0 && proposalIds.contains(pdc.getTargetSubProposalId()) && pdc.getTargetSubProposalId() != proposal.getProposalId()) {
						PointsTarget target = new PointsTarget();
						target.setProposalId(pdc.getTargetSubProposalId());
						target.setPercentage(pdc.getPercentage());
						targets.add(target);
					}
				}
			}
			else if (distributionStrategy == DistributionStrategy.EQUAL_DIVISION) {
				for (Long proposalId: proposalIds) {
                    if (proposalId != proposal.getProposalId()) {
                        PointsTarget target = new PointsTarget();
                        target.setProposalId(proposalId);
                        target.setPercentage(1.0d / proposalIds.size());
                        targets.add(target);
                    }
				}
			}
			return targets;
		}
		
	}), 
	NONE(new ReceiverLimitationTargetsPickerAlgorithm() {

		@Override
		public List<PointsTarget> getPointTargets(Proposal proposal,
				PointType pointType, DistributionStrategy distributionStrategy) {
			return null;
		}
		
	}), ;
	
	private final ReceiverLimitationTargetsPickerAlgorithm targetsPickerAlgorithm;
	
	private ReceiverLimitationStrategy(ReceiverLimitationTargetsPickerAlgorithm algorithm) {
		targetsPickerAlgorithm = algorithm;
	}
	
	public List<PointsTarget> getTargets(Proposal proposal, PointType pointType, DistributionStrategy distributionStrategy) throws PortalException, SystemException {
		return targetsPickerAlgorithm.getPointTargets(proposal, pointType, distributionStrategy);
		
	}
	
	
	public static interface ReceiverLimitationTargetsPickerAlgorithm {
		List<PointsTarget> getPointTargets(Proposal proposal, PointType pointType, DistributionStrategy distributionStrategy) throws PortalException, SystemException;
	}
}

@@ -4499,20 +4499,105 @@
 sals) %7B%0A
-%09%09%09%09
+                if (p.getProposalId() != proposal.getProposalId()) %7B%0A                    
 proposal
@@ -4624,16 +4624,34 @@
 lId());%0A
+                %7D%0A
 %09%09%09%7D%0A%09%09%09
@@ -5336,78 +5336,8 @@
 ) %7B%0A
-                    if (proposalId != proposal.getProposalId()) %7B%0A    
     
@@ -5406,36 +5406,32 @@
                 
-    
 target.setPropos
@@ -5448,20 +5448,16 @@
 salId);%0A
-    
         
@@ -5533,28 +5533,24 @@
             
-    
 targets.add(
@@ -5562,30 +5562,8 @@
 t);%0A
-                    %7D%0A
 %09%09%09%09

Fix problem where self-linking proposals were taken into account when calculating the points per proposal