001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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.ametys.odf.clientsideelement;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.ametys.cms.clientsideelement.SmartContentClientSideElement;
024import org.ametys.cms.repository.Content;
025import org.ametys.core.ui.Callable;
026import org.ametys.odf.ProgramItem;
027import org.ametys.odf.course.Course;
028import org.ametys.odf.course.CourseContainer;
029import org.ametys.odf.courselist.CourseList;
030import org.ametys.odf.courselist.CourseListContainer;
031import org.ametys.odf.coursepart.CoursePart;
032import org.ametys.odf.program.ProgramPart;
033import org.ametys.odf.program.TraversableProgramPart;
034import org.ametys.plugins.repository.UnknownAmetysObjectException;
035import org.ametys.runtime.i18n.I18nizableText;
036
037/**
038 * This client side element is enabled if the catalog of a {@link Course} can be edited
039 *
040 */
041public class EditCatalogClientSideElement extends SmartContentClientSideElement
042{
043    /**
044     * Get informations on contents' state
045     * @param contentsId the ids of contents
046     * @return informations on contents' state
047     */
048    @Callable
049    public Map<String, Object> getStatus(List<String> contentsId)
050    {
051        Map<String, Object> results = new HashMap<>();
052        
053        results.put("unmodifiable-contents", new ArrayList<Map<String, Object>>());
054        results.put("locked-contents", new ArrayList<Map<String, Object>>());
055        results.put("invalidworkflowaction-contents", new ArrayList<Map<String, Object>>());
056        results.put("unmodifiablecatalog-contents", new ArrayList<Map<String, Object>>());
057        results.put("referenced-contents", new ArrayList<Map<String, Object>>());
058        results.put("allright-contents", new ArrayList<Map<String, Object>>());
059        
060        for (String contentId : contentsId)
061        {
062            Content content = _resolver.resolveById(contentId);
063
064            if (content instanceof ProgramItem)
065            {
066                boolean error = false;
067                
068                // Is modifiable
069                String enabledOnModifiableOnly = (String) this._script.getParameters().get("enabled-on-modifiable-only"); 
070                if ("true".equals(enabledOnModifiableOnly) && !_isModifiable(content))
071                {
072                    Map<String, Object> contentParams = getContentDefaultParameters (content);
073                    contentParams.put("description", _getNoModifiableDescription(content));
074                    
075                    @SuppressWarnings("unchecked")
076                    List<Map<String, Object>> unModifiableContents = (List<Map<String, Object>>) results.get("unmodifiable-contents");
077                    unModifiableContents.add(contentParams);
078
079                    error = true;
080                }
081                
082                // Is locked
083                String enabledOnUnlockOnly = (String) this._script.getParameters().get("enabled-on-unlock-only"); 
084                if ("true".equals(enabledOnUnlockOnly) && _isLocked(content))
085                {
086                    Map<String, Object> contentParams = getContentDefaultParameters (content);
087                    contentParams.put("description", _getLockedDescription(content));
088                    
089                    @SuppressWarnings("unchecked")
090                    List<Map<String, Object>> lockedContents = (List<Map<String, Object>>) results.get("locked-contents");
091                    lockedContents.add(contentParams);
092                    
093                    error = true;
094                }
095                    
096                // Is workflow action correct
097                String enabledOnWorkflowActionOnly = (String) this._script.getParameters().get("enabled-on-workflow-action-only"); 
098                if (enabledOnWorkflowActionOnly != null)
099                {
100                    int actionId = _workflowAction(content);
101                    if (actionId == -1)
102                    {
103                        Map<String, Object> contentParams = getContentDefaultParameters (content);
104                        contentParams.put("description", _getWorkflowActionUnvailableDescription(content));
105                        
106                        @SuppressWarnings("unchecked")
107                        List<Map<String, Object>> invalidActionContents = (List<Map<String, Object>>) results.get("invalidworkflowaction-contents");
108                        invalidActionContents.add(contentParams);
109                        
110                        error = true;
111                    }
112                    else
113                    {
114                        results.put("workflowaction-content-actionId", actionId);
115                    }
116                }
117                
118                // Is catalog can be edited ?
119                if (!_isCatalogModifiable(content))
120                {
121                    Map<String, Object> contentParams = getContentDefaultParameters (content);
122                    contentParams.put("description", _getNoModifiableCatalogDescription(content));
123                    
124                    @SuppressWarnings("unchecked")
125                    List<Map<String, Object>> unModifiableCatalogContents = (List<Map<String, Object>>) results.get("unmodifiablecatalog-contents");
126                    unModifiableCatalogContents.add(contentParams);
127                    
128                    error = true;
129                }
130                
131                // Is part of ODF contents ?
132                if (_isReferenced(content))
133                {
134                    Map<String, Object> contentParams = getContentDefaultParameters (content);
135                    contentParams.put("description", _getReferencedDescription(content));
136                    
137                    @SuppressWarnings("unchecked")
138                    List<Map<String, Object>> referencedContents = (List<Map<String, Object>>) results.get("referenced-contents");
139                    referencedContents.add(contentParams);
140                    
141                    error = true;
142                }
143                
144                if (_isAllRight (content, error, results))
145                {
146                    Map<String, Object> contentParams = getContentDefaultParameters (content);
147                    contentParams.put("description", _getAllRightDescription(content));
148                    
149                    @SuppressWarnings("unchecked")
150                    List<Map<String, Object>> allrightContents = (List<Map<String, Object>>) results.get("allright-contents");
151                    allrightContents.add(contentParams);
152                }
153            }
154        }
155        
156        return results;
157    }
158    
159    private I18nizableText _getNoModifiableCatalogDescription (Content content)
160    {
161        List<String> modifiableI18nParameters = new ArrayList<>();
162        modifiableI18nParameters.add(content.getTitle());
163        
164        I18nizableText ed = (I18nizableText) this._script.getParameters().get("nomodifiablecatalog-content-description");
165        return new I18nizableText(ed.getCatalogue(), ed.getKey(), modifiableI18nParameters);
166    }
167    
168    private I18nizableText _getReferencedDescription (Content content)
169    {
170        List<String> modifiableI18nParameters = new ArrayList<>();
171        modifiableI18nParameters.add(content.getTitle());
172        
173        I18nizableText ed = (I18nizableText) this._script.getParameters().get("referenced-content-description");
174        return new I18nizableText(ed.getCatalogue(), ed.getKey(), modifiableI18nParameters);
175    }
176    
177    private boolean _isCatalogModifiable (Content content)
178    {
179        // Browse the ODF content children to detect if a child content is shared with other
180        return !_hasSharedContent(content);
181    }
182    
183    private boolean _isReferenced (Content content)
184    {
185        if (content instanceof ProgramPart)
186        {
187            return content.getMetadataHolder().getStringArray(ProgramPart.METADATA_PARENT_PROGRAM_PARTS, new String[0]).length > 0;
188        }
189        else if (content instanceof Course)
190        {
191            return content.getMetadataHolder().getStringArray(Course.METADATA_PARENT_COURSE_LISTS, new String[0]).length > 0;
192        }
193        else if (content instanceof CourseList)
194        {
195            return content.getMetadataHolder().getStringArray(CourseList.METADATA_PARENT_COURSES, new String[0]).length > 0;
196        }
197        return true;
198    }
199    
200    private boolean _hasSharedContent (Content content)
201    {
202        if (content instanceof TraversableProgramPart)
203        {
204            String[] children = content.getMetadataHolder().getStringArray(TraversableProgramPart.METADATA_CHILD_PROGRAM_PARTS, new String[0]);
205            for (String id : children)
206            {
207                try
208                {
209                    Content child = _resolver.resolveById(id);
210                    _isShared(child, ProgramPart.METADATA_PARENT_PROGRAM_PARTS);
211                }
212                catch (UnknownAmetysObjectException e)
213                {
214                    // Nothing
215                }
216            }
217        }
218        
219        if (content instanceof CourseContainer)
220        {
221            for (Course course : ((CourseContainer) content).getCourses())
222            {
223                _isShared(course, Course.METADATA_PARENT_COURSE_LISTS);
224            }
225        }
226        
227        if (content instanceof CourseListContainer)
228        {
229            for (CourseList cl : ((CourseListContainer) content).getCourseLists())
230            {
231                try
232                {
233                    if (_hasSharedContent(cl))
234                    {
235                        return true;
236                    }
237                }
238                catch (UnknownAmetysObjectException e)
239                {
240                    // Nothing
241                }
242            }
243        }
244        
245        if (content instanceof Course)
246        {
247            for (CoursePart coursePart : ((Course) content).getCourseParts())
248            {
249                _isShared(coursePart, CoursePart.METADATA_PARENT_COURSES);
250            }
251        }
252        
253        return false;
254    }
255    
256    private boolean _isShared(Content content, String metadataName)
257    {
258        try
259        {
260            String[] parentIds = content.getMetadataHolder().getStringArray(metadataName, new String[0]);
261            if (parentIds.length > 1 || _hasSharedContent(content))
262            {
263                return true;
264            }
265        }
266        catch (UnknownAmetysObjectException e)
267        {
268            // Nothing
269        }
270        
271        return false;
272    }
273}