001/*
002 *  Copyright 2015 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.plugins.explorer.calendars.clientside;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.LinkedList;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.commons.lang3.BooleanUtils;
030
031import org.ametys.core.ui.Callable;
032import org.ametys.core.ui.StaticClientSideElement;
033import org.ametys.plugins.explorer.calendars.Calendar;
034import org.ametys.plugins.explorer.calendars.CalendarEvent;
035import org.ametys.plugins.explorer.workflow.AbstractExplorerNodeWorkflowComponent;
036import org.ametys.plugins.repository.AmetysObject;
037import org.ametys.plugins.repository.AmetysObjectResolver;
038import org.ametys.plugins.workflow.support.WorkflowHelper;
039import org.ametys.plugins.workflow.support.WorkflowProvider;
040import org.ametys.runtime.i18n.I18nizableText;
041
042import com.opensymphony.workflow.Workflow;
043import com.opensymphony.workflow.loader.ActionDescriptor;
044import com.opensymphony.workflow.loader.StepDescriptor;
045import com.opensymphony.workflow.loader.WorkflowDescriptor;
046import com.opensymphony.workflow.spi.Step;
047
048/**
049 * Ribbon tab client side element for calendars
050 */
051public class CalendarsTabClientSideElement extends StaticClientSideElement
052{
053    /** The workflow provider */
054    protected WorkflowProvider _workflowProvider;
055    
056    /** The workflow helper */
057    protected WorkflowHelper _workflowHelper;
058    
059    /** The ametys resolver */
060    protected AmetysObjectResolver _resolver;
061    
062    @Override
063    public void service(ServiceManager serviceManager) throws ServiceException
064    {
065        super.service(serviceManager);
066        _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE);
067        _workflowHelper = (WorkflowHelper) serviceManager.lookup(WorkflowHelper.ROLE);
068        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
069    }
070    
071    @Override
072    public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters)
073    {
074        List<Script> scripts = super.getScripts(ignoreRights, contextParameters);
075        if (scripts.size() > 0)
076        {
077            scripts.get(0).getParameters().put("workflows", getWorkflowsInfo());
078        }
079        return scripts;
080    }
081    
082    /**
083     * Get info about each existing workflow.
084     * @return a list of map containing workflow info. For each entry, the key
085     *         is the workflow name and the value is a map containing the
086     *         necessary workflow data
087     */
088    public Map<String, Object> getWorkflowsInfo()
089    {
090        Map<String, Object> workflowsMap = new HashMap<>();
091        
092        for (String workflowName : _workflowHelper.getWorkflowNames())
093        {
094            Map<String, Object> workflowEntry = new HashMap<>();
095            workflowsMap.put(workflowName, workflowEntry);
096            
097            WorkflowDescriptor workflowDescriptor = _workflowHelper.getWorkflowDescriptor(workflowName);
098            if (workflowDescriptor != null)
099            {
100                _addWorkflowInfo(workflowEntry, workflowDescriptor);
101                _addStepsInfo(workflowEntry, workflowDescriptor);
102                _addActionsInfo(workflowEntry, workflowDescriptor);
103            }
104        }
105        
106        return workflowsMap;
107    }
108    
109    /**
110     * Add workflow info to the result map
111     * @param result The result map to populate
112     * @param workflowDescriptor the workflow descriptor
113     */
114    protected void _addWorkflowInfo(Map<String, Object> result, WorkflowDescriptor workflowDescriptor)
115    {
116        result.put("name", workflowDescriptor.getName());
117    }
118    
119    /**
120     * Add steps info to the result map
121     * @param result The result map to populate
122     * @param workflowDescriptor the workflow descriptor
123     */
124    protected void _addStepsInfo(Map<String, Object> result, WorkflowDescriptor workflowDescriptor)
125    {
126        Map<String, Object> stepMap = new HashMap<>();
127        result.put("steps", stepMap);
128        
129        List<StepDescriptor> steps = workflowDescriptor.getSteps();
130        for (StepDescriptor step : steps)
131        {
132            _addStepInfo(stepMap, workflowDescriptor, step);
133        }
134    }
135
136    /**
137     * Add step info to the map of steps
138     * @param stepMap The step map to populate
139     * @param workflowDescriptor the workflow descriptor
140     * @param step the step descriptor
141     */
142    protected void _addStepInfo(Map<String, Object> stepMap, WorkflowDescriptor workflowDescriptor, StepDescriptor step)
143    {
144        int stepId = step.getId();
145        String stepName = step.getName();
146        
147        Map<String, Object> stepInfo = new HashMap<>();
148        stepMap.put(String.valueOf(stepId), stepInfo);
149        
150        stepInfo.put("id", stepId);
151        stepInfo.put("name", stepName);
152        
153        stepInfo.put("label", new I18nizableText("application", stepName));
154        stepInfo.put("description", new I18nizableText("application", stepName + "_DESCRIPTION"));
155        
156        // Default icons
157        String[] icons = new String[]{"-small", "-medium", "-large"};
158        for (String icon : icons)
159        {
160            I18nizableText i18nStepName = new I18nizableText("application", stepName);
161            if ("application".equals(i18nStepName.getCatalogue()))
162            {
163                stepInfo.put("icon" + icon, new I18nizableText("/plugins/explorer/resources_workflow/" + i18nStepName.getKey() + icon + ".png"));
164            }
165            else
166            {
167                String pluginName = i18nStepName.getCatalogue().substring("plugin.".length());
168                stepInfo.put("icon" + icon, new I18nizableText("/plugins/" + pluginName + "/resources/img/workflow/" + i18nStepName.getKey() + icon + ".png"));
169            }
170        }
171        
172        List<Integer> actionsId = new LinkedList<>();
173        stepInfo.put("actions", actionsId);
174        
175        for (int actionId : _workflowHelper.getAllActionsFromStep(workflowDescriptor.getName(), stepId))
176        {
177            actionsId.add(actionId);
178        }
179    }
180    
181    /**
182     * Add actions info to the result map
183     * @param result The result map to populate
184     * @param workflowDescriptor the workflow descriptor
185     */
186    protected void _addActionsInfo(Map<String, Object> result, WorkflowDescriptor workflowDescriptor)
187    {
188        Map<String, Object> actionMap = new HashMap<>();
189        result.put("actions", actionMap);
190        
191        int[] allActions = _workflowHelper.getAllActions(workflowDescriptor.getName());
192        for (int actionId : allActions)
193        {
194            ActionDescriptor action = workflowDescriptor.getAction(actionId);
195            _addActionInfo(actionMap, workflowDescriptor, action);
196        }
197    }
198
199    /**
200     * Add action info to the map of actions
201     * @param actionMap The action map to populate
202     * @param workflowDescriptor the workflow descriptor
203     * @param action the action descriptor
204     */
205    protected void _addActionInfo(Map<String, Object> actionMap, WorkflowDescriptor workflowDescriptor, ActionDescriptor action)
206    {
207        int actionId = action.getId();
208        String actionName = action.getName();
209        
210        Map<String, Object> actionInfo = new HashMap<>();
211        actionMap.put(String.valueOf(actionId), actionInfo);
212        
213        actionInfo.put("id", actionId);
214        actionInfo.put("name", actionName);
215        
216        actionInfo.put("label", new I18nizableText("application", actionName));
217        actionInfo.put("description", new I18nizableText("application", actionName + "_DESCRIPTION"));
218        
219        actionInfo.put("internal", BooleanUtils.toBoolean((String) action.getMetaAttributes().get("internal")));
220    }
221    
222    /**
223     * Retrieves the child workflow names for a given calendar
224     * @param calendarId The calendar identifier
225     * @return The child workflow names
226     */
227    @Callable
228    public Set<String> getSubWorkflowNames(String calendarId)
229    {
230        Calendar calendar = _resolver.resolveById(calendarId);
231        return getSubWorkflowNames(calendar);
232    }
233    
234    /**
235     * Retrieves the child workflow names for a given calendar
236     * @param calendar The calendar 
237     * @return The child workflow names
238     */
239    public Set<String> getSubWorkflowNames(Calendar calendar)
240    {
241        Set<String> workflowNames = new HashSet<>();
242        
243        for (AmetysObject ao : calendar.getChildren())
244        {
245            if (ao instanceof Calendar)
246            {
247                Calendar child = (Calendar) ao;
248                workflowNames.add(child.getWorkflowName());
249                workflowNames.addAll(getSubWorkflowNames(child));
250            }
251        }
252        
253        return workflowNames;
254    }
255    
256    /**
257     * Get the workflow state of an event
258     * @param eventId The id of the event
259     * @param workflowName The workflow name
260     * @param workflowStepId  The workflow step id
261     * @param workflowActionsIds The list of action ids
262     * @return The workflow state
263     */
264    @Callable
265    public Map<String, Object> getWorkflowState(String eventId, String workflowName, int workflowStepId, List<Integer> workflowActionsIds)
266    {
267        Map<String, Object> results = new HashMap<>();
268        Map<String, Object> eventMap = new HashMap<>();
269        results.put("event", eventMap);
270        
271        CalendarEvent event = _resolver.resolveById(eventId);
272        Workflow workflow = _workflowProvider.getAmetysObjectWorkflow(event);
273        
274        long wId = event.getWorkflowId();
275        if (!workflow.getWorkflowName(wId).equals(workflowName))
276        {
277            return results;
278        }
279        
280        List<Step> steps = workflow.getCurrentSteps(wId);
281        List<Integer> stepIds = new ArrayList<>();
282        for (Step step : steps)
283        {
284            stepIds.add(step.getStepId());
285        }
286        
287        if (stepIds.contains(workflowStepId))
288        {
289            Calendar calendar = event.getParent();
290            
291            eventMap.put("id", event.getId());
292            eventMap.put("parentId", calendar.getId());
293            eventMap.put("title", event.getTitle());
294            
295            String i18nKey = "PLUGINS_EXPLORER_CALENDAR_WORKFLOW_DESCRIPTION";
296            
297            List<String> workflowI18nParameters = new ArrayList<>();
298            workflowI18nParameters.add(event.getTitle());
299            
300            eventMap.put("description", new I18nizableText("plugin.explorer", i18nKey, workflowI18nParameters));
301
302            Map<String, Object> vars = new HashMap<>();
303            vars.put(AbstractExplorerNodeWorkflowComponent.EXPLORERNODE_KEY, calendar);
304
305            int[] availableActions = workflow.getAvailableActions(wId, vars);
306            Arrays.sort(availableActions);
307            
308            List<Integer> activeActions = new ArrayList<>();
309            for (int actionId : workflowActionsIds)
310            {
311                if (Arrays.binarySearch(availableActions, actionId) >= 0)
312                {
313                    activeActions.add(actionId);
314                }
315            }
316            eventMap.put("actions", activeActions);
317        }
318
319        return results;
320    }
321}