content: package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders;
  
  import org.stringtemplate.v4.ST;
  import org.stringtemplate.v4.STGroup;
  
  import at.ac.tuwien.kr.alpha.api.ComparisonOperator;
  import at.ac.tuwien.kr.alpha.api.programs.Predicate;
  import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement;
  import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol;
  import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm;
  import at.ac.tuwien.kr.alpha.api.programs.terms.Term;
  import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom;
  import at.ac.tuwien.kr.alpha.commons.Predicates;
  import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators;
  import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms;
  import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms;
  import at.ac.tuwien.kr.alpha.commons.util.Util;
  
  /**
   * Aggregate encoder handling sum aggregates.
   * 
   * Copyright (c) 2020, the Alpha Team.
   */
  public final class SumEncoder extends StringtemplateBasedAggregateEncoder {
  
  	private static final STGroup AGGREGATE_ENCODINGS = Util.loadStringTemplateGroup(
  			SumEncoder.class.getResource("/stringtemplates/aggregate-encodings.stg"));
  
  	private static final ST SUM_LE_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("sum_le");
  	private static final ST SUM_EQ_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("sum_eq");
  
  	private static final ST NON_NEG_ELEMENTS_SUM_LE_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("sum_le_no_negative_elements");
  	private static final ST NON_NEG_ELEMENTS_SUM_EQ_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("sum_eq_no_negative_elements");
  
  	private SumEncoder(ComparisonOperator acceptedOperator, ST encodingTemplate) {
  		super(AggregateFunctionSymbol.SUM, acceptedOperator, encodingTemplate);
  	}
  
  	public static SumEncoder buildSumLessOrEqualEncoder(boolean supportNegativeIntegers) {
  		return new SumEncoder(ComparisonOperators.LE, supportNegativeIntegers ? SUM_LE_TEMPLATE : NON_NEG_ELEMENTS_SUM_LE_TEMPLATE);
  	}
  
  	public static SumEncoder buildSumEqualsEncoder(boolean supportNegativeIntegers) {
  		return new SumEncoder(ComparisonOperators.EQ, supportNegativeIntegers ? SUM_EQ_TEMPLATE : NON_NEG_ELEMENTS_SUM_EQ_TEMPLATE);
  	}
  
  	/**
  	 * In contrast to encoders for other aggregate functions, the "element tuple" atom for sum encodings is ternary - apart
  	 * from the aggregate arguments and the variable tuple identifying the aggregated element, it also holds the value to
  	 * add to the result sum as its third argument.
  	 */
  	@Override
  	protected BasicAtom buildElementRuleHead(String aggregateId, AggregateElement element, Term aggregateArguments) {
  		Predicate headPredicate = Predicates.getPredicate(this.getElementTuplePredicateSymbol(aggregateId), 3);
  		FunctionTerm elementTuple = Terms.newFunctionTerm(AbstractAggregateEncoder.ELEMENT_TUPLE_FUNCTION_SYMBOL, element.getElementTerms());
  		return Atoms.newBasicAtom(headPredicate, aggregateArguments, elementTuple, element.getElementTerms().get(0));
  	}
  
  }