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.odf.program;
017
018import java.util.HashMap;
019import java.util.Map;
020import java.util.Map.Entry;
021
022import org.apache.avalon.framework.component.Component;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.avalon.framework.service.Serviceable;
026
027import org.ametys.cms.ObservationConstants;
028import org.ametys.cms.repository.ModifiableContent;
029import org.ametys.core.observation.Event;
030import org.ametys.core.observation.ObservationManager;
031import org.ametys.core.ui.Callable;
032import org.ametys.core.user.CurrentUserProvider;
033import org.ametys.core.user.UserIdentity;
034import org.ametys.odf.ODFHelper;
035import org.ametys.odf.observation.OdfObservationConstants;
036import org.ametys.odf.translation.TranslationHelper;
037import org.ametys.plugins.repository.AmetysObjectResolver;
038import org.ametys.plugins.repository.UnknownAmetysObjectException;
039
040/**
041 * DAO for manipulating ODF programs.
042 *
043 */
044public class ProgramDAO implements Serviceable, Component
045{
046    /** The Avalon role */
047    public static final String ROLE = ProgramDAO.class.getName();
048    
049    /** The ametys object resolver */
050    protected AmetysObjectResolver _resolver;
051    /** Observer manager. */
052    protected ObservationManager _observationManager;
053    /** The current user provider. */
054    protected CurrentUserProvider _currentUserProvider;
055    /** ODF helper */
056    protected ODFHelper _odfHelper;
057    
058    @Override
059    public void service(ServiceManager manager) throws ServiceException
060    {
061        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
062        _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE);
063        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
064        _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE);
065    }
066    
067    /**
068     * Translates a given program in a language
069     * @param contentId The program id
070     * @param language The language in which to translate
071     * @param fullCopy True if full copy
072     * @return A Map with id of translated program or an error message
073     * @throws Exception if an error occurs
074     */
075    @Callable
076    public Map<String, String> translateProgram (String contentId, String language, boolean fullCopy) throws Exception
077    {
078        Map<String, String> result = new HashMap<>();
079        
080        Program program = _resolver.resolveById(contentId);
081        
082        if (program.getLanguage().equals(language))
083        {
084            result.put("error", "same-language");
085            return result;
086        }
087        
088        Map<String, String> translatedContents = new HashMap<>();
089        
090        String translatedProgramId = null;
091        
092        // Get existing translations
093        Map<String, String> translations = TranslationHelper.getTranslations(program);
094        
095        if (!translations.containsKey(language))
096        {
097            ModifiableContent translatedProgram = _odfHelper.copyProgramItem(program, null, language, null, fullCopy, translatedContents, translatedContents, translatedContents, translatedContents, translatedContents);
098            translatedProgramId = translatedProgram.getId();
099        }
100        else
101        {
102            translatedProgramId = translations.get(language);
103            // Check if content exists
104            try
105            {
106                _resolver.resolveById(translatedProgramId);
107                result.put("error", "already-exists");
108            }
109            catch (UnknownAmetysObjectException e) 
110            {
111                ModifiableContent translatedProgram = _odfHelper.copyProgramItem(program, null, language, null, fullCopy, translatedContents, translatedContents, translatedContents, translatedContents, translatedContents);
112                translatedProgramId = translatedProgram.getId();
113            }
114        }
115        
116        linkTranslations(translatedContents);
117        
118        result.put("translated-program-id", translatedProgramId);
119        
120        return result;
121    }
122    
123    /**
124     * Store links to the other translations for all copied contents
125     * @param translatedContents The translated contents
126     */
127    protected void linkTranslations(Map<String, String> translatedContents)
128    {
129        for (Entry<String, String> entry : translatedContents.entrySet())
130        {
131            ModifiableContent originalContent = _resolver.resolveById(entry.getKey());
132            ModifiableContent translatedContent = _resolver.resolveById(entry.getValue());
133            
134            linkTranslations(originalContent, translatedContent);
135            
136            originalContent.saveChanges();
137            translatedContent.saveChanges();
138            
139            Map<String, Object> eventParams = new HashMap<>();
140            eventParams.put(ObservationConstants.ARGS_CONTENT, originalContent);
141            
142            _observationManager.notify(new Event(OdfObservationConstants.ODF_CONTENT_TRANSLATED, _getCurrentUser(), eventParams));
143        }
144    }
145    
146    /**
147     * Store links to the other translations in all the translated objects.
148     * @param originalContent The original content
149     * @param translatedContent The translated content
150     */
151    protected void linkTranslations(ModifiableContent originalContent, ModifiableContent translatedContent)
152    {
153        Map<String, String> translations = TranslationHelper.getTranslations(originalContent);
154        
155        // Add the original and translated references.
156        translations.put(originalContent.getLanguage(), originalContent.getId());
157        translations.put(translatedContent.getLanguage(), translatedContent.getId());
158        
159        for (String contentId : translations.values())
160        {
161            ModifiableContent content = _resolver.resolveById(contentId);
162            
163            Map<String, String> otherTranslations = new HashMap<>(translations);
164            otherTranslations.remove(content.getLanguage());
165            
166            TranslationHelper.setTranslations(content, otherTranslations);
167        }
168    }
169    
170    /**
171     * Provides the current user.
172     * @return the identity which cannot be <code>null</code>.
173     */
174    protected UserIdentity _getCurrentUser()
175    {
176        return _currentUserProvider.getUser();
177    }
178
179}