001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.impl.repository;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
021import org.kuali.rice.krad.service.KRADServiceLocator;
022import org.kuali.rice.krad.service.SequenceAccessorService;
023import org.kuali.rice.krad.util.ObjectUtils;
024import org.kuali.rice.krms.api.repository.agenda.AgendaDefinitionContract;
025import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
026import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinitionContract;
027import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
028
029import java.util.ArrayList;
030import java.util.List;
031import java.util.Map;
032import static org.kuali.rice.krms.impl.repository.AgendaItemBo.COPY_OF_TEXT;
033
034/**
035 * Agenda Item business object
036 * 
037 * @author Kuali Rice Team (rice.collab@kuali.org)
038 *
039 */
040public class AgendaItemBo extends PersistableBusinessObjectBase implements AgendaItemDefinitionContract {
041
042    public static final String COPY_OF_TEXT = "Copy of ";
043    private static final String KRMS_AGENDA_ITM_S = "KRMS_AGENDA_ITM_S";
044
045        private String id;
046        private String agendaId;
047        private String ruleId;
048        private String subAgendaId;
049        private String whenTrueId;
050        private String whenFalseId;
051        private String alwaysId;
052        
053        private RuleBo rule;
054        
055        private AgendaItemBo whenTrue;
056        private AgendaItemBo whenFalse;
057        private AgendaItemBo always;
058
059    private static SequenceAccessorService sequenceAccessorService;
060        
061        public String getUl(AgendaItemBo firstItem) {
062                return ("<ul>" + getUlHelper(firstItem) + "</ul>");
063        }
064        
065        public String getUlHelper(AgendaItemBo item) {
066                StringBuilder sb = new StringBuilder();
067                sb.append("<li>" + ruleId + "</li>");
068                if (whenTrue != null) {
069                        sb.append("<ul><li>when true</li><ul>");
070                        sb.append(getUlHelper(whenTrue));
071                        sb.append("</ul></ul>");
072                }
073                if (whenFalse != null) {
074                        sb.append("<ul><li>when false</li><ul>");
075                        sb.append(getUlHelper(whenFalse));
076                        sb.append("</ul></ul>");
077                }
078                if (always != null) {
079                        sb.append(getUlHelper(always));
080                }
081                return sb.toString();
082        }
083
084    public String getRuleText() {
085        StringBuilder resultBuilder = new StringBuilder();
086        if (getRule() != null) {
087            if (StringUtils.isBlank(getRule().getName())) {
088                resultBuilder.append("- unnamed rule -");
089            } else {
090                resultBuilder.append(getRule().getName());
091            }
092            if (!StringUtils.isBlank(getRule().getDescription())) {
093                resultBuilder.append(": ");
094                resultBuilder.append(getRule().getDescription());
095            }
096            // add a description of the action configured on the rule, if there is one
097            if (!CollectionUtils.isEmpty(getRule().getActions())) {
098                resultBuilder.append("   [");
099                ActionBo action = getRule().getActions().get(0);
100
101                KrmsTypeDefinition krmsTypeDefn =
102                        KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(action.getTypeId());
103
104                resultBuilder.append(krmsTypeDefn.getName());
105                resultBuilder.append(": ");
106                resultBuilder.append(action.getName());
107
108                if (getRule().getActions().size() > 1) {
109                    resultBuilder.append(" ... ");
110                }
111                resultBuilder.append("]");
112            }
113        } else {
114            throw new IllegalStateException();
115        }
116        return resultBuilder.toString();
117    }
118
119//      def List<AgendaItemBo> alwaysList
120//      def List<AgendaItemBo> whenTrueList
121//      def List<AgendaItemBo> whenFalseList
122        
123        public List<AgendaItemBo> getAlwaysList() {
124                List<AgendaItemBo> results = new ArrayList<AgendaItemBo>();
125                
126                AgendaItemBo currentNode = this;
127                while (currentNode.always != null) {
128                        results.add(currentNode.always);
129                        currentNode = currentNode.always;
130                }
131                
132                return results;
133        }
134
135        /**
136         * @return the id
137         */
138        public String getId() {
139                return this.id;
140        }
141
142        /**
143         * @param id the id to set
144         */
145        public void setId(String id) {
146                this.id = id;
147        }
148
149        /**
150         * @return the agendaId
151         */
152        public String getAgendaId() {
153                return this.agendaId;
154        }
155
156        /**
157         * @param agendaId the agendaId to set
158         */
159        public void setAgendaId(String agendaId) {
160                this.agendaId = agendaId;
161        }
162
163        /**
164         * @return the ruleId
165         */
166        public String getRuleId() {
167                return this.ruleId;
168        }
169
170        /**
171         * @param ruleId the ruleId to set
172         */
173        public void setRuleId(String ruleId) {
174                this.ruleId = ruleId;
175        }
176
177        /**
178         * @return the subAgendaId
179         */
180        public String getSubAgendaId() {
181                return this.subAgendaId;
182        }
183
184        /**
185         * @param subAgendaId the subAgendaId to set
186         */
187        public void setSubAgendaId(String subAgendaId) {
188                this.subAgendaId = subAgendaId;
189        }
190
191
192        /**
193         * @return the whenTrueId
194         */
195        public String getWhenTrueId() {
196                return this.whenTrueId;
197        }
198
199        /**
200         * @param whenTrueId the whenTrueId to set
201         */
202        public void setWhenTrueId(String whenTrueId) {
203                this.whenTrueId = whenTrueId;
204        }
205
206        /**
207         * @return the whenFalseId
208         */
209        public String getWhenFalseId() {
210                return this.whenFalseId;
211        }
212
213        /**
214         * @param whenFalseId the whenFalseId to set
215         */
216        public void setWhenFalseId(String whenFalseId) {
217                this.whenFalseId = whenFalseId;
218        }
219
220        /**
221         * @return the alwaysId
222         */
223        public String getAlwaysId() {
224                return this.alwaysId;
225        }
226
227        /**
228         * @param alwaysId the alwaysId to set
229         */
230        public void setAlwaysId(String alwaysId) {
231                this.alwaysId = alwaysId;
232        }
233
234        /**
235         * @return the whenTrue
236         */
237        public AgendaItemBo getWhenTrue() {
238                return this.whenTrue;
239        }
240
241        /**
242         * @param whenTrue the whenTrue to set
243         */
244        public void setWhenTrue(AgendaItemBo whenTrue) {
245                this.whenTrue = whenTrue;
246        if (whenTrue != null) {
247            setWhenTrueId(whenTrue.getId());
248        } else {
249            setWhenTrueId(null);
250        }
251        }
252
253        /**
254         * @return the whenFalse
255         */
256        public AgendaItemBo getWhenFalse() {
257                return this.whenFalse;
258        }
259
260        /**
261         * @param whenFalse the whenFalse to set
262         */
263        public void setWhenFalse(AgendaItemBo whenFalse) {
264                this.whenFalse = whenFalse;
265        if (whenFalse != null) {
266            setWhenFalseId(whenFalse.getId());
267        } else {
268            setWhenFalseId(null);
269        }
270        }
271
272        /**
273         * @return the always
274         */
275        public AgendaItemBo getAlways() {
276                return this.always;
277        }
278
279        /**
280         * @param always the always to set
281         */
282        public void setAlways(AgendaItemBo always) {
283                this.always = always;
284        if (always != null) {
285            setAlwaysId(always.getId());
286        } else {
287            setAlwaysId(null);
288        }
289        }
290        
291    /**
292     * @return the rule
293     */
294    public RuleBo getRule() {
295        return this.rule;
296    }
297
298    @Override
299    public AgendaDefinitionContract getSubAgenda() {
300        return null;  //To change body of implemented methods use File | Settings | File Templates.
301    }
302
303    /**
304     * @param rule the rule to set
305     */
306    public void setRule(RuleBo rule) {
307        this.rule = rule;
308        if (rule != null) {
309            setRuleId(rule.getId());
310        } else {
311            setRuleId(null);
312        }
313    }
314
315        
316    /**
317        * Converts a mutable bo to it's immutable counterpart
318        * @param bo the mutable business object
319        * @return the immutable object
320        */
321   static AgendaItemDefinition to(AgendaItemBo bo) {
322           if (bo == null) { return null; }
323           AgendaItemDefinition.Builder builder = AgendaItemDefinition.Builder.create(bo);
324           
325           return builder.build();
326   }
327
328   /**
329        * Converts a immutable object to it's mutable bo counterpart
330        * @param im immutable object
331        * @return the mutable bo
332        */
333   static AgendaItemBo from(AgendaItemDefinition im) {
334           if (im == null) { return null; }
335
336           AgendaItemBo bo = new AgendaItemBo();
337           bo.id = im.getId();
338           bo.agendaId = im.getAgendaId();
339           bo.ruleId = im.getRuleId();
340           bo.subAgendaId = im.getSubAgendaId();
341           bo.whenTrueId = im.getWhenTrueId();
342           bo.whenFalseId = im.getWhenFalseId();
343           bo.alwaysId = im.getAlwaysId();
344       bo.versionNumber = im.getVersionNumber();
345
346       bo.rule = RuleBo.from(im.getRule());
347       bo.whenTrue = AgendaItemBo.from(im.getWhenTrue());
348       bo.whenFalse = AgendaItemBo.from(im.getWhenFalse());
349       bo.always = AgendaItemBo.from(im.getAlways());
350           
351           return bo;
352   }
353
354    /**
355     * Returns a copy of this AgendaItem
356     * @param copiedAgenda the new Agenda that the copied AgendiaItem will be associated with
357     * @param oldRuleIdToNew Map<String, RuleBo> mapping of old rule id to the new RuleBo
358     * @param dts DateTimeStamp to append to the copied AgendaItem name
359     * @return AgendaItemBo copy of this AgendaItem with new id and name
360     */
361    public AgendaItemBo copyAgendaItem(AgendaBo copiedAgenda,  Map<String, RuleBo> oldRuleIdToNew,
362            Map<String, AgendaItemBo> oldAgendaItemIdToNew, List<AgendaItemBo> copiedAgendaItems, final String dts) {
363        // Use deepCopy and update all the ids.
364        AgendaItemBo copiedAgendaItem = (AgendaItemBo) ObjectUtils.deepCopy(this);
365        copiedAgendaItem.setId(getNewId());
366        copiedAgendaItem.setAgendaId(copiedAgenda.getId());
367
368        oldAgendaItemIdToNew.put(this.getId(), copiedAgendaItem);
369
370        // Don't create another copy of a rule that we have already copied.
371        if (!oldRuleIdToNew.containsKey(this.getRuleId())) {
372            if (this.getRule() != null) {
373                copiedAgendaItem.setRule(this.getRule().copyRule(COPY_OF_TEXT + this.getRule().getName() + " " + dts));
374                oldRuleIdToNew.put(this.getRuleId(), copiedAgendaItem.getRule());
375            }
376        } else {
377            copiedAgendaItem.setRule(oldRuleIdToNew.get(this.getRuleId()));
378        }
379
380        if (copiedAgendaItem.getWhenFalse() != null) {
381            if (!oldAgendaItemIdToNew.containsKey(this.getWhenFalseId())) {
382                copiedAgendaItem.setWhenFalse(this.getWhenFalse().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
383                oldAgendaItemIdToNew.put(this.getWhenFalseId(), copiedAgendaItem.getWhenFalse());
384                copiedAgendaItems.add(copiedAgendaItem.getWhenFalse());
385            } else {
386                copiedAgendaItem.setWhenFalse(oldAgendaItemIdToNew.get(this.getWhenFalseId()));
387            }
388        }
389
390        if (copiedAgendaItem.getWhenTrue() != null) {
391            if (!oldAgendaItemIdToNew.containsKey(this.getWhenTrueId())) {
392                copiedAgendaItem.setWhenTrue(this.getWhenTrue().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
393                oldAgendaItemIdToNew.put(this.getWhenTrueId(), copiedAgendaItem.getWhenTrue());
394                copiedAgendaItems.add(copiedAgendaItem.getWhenTrue());
395            } else {
396                copiedAgendaItem.setWhenTrue(oldAgendaItemIdToNew.get(this.getWhenTrueId()));
397            }
398        }
399
400        if (copiedAgendaItem.getAlways() != null) {
401            if (!oldAgendaItemIdToNew.containsKey(this.getAlwaysId())) {
402                copiedAgendaItem.setAlways(this.getAlways().copyAgendaItem(copiedAgenda, oldRuleIdToNew, oldAgendaItemIdToNew, copiedAgendaItems, dts));
403                oldAgendaItemIdToNew.put(this.getAlwaysId(), copiedAgendaItem.getAlways());
404                copiedAgendaItems.add(copiedAgendaItem.getAlways());
405            } else {
406                copiedAgendaItem.setAlways(oldAgendaItemIdToNew.get(this.getAlwaysId()));
407            }
408        }
409        return copiedAgendaItem;
410    }
411
412
413    /**
414     * Set the SequenceAccessorService, useful for testing.
415     * @param sas SequenceAccessorService to use for getNewId()
416     */
417    public static void setSequenceAccessorService(SequenceAccessorService sas) {
418        sequenceAccessorService = sas;
419    }
420
421    /**
422     * Returns the next available AgendaItem id.
423     * @return String the next available id
424     */
425    private static String getNewId() {
426        if (sequenceAccessorService == null) {
427            // we don't assign to sequenceAccessorService to preserve existing behavior
428            return KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber(KRMS_AGENDA_ITM_S, AgendaItemBo.class) + "";
429        }
430        Long id = sequenceAccessorService.getNextAvailableSequenceNumber(KRMS_AGENDA_ITM_S, AgendaItemBo.class);
431        return id.toString();
432    }
433}