001/*
002 *  Copyright 2014 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.generators;
017
018import java.io.IOException;
019import java.time.ZonedDateTime;
020import java.time.format.DateTimeFormatter;
021import java.util.Date;
022import java.util.GregorianCalendar;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.ProcessingException;
030import org.apache.cocoon.environment.ObjectModelHelper;
031import org.apache.cocoon.environment.Request;
032import org.apache.cocoon.generation.ServiceableGenerator;
033import org.apache.cocoon.xml.AttributesImpl;
034import org.apache.cocoon.xml.XMLUtils;
035import org.apache.commons.lang.StringUtils;
036import org.xml.sax.SAXException;
037
038import org.ametys.core.user.User;
039import org.ametys.core.user.UserIdentity;
040import org.ametys.core.user.UserManager;
041import org.ametys.core.util.DateUtils;
042import org.ametys.plugins.explorer.calendars.Calendar;
043import org.ametys.plugins.explorer.calendars.CalendarEvent;
044import org.ametys.plugins.explorer.workflow.AbstractExplorerNodeWorkflowComponent;
045import org.ametys.plugins.repository.AmetysObject;
046import org.ametys.plugins.repository.AmetysObjectResolver;
047import org.ametys.plugins.repository.ModifiableAmetysObject;
048import org.ametys.plugins.repository.RemovableAmetysObject;
049import org.ametys.plugins.workflow.support.WorkflowHelper;
050import org.ametys.plugins.workflow.support.WorkflowProvider;
051import org.ametys.runtime.i18n.I18nizableText;
052
053import com.opensymphony.workflow.Workflow;
054import com.opensymphony.workflow.spi.Step;
055
056/**
057 * Generate all the needed calendar's informations
058 */
059public class CalendarEventInfoGenerator extends ServiceableGenerator
060{
061    /** The object resolver */
062    protected AmetysObjectResolver _resolver;
063    /** The ametys users manager */
064    protected UserManager _userManager;
065    /** The workflow provider */
066    protected WorkflowProvider _workflowProvider;
067    /** The workflow helper */
068    protected WorkflowHelper _workflowHelper;
069    
070    @Override
071    public void service(ServiceManager serviceManager) throws ServiceException
072    {
073        super.service(serviceManager);
074        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
075        _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE);
076        _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE);
077        _workflowHelper = (WorkflowHelper) serviceManager.lookup(WorkflowHelper.ROLE);
078    }
079    
080    public void generate() throws IOException, SAXException, ProcessingException
081    {
082        Request request = ObjectModelHelper.getRequest(objectModel);
083        
084        String startDateString = request.getParameter("start");
085        Date startDate = DateUtils.parse(startDateString);
086
087        String endDateString = request.getParameter("end");
088        Date endDate = DateUtils.parse(endDateString);
089
090        String handleWorkflowInit = request.getParameter("handleWorkflowInit");
091
092        contentHandler.startDocument();
093        XMLUtils.startElement(contentHandler, "infos");
094        
095        String ids = request.getParameter("ids");
096        String occurrencesDate = request.getParameter("occurrencesDate");
097        
098        if (StringUtils.isNotBlank(ids) && StringUtils.isNotBlank(occurrencesDate))
099        {
100            String[] eventsIds = StringUtils.split(ids, ",");
101            String[] eventOccurrencesDate = StringUtils.split(occurrencesDate, ",");
102            
103            XMLUtils.startElement(contentHandler, "events");
104            for (int i = 0; i < eventsIds.length; i++)
105            {
106                String id = eventsIds[i];
107                String occurrenceDate = eventOccurrencesDate[i];
108                
109                long date = ZonedDateTime.parse(occurrenceDate, DateTimeFormatter.ISO_DATE_TIME).toInstant().toEpochMilli();
110                CalendarEvent event = _resolver.resolveById(id);
111                _saxEvent(event, new Date(date));
112            }
113            XMLUtils.endElement(contentHandler, "events");
114        }
115        else
116        {
117            String calendarId = request.getParameter("calendarId");
118            if (calendarId != null)
119            {
120                Calendar calendar = _resolver.resolveById(calendarId);
121                
122                if ("true".equals(request.getParameter("fromRootCalendar")))
123                {
124                    AmetysObject parent = calendar;
125                        
126                    while (parent instanceof Calendar)
127                    {
128                        calendar = (Calendar) parent;
129                        parent = parent.getParent();
130                    }
131                }
132                
133                _saxCalendar(calendar, "true".equals(request.getParameter("recursive")), "true".equals(request.getParameter("sax-events")), startDate, endDate, handleWorkflowInit);
134            }
135        }
136        
137        XMLUtils.endElement(contentHandler, "infos");  
138        contentHandler.endDocument();
139    }
140
141    private void _saxCalendar(Calendar calendar, boolean recursive, boolean saxEvents, Date startDate, Date endDate, String handleWorkflowInit) throws SAXException
142    {
143        AttributesImpl attr = new AttributesImpl();
144        attr.addCDATAAttribute("id", calendar.getId());
145        attr.addCDATAAttribute("title", calendar.getName());
146        attr.addCDATAAttribute("desc", calendar.getDescription());
147        attr.addCDATAAttribute("templateDesc", calendar.getTemplateDescription());
148        attr.addCDATAAttribute("color", calendar.getColor());
149        attr.addCDATAAttribute("workflowName", calendar.getWorkflowName());
150        attr.addCDATAAttribute("modifiable", calendar instanceof ModifiableAmetysObject ? "true" : "false");
151        attr.addCDATAAttribute("hasRight", "true");
152        attr.addCDATAAttribute("removable", calendar instanceof RemovableAmetysObject ? "true" : "false");
153        
154        HashMap<String, Object> inputs = new HashMap<>();
155        inputs.put(AbstractExplorerNodeWorkflowComponent.EXPLORERNODE_KEY, calendar);
156        if (handleWorkflowInit == null)
157        {
158            Workflow workflow = _workflowProvider.getAmetysObjectWorkflow();
159            attr.addCDATAAttribute("canInitWorkflow", workflow.canInitialize(calendar.getWorkflowName(), 1, inputs) ? "true" : "false");
160        }
161        else
162        {
163            attr.addCDATAAttribute("canInitWorkflow", "true");
164        }
165        XMLUtils.startElement(contentHandler, "calendar", attr);
166
167        if (recursive)
168        {
169            XMLUtils.startElement(contentHandler, "calendars");
170            for (AmetysObject object : calendar.getChildren())
171            {
172                if (object instanceof Calendar)
173                {
174                    Calendar subCalendar = (Calendar) object;
175                    _saxCalendar(subCalendar, recursive, saxEvents, startDate, endDate, handleWorkflowInit);
176                }
177            }
178            XMLUtils.endElement(contentHandler, "calendars");
179        }
180        
181        if (saxEvents)
182        {
183            XMLUtils.startElement(contentHandler, "events");
184            
185            for (Map.Entry<CalendarEvent, List<Date>> entry : calendar.getEvents(startDate, endDate).entrySet())
186            {
187                CalendarEvent event = entry.getKey();
188                List<Date> occurences = entry.getValue();
189                for (Date date : occurences)
190                {
191                    _saxEvent(event, date);
192                }
193            }
194            XMLUtils.endElement(contentHandler, "events");
195        }
196        
197        XMLUtils.endElement(contentHandler, "calendar");
198    }
199
200    private void _saxEvent(CalendarEvent event, Date date) throws SAXException
201    {
202        AttributesImpl attr = new AttributesImpl();
203        String id = event.getId() + "$" + DateUtils.dateToString(date);
204        attr.addCDATAAttribute("id", id);
205        attr.addCDATAAttribute("calendarId", event.getParent().getId());
206        attr.addCDATAAttribute("workflowId", event.getWorkflowId() + "");
207        attr.addCDATAAttribute("color", ((Calendar) event.getParent()).getColor());
208        attr.addCDATAAttribute("modifiable", "true");
209        
210        XMLUtils.startElement(contentHandler, "event", attr);
211        
212        Workflow workflow = _workflowProvider.getAmetysObjectWorkflow(event);
213        List<Step> listSteps = workflow.getCurrentSteps(event.getWorkflowId());
214        if (!listSteps.isEmpty())
215        {
216            // We select the first current step
217            Step step = listSteps.get(0);
218            String stepDesc = _workflowHelper.getStepName(((Calendar) event.getParent()).getWorkflowName(), step.getStepId());
219            I18nizableText workflowStepName = new I18nizableText("application", stepDesc);
220            
221            if ("application".equals(workflowStepName.getCatalogue()))
222            {
223                XMLUtils.createElement(contentHandler, "icon-small-workflow", "/plugins/explorer/resources_workflow/" + workflowStepName.getKey() + "-small.png");
224            }
225            else
226            {
227                String pluginName = workflowStepName.getCatalogue().substring("plugin.".length());
228                XMLUtils.createElement(contentHandler, "icon-small-workflow", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-small.png");
229            }
230        }
231        
232        XMLUtils.createElement(contentHandler, "title", event.getTitle());
233        XMLUtils.createElement(contentHandler, "desc", event.getDescription());
234        XMLUtils.createElement(contentHandler, "fullDay", event.getFullDay() ? "true" : "false");
235        
236        XMLUtils.createElement(contentHandler, "recurrenceType", event.getRecurrenceType().toString());
237        
238        String untilDateAsString = "";
239        Date untilDate = event.getRepeatUntil();
240        if (untilDate != null)
241        {
242            untilDateAsString =  DateUtils.dateToString(untilDate);
243        }
244        XMLUtils.createElement(contentHandler, "untilDate", untilDateAsString);
245        
246        Date firstStartDateEvent = event.getStartDate();
247        Date firstEndDateEvent = event.getEndDate();
248        
249        long diff = firstEndDateEvent.getTime() - firstStartDateEvent.getTime();
250        Date startDateEvent = date;
251        Date endDateEvent = new Date(date.getTime() + diff);
252        
253        if (event.getFullDay())
254        {
255            GregorianCalendar gcStart = new GregorianCalendar();
256            gcStart.setTime(startDateEvent);
257            gcStart.set(java.util.Calendar.HOUR_OF_DAY, 0);
258            gcStart.set(java.util.Calendar.MINUTE, 0);
259            gcStart.set(java.util.Calendar.SECOND, 0);
260            gcStart.set(java.util.Calendar.MILLISECOND, 0);
261     
262            startDateEvent = gcStart.getTime();
263            
264            GregorianCalendar gcEnd = new GregorianCalendar();
265            gcEnd.setTime(endDateEvent);
266            gcEnd.set(java.util.Calendar.HOUR_OF_DAY, 23);
267            gcEnd.set(java.util.Calendar.MINUTE, 59);
268            gcEnd.set(java.util.Calendar.SECOND, 59);
269            gcEnd.set(java.util.Calendar.MILLISECOND, 999);
270     
271            endDateEvent = gcEnd.getTime();
272        }
273        
274        XMLUtils.createElement(contentHandler, "startDate", DateUtils.dateToString(startDateEvent));
275        XMLUtils.createElement(contentHandler, "endDate", DateUtils.dateToString(endDateEvent));
276        _saxUser(event.getCreator(), "creator");
277        XMLUtils.createElement(contentHandler, "creationDate", DateUtils.dateToString(event.getCreationDate()));
278        _saxUser(event.getLastContributor(), "contributor");
279        XMLUtils.createElement(contentHandler, "lastModified", DateUtils.dateToString(event.getLastModified()));
280        
281        UserIdentity validator = event.getLastValidator();
282        if (validator != null)
283        {
284            _saxUser(validator, "validator");
285        }
286        
287        Date lastValidated = event.getLastValidated();
288        if (lastValidated != null)
289        {
290            XMLUtils.createElement(contentHandler, "lastValidated", DateUtils.dateToString(lastValidated));
291        }
292        
293        XMLUtils.endElement(contentHandler, "event");
294    }
295    
296    private void _saxUser(UserIdentity userIdentity, String tagName) throws SAXException
297    {
298        AttributesImpl attr = new AttributesImpl();
299        attr.addCDATAAttribute("login", userIdentity.getLogin());
300        attr.addCDATAAttribute("population", userIdentity.getPopulationId());
301        
302        User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
303        if (user != null)
304        {
305            attr.addCDATAAttribute("fullName", user.getFullName());
306        }
307        
308        XMLUtils.createElement(contentHandler, tagName, attr);
309    }
310}