001/*
002 *  Copyright 2011 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.skinfactory.parameters;
017
018import java.io.IOException;
019import java.io.OutputStream;
020import java.nio.charset.StandardCharsets;
021import java.nio.file.Files;
022import java.nio.file.Path;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028import org.apache.cocoon.xml.AttributesImpl;
029import org.apache.cocoon.xml.XMLUtils;
030import org.apache.commons.io.IOUtils;
031import org.xml.sax.ContentHandler;
032import org.xml.sax.SAXException;
033
034import org.ametys.runtime.i18n.I18nizableText;
035import org.ametys.web.skin.SkinModel;
036
037/**
038 * Implementation of {@link AbstractSkinParameter} for a i18niable text
039 */
040public class I18nizableTextParameter extends AbstractSkinParameter
041{
042    private String _i18nKey;
043    private Map<String, String> _defaultValues;
044    
045    /**
046     * Constructor
047     * @param id the unique id
048     * @param label the label
049     * @param description the description
050     * @param i18nKey the i18n key
051     * @param defaultValues the default values
052     */
053    public I18nizableTextParameter(String id, I18nizableText label, I18nizableText description, String i18nKey, Map<String, String> defaultValues)
054    {
055        super(id, label, description);
056        _i18nKey = i18nKey;
057        _defaultValues = defaultValues;
058    }
059    
060    @Override
061    public SkinParameterType getType()
062    {
063        return SkinParameterType.I18N;
064    }
065    
066    /**
067     * Get the i18n key
068     * @return the i18n key
069     */
070    public String geti18nKey()
071    {
072        return _i18nKey;
073    }
074
075    /**
076     * Set the i18n key
077     * @param i18nKey the i18n key to set
078     */
079    public void setKey (String i18nKey)
080    {
081        _i18nKey = i18nKey;
082    }
083    
084    @Override
085    public void apply(Path tempDir, Path modelDir, Object value, String lang)
086    {
087        Path i18nFile = tempDir.resolve("i18n/messages.xml");
088        if (lang != null)
089        {
090            Path f = tempDir.resolve("i18n/messages_" + lang + ".xml");
091            if (Files.exists(f))
092            {
093                i18nFile = f;
094            }
095        }
096        
097        String string = _filetoString (i18nFile);
098        
099        Pattern pattern = null;
100        if (i18nFile.getFileName().toString().equals("messages.xml"))
101        {
102            pattern = Pattern.compile("^\\s*<message key=\"" + geti18nKey() + "\">([^<]*)<!--\\s*AMETYS\\s*\\(\\s*\"([^\"]+)\"\\s*(?:,\\s*([^,\"\\s]+|\"[^\"]*\")\\s*)?(?:,\\s*([^,\"\\s]+|\"[^\"]*\")\\s*)?\\)\\s*--></message>\\s*$", Pattern.MULTILINE); 
103            
104        }
105        else
106        {
107            pattern = Pattern.compile("^\\s*<message key=\"" + geti18nKey() + "\">([^<]*)</message>\\s*$", Pattern.MULTILINE); 
108        }
109        
110        Matcher matcher = pattern.matcher(string);
111        
112        try (OutputStream os = Files.newOutputStream(i18nFile))
113        {
114            int startIndex = 0;
115            
116            while (matcher.find())
117            {
118                int propertyStart = matcher.start(1);
119                
120                String beforeValue = string.substring(startIndex, propertyStart);
121                IOUtils.write(beforeValue, os, "UTF-8");
122                IOUtils.write((String) value, os, "UTF-8");
123                
124                startIndex = matcher.end(1);
125            }
126            
127            IOUtils.write(string.substring(startIndex), os, "UTF-8");
128        }
129        catch (IOException e)
130        {
131            throw new SkinParameterException ("Unable to apply css parameter '" + getId() + "'", e);
132        }
133    }
134    
135    private String _filetoString(Path file)
136    {
137        try
138        {
139            return Files.readString(file, StandardCharsets.UTF_8);
140        }
141        catch (IOException e)
142        {
143            throw new SkinParameterException ("Unable to parse file '" + file.getFileName().toString() + "'", e);
144        }
145    }
146    
147    @Override
148    public void toSAX(ContentHandler contentHandler, String modelName) throws SAXException
149    {
150        AttributesImpl attrs = new AttributesImpl();
151        attrs.addCDATAAttribute("id", getId());
152        attrs.addCDATAAttribute("type", SkinParameterType.I18N.name().toLowerCase());
153        
154        XMLUtils.startElement(contentHandler, "parameter", attrs);
155        
156        getLabel().toSAX(contentHandler, "label");
157        getDescription().toSAX(contentHandler, "description");
158        XMLUtils.createElement(contentHandler, "i18nkey", geti18nKey());
159        
160        XMLUtils.endElement(contentHandler, "parameter");
161    }
162    
163    @Override
164    public Map<String, Object> toJson(String modelName)
165    {
166        Map<String, Object> jsonObject = new HashMap<>();
167            
168        jsonObject.put("id", getId());
169        jsonObject.put("type", SkinParameterType.I18N.name().toLowerCase());
170        jsonObject.put("label", getLabel());
171        jsonObject.put("description", getDescription());
172        jsonObject.put("i18nkey", geti18nKey());
173        
174        return jsonObject;
175    }
176    
177    /**
178     * Get default values
179     * @return The default values
180     */
181    public Map<String, String> getDefaultValues ()
182    {
183        return _defaultValues;
184    }
185    
186    @Override
187    public String getDefaultValue(SkinModel model)
188    {
189        return getDefaultValue (model, null);
190    }
191    
192    @Override
193    public String getDefaultValue (SkinModel model, String lang)
194    {
195        if (lang != null && _defaultValues.containsKey(lang))
196        {
197            return _defaultValues.get(lang);
198        }
199        
200        return _defaultValues.entrySet().iterator().next().getValue();
201    }
202}