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