001    /**
002     * Copyright 2004-2013 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     */
016    /*
017     * To change this template, choose Tools | Templates
018     * and open the template in the editor.
019     */
020    package org.kuali.student.contract.model.util;
021    
022    import java.util.List;
023    
024    import org.kuali.student.contract.exception.DictionaryExecutionException;
025    import org.kuali.student.contract.model.Dictionary;
026    import org.kuali.student.contract.model.DictionaryModel;
027    import org.kuali.student.contract.model.Field;
028    import org.kuali.student.contract.model.XmlType;
029    
030    /**
031     *
032     * @author nwright
033     */
034    public class DictionaryParentSetter {
035    
036        private DictionaryModel model;
037        private ModelFinder finder;
038    
039        public DictionaryParentSetter(DictionaryModel model) {
040            this.model = model;
041            this.finder = new ModelFinder(model);
042        }
043    
044        public void set() {
045            for (int i = 1; i < model.getDictionary().size(); i++) {
046                Dictionary child = model.getDictionary().get(i);
047                Dictionary parent = calcParent(i, child);
048                child.setParent(parent);
049            }
050        }
051    
052        private Dictionary calcParent(int index, Dictionary child) {
053            // if first field the parent is by default null
054            // course.official
055            if (index == 0) {
056                return null;
057            }
058            // if first field of the defnition of a new main type
059            // then the parent is null
060            // i.e. program.official is the start of a new cluInfo definition
061            XmlType xmlType = finder.findXmlType(child.getXmlObject());
062            if (xmlType == null) {
063                throw new DictionaryExecutionException("child.getXmlObject ()=" + child.getXmlObject());
064            }
065            if (xmlType.hasOwnCreateUpdate()) {
066                List<Field> fields = finder.findFields(child.getXmlObject());
067                if (fields.get(0).getShortName().equalsIgnoreCase(child.getShortName())) {
068                    return null;
069                }
070            }
071            Dictionary prev = model.getDictionary().get(index - 1);
072            // if this is just another field on same object as prev
073            // then they have the same parent
074            // course.official.no                cluIdentifierInfo
075            // course.official.transcriptTitle      cluIdentifierInfo    << this has the same parent as previous
076            if (prev.getXmlObject().equalsIgnoreCase(child.getXmlObject())) {
077                return prev.getParent();
078            }
079            // objects are different so check if we are going down or up
080            // if going down the hierarchy
081            Field prevField = finder.findField(prev);
082            if (prevField == null) {
083                throw new DictionaryExecutionException("Could not find field associated with dictionary entry with id =" + prev.getId());
084            }
085            // going down heirarchy if this sub-object is the same type of the previous field
086            // because that means this field is  the 1st field of the sub-type definition
087            if (calcType(prevField.getXmlType()).equalsIgnoreCase(child.getXmlObject())) {
088                // loop back to find the first (default) definition for that field -- that is the real parent
089                // not the state override
090                // course.desc                <<<< Make this the parent
091                // course.desc.draft.private
092                // course.desc.template
093                // course.desc.draft.public   <<<< not this
094                // course.desc.plain          <<<< of this
095                for (int i = index - 2; i > -1; i--) {
096                    Dictionary prev2 = model.getDictionary().get(i);
097                    if (prev2.getXmlObject().equalsIgnoreCase(prev.getXmlObject())) {
098                        if (prev2.getShortName().equalsIgnoreCase(prev.getShortName())) {
099                            prev = prev2;
100                            continue;
101                        }
102                    }
103                    break;
104                }
105                return prev;
106            }
107            // we are popping up from down in the heirarchy
108            // have to go back to find the previous item at the same level
109            // course.desc                                      cluInfo
110            // course.desc.draft.private              cluInfo
111            // course.desc.template                     cluInfo
112            // course.desc.draft.public                cluInfo       << use this parent
113            // course.desc.plain                           richTextInfo
114            // course.desc.plain.draft.private          richTextInfo
115            // course.desc.plain.draft.public            richTextInfo
116            // course.desc.formatted                      richTextInfo
117            // course.desc.formatted.draft.private  richTextInfo
118            // course.desc.formatted.draft.public    richTextInfo
119            // course.rationale                             cluInfo       << as this field's parent
120            for (int i = index - 1; i > -1; i--) {
121                Dictionary dict = model.getDictionary().get(i);
122                if (dict.getXmlObject().equalsIgnoreCase(child.getXmlObject())) {
123                    return dict.getParent();
124                }
125            }
126            throw new DictionaryExecutionException("dictionary entry " + child.getId()
127                    + " could not calculate the parent");
128        }
129    
130        private String calcType(String type) {
131            if (type.endsWith("List")) {
132                type = type.substring(0, type.length() - "List".length());
133            }
134    
135            return type;
136        }
137    }