001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package org.kuali.rice.krms.impl.repository;
006
007import java.util.ArrayList;
008import java.util.LinkedHashMap;
009import java.util.List;
010import java.util.Map;
011
012import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
013import org.kuali.rice.krms.api.repository.NaturalLanguageTree;
014import org.kuali.rice.krms.api.repository.RuleManagementService;
015import org.kuali.rice.krms.api.repository.TranslateBusinessMethods;
016import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
017import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
018import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplate;
019import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplaterContract;
020import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
021import org.kuali.rice.krms.api.repository.proposition.PropositionParameter;
022import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType;
023import org.kuali.rice.krms.api.repository.proposition.PropositionType;
024import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
025import org.kuali.rice.krms.api.repository.term.TermDefinition;
026import org.kuali.rice.krms.api.repository.term.TermParameterDefinition;
027import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
028
029/**
030 * @author nwright
031 */
032public class TranslationUtility implements TranslateBusinessMethods {
033
034    private RuleManagementService ruleManagementService;
035    private NaturalLanguageTemplaterContract templater;
036
037    public TranslationUtility(RuleManagementService ruleManagementService,
038            NaturalLanguageTemplaterContract templater) {
039        this.ruleManagementService = ruleManagementService;
040        this.templater = templater;
041    }
042
043    public RuleManagementService getRuleManagementService() {
044        return ruleManagementService;
045    }
046
047    public void setRuleManagementService(RuleManagementService ruleManagementService) {
048        this.ruleManagementService = ruleManagementService;
049    }
050
051    public NaturalLanguageTemplaterContract getTemplater() {
052        return templater;
053    }
054
055    public void setTemplater(NaturalLanguageTemplaterContract templater) {
056        this.templater = templater;
057    }
058
059    @Override
060    public String translateNaturalLanguageForObject(String naturalLanguageUsageId, String typeId, String krmsObjectId, String languageCode)
061            throws RiceIllegalArgumentException {
062
063        PropositionDefinition proposition = null;
064        // TODO: find out what RICE intended for this typeId? Was it supposed to be the Simple Class name?
065        if (typeId.equals("proposition")) {
066            proposition = this.ruleManagementService.getProposition(krmsObjectId);
067            if (proposition == null) {
068                throw new RiceIllegalArgumentException(krmsObjectId + " is not an Id for a proposition");
069            }
070        } else if (typeId.equals("agenda")) {
071            AgendaDefinition agenda = this.ruleManagementService.getAgenda(krmsObjectId);
072            if (agenda == null) {
073                throw new RiceIllegalArgumentException(krmsObjectId + " is not an Id for an agenda");
074            }
075            if (agenda.getFirstItemId() == null) {
076                throw new RiceIllegalArgumentException("Agenda has no first item");
077            }
078            AgendaItemDefinition item = this.ruleManagementService.getAgendaItem(agenda.getFirstItemId());
079            if (item.getRuleId() == null) {
080                throw new RiceIllegalArgumentException("Only simple agenda's composed of one item that holds a rule is supported at this time");
081            }
082            RuleDefinition rule = this.ruleManagementService.getRule(item.getRuleId());
083            proposition = rule.getProposition();
084            if (proposition == null) {
085                throw new RiceIllegalArgumentException("The agenda's rule has a proposition that is null");
086            }
087        }
088        String propositionTypeId = proposition.getTypeId();
089        NaturalLanguageTemplate naturalLanguageTemplate =
090                this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
091                propositionTypeId,
092                naturalLanguageUsageId);
093        if (naturalLanguageTemplate == null) {
094            throw new RiceIllegalArgumentException("no template found for " + languageCode
095                    + " " + typeId
096                    + " " + naturalLanguageUsageId);
097        }
098        return this.translateNaturalLanguageForProposition(naturalLanguageUsageId, proposition, languageCode);
099    }
100
101    @Override
102    public String translateNaturalLanguageForProposition(String naturalLanguageUsageId,
103            PropositionDefinition proposition, String languageCode)
104            throws RiceIllegalArgumentException {
105        NaturalLanguageTemplate naturalLanguageTemplate =
106                this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
107                proposition.getTypeId(), naturalLanguageUsageId);
108        if (naturalLanguageTemplate == null) {
109            throw new RiceIllegalArgumentException(languageCode + "." + proposition.getTypeId() + "." + naturalLanguageUsageId);
110        }
111        Map<String, Object> contextMap;
112        if (proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
113            contextMap = this.buildSimplePropositionContextMap(proposition);
114        } else {
115            contextMap = this.buildCompoundPropositionContextMap(null, proposition, null);
116        }
117        return templater.translate(naturalLanguageTemplate, contextMap);
118    }
119
120    @Override
121    public NaturalLanguageTree translateNaturalLanguageTreeForProposition(String naturalLanguageUsageId,
122            PropositionDefinition proposition,
123            String languageCode) throws RiceIllegalArgumentException {
124        NaturalLanguageTemplate naturalLanguageTemplate = null;
125        //Continue if typeid is null, some children may not be initialized yet.
126        if (proposition.getTypeId() != null) {
127            naturalLanguageTemplate = this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
128                    proposition.getTypeId(), naturalLanguageUsageId);
129            if (naturalLanguageTemplate == null) {
130                throw new RiceIllegalArgumentException(languageCode + "." + proposition.getTypeId() + "." + naturalLanguageUsageId);
131            }
132        }
133
134        if (proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
135            NaturalLanguageTree.Builder tree = NaturalLanguageTree.Builder.create();
136            Map<String, Object> contextMap = this.buildSimplePropositionContextMap(proposition);
137            String naturalLanguage = templater.translate(naturalLanguageTemplate, contextMap);
138            tree.setNaturalLanguage(naturalLanguage);
139            return tree.build();
140        }
141        if (proposition.getPropositionTypeCode().equals(PropositionType.COMPOUND.getCode())) {
142            NaturalLanguageTree.Builder tree = NaturalLanguageTree.Builder.create();
143            Map<String, Object> contextMap = this.buildCompoundPropositionContextMap(naturalLanguageUsageId, proposition, languageCode);
144            String naturalLanguage = templater.translate(naturalLanguageTemplate, contextMap);
145            tree.setNaturalLanguage(naturalLanguage);
146
147            //Null check because newly created compound propositions should also be translateable.
148            if(proposition.getCompoundComponents()!=null){
149                List<NaturalLanguageTree> children = new ArrayList<NaturalLanguageTree>();
150                for (PropositionDefinition child : proposition.getCompoundComponents()) {
151                    children.add(this.translateNaturalLanguageTreeForProposition(naturalLanguageUsageId, child, languageCode));
152                }
153                tree.setChildren(children);
154            }
155
156            return tree.build();
157        }
158        throw new RiceIllegalArgumentException("Unknown proposition type: " + proposition.getPropositionTypeCode());
159    }
160
161    protected Map<String, Object> buildSimplePropositionContextMap(PropositionDefinition proposition) {
162        if (!proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
163            throw new RiceIllegalArgumentException("proposition is not simple " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
164        }
165        Map<String, Object> contextMap = new LinkedHashMap<String, Object>();
166        for (PropositionParameter param : proposition.getParameters()) {
167            if (param.getParameterType().equals(PropositionParameterType.TERM.getCode())) {
168                if (param.getTermValue() != null) {
169                    for (TermParameterDefinition termParam : param.getTermValue().getParameters()) {
170                        contextMap.put(termParam.getName(), termParam.getValue());
171                    }
172                } else {
173                    contextMap.put(param.getParameterType(), param.getValue());
174                }
175            } else {
176                contextMap.put(param.getParameterType(), param.getValue());
177            }
178        }
179        return contextMap;
180    }
181    public static final String COMPOUND_COMPONENTS = "compoundComponent";
182
183    protected Map<String, Object> buildCompoundPropositionContextMap(String naturalLanguageUsageId, PropositionDefinition proposition, String languageCode) {
184        if (!proposition.getPropositionTypeCode().equals(PropositionType.COMPOUND.getCode())) {
185            throw new RiceIllegalArgumentException("proposition us not compound " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
186        }
187        Map<String, Object> contextMap = new LinkedHashMap<String, Object>();
188        /*List<String> children = new ArrayList<String>();
189         for (PropositionDefinition param : proposition.getCompoundComponents()) {
190         children.add(this.translateNaturalLanguageForProposition(naturalLanguageUsageId, proposition, languageCode));
191         }
192         contextMap.put(COMPOUND_COMPONENTS, children);*/
193        return contextMap;
194    }
195
196    protected String translateCompoundProposition(PropositionDefinition proposition, String naturalLanguageUsageId, String languageCode)
197            throws RiceIllegalArgumentException {
198        if (!proposition.getPropositionTypeCode().equals(PropositionType.COMPOUND.getCode())) {
199            throw new RiceIllegalArgumentException("proposition us not compound " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
200        }
201        String compoundNaturalLanguageTypeId = this.calcCompoundNaturalLanguageTypeId(proposition.getCompoundOpCode());
202        // TODO: make sure we cache the AND and OR templates
203        NaturalLanguageTemplate template = this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
204                compoundNaturalLanguageTypeId, naturalLanguageUsageId);
205        Map<String, Object> contextMap = this.buildCompoundPropositionContextMap(naturalLanguageUsageId, proposition, languageCode);
206        return this.templater.translate(template, contextMap);
207
208    }
209
210    protected String calcCompoundNaturalLanguageTypeId(String compoundOpCode) throws RiceIllegalArgumentException {
211        if (compoundOpCode.equals("a")) {
212            return "kuali.compound.proposition.op.code." + "and";
213        }
214        if (compoundOpCode.equals("o")) {
215            return "kuali.compound.proposition.op.code." + "or";
216        }
217        throw new RiceIllegalArgumentException("unsupported compound op code " + compoundOpCode);
218    }
219
220    protected String translateSimpleProposition(NaturalLanguageTemplate naturalLanguageTemplate,
221            PropositionDefinition proposition)
222            throws RiceIllegalArgumentException {
223        if (!proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
224            throw new RiceIllegalArgumentException("proposition not simple " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
225        }
226        Map<String, Object> contextMap = this.buildSimplePropositionContextMap(proposition);
227        return templater.translate(naturalLanguageTemplate, contextMap);
228    }
229}