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