001/**
002 * Copyright 2004-2014 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 */
020package org.kuali.student.contract.model.util;
021
022import java.util.List;
023
024import org.kuali.student.contract.exception.DictionaryExecutionException;
025import org.kuali.student.contract.model.Dictionary;
026import org.kuali.student.contract.model.DictionaryModel;
027import org.kuali.student.contract.model.Field;
028import org.kuali.student.contract.model.XmlType;
029
030/**
031 *
032 * @author nwright
033 */
034public 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}