001package arcommon.persistens;
002
003import java.io.BufferedWriter;
004import java.io.File;
005import java.io.IOException;
006
007import arcommon.FileUtil;
008import arcommon.ReflectionUtil;
009import arcommon.Util;
010import arcommon.xml.XmlUtil;
011
012public class SettingsUtil {
013    private static final String XML_SETTINGS_EXTENSION = "xml";
014    private static final String JAVA_SERIALIZATION_SETTINGS_EXTENSION = "dat";
015    
016    private static String settingsFileName = "Settings." + JAVA_SERIALIZATION_SETTINGS_EXTENSION;
017    private static boolean settingsFileNameSet = false;
018    public static boolean useXml = true;
019    public static boolean saveXmlOnlyIfChanged = true;
020    private static String originalSettingsContent;
021    public static boolean warnOnNotExist = true;
022    
023    private static ISettings settings;
024    private static ISettings defaultSettings;
025    private static Class<? extends ISettings> defaultSettingsClass;
026
027    public static String getSettingsFileName() {
028        return settingsFileName;
029    }
030
031    public static void setSettingsFileName(String psettingsFileName) {
032        if (psettingsFileName == null) {
033            throw new IllegalArgumentException("psettingsFileName == null");
034        }
035        if (settingsFileNameSet) {
036            throw new RuntimeException("settingsFileName has already been set to \"" + settingsFileName + "\"");
037        }
038        settingsFileName = psettingsFileName;
039        settingsFileNameSet = true;
040    }
041    
042    public static ISettings load() {
043        if (settings == null && !loadLocal()) {
044            if (defaultSettings == null && defaultSettingsClass == null) {
045                throw new RuntimeException("defaultSettings (and defaultSettingsClass) is null. Call setDefaultSettings()!");
046            }
047            if (defaultSettingsClass != null) {
048                defaultSettings = ReflectionUtil.createInstanceDefaultConstructor(defaultSettingsClass);
049            }
050            settings = defaultSettings;
051        }
052        return settings;
053    }
054
055    public static void setDefaultSettings(ISettings pdefaultSettings) {
056        if (pdefaultSettings == null) {
057            throw new IllegalArgumentException("pdefaultSettings == null");
058        }
059        if (defaultSettings != null) {
060            throw new RuntimeException("defaultSettings has already been set to " + defaultSettings);
061        }
062        if (defaultSettingsClass != null) {
063            throw new RuntimeException("defaultSettingsClass has already been set to " + defaultSettingsClass);
064        }
065        defaultSettings = pdefaultSettings;
066    }
067
068    public static void setDefaultSettingsClass(Class<? extends ISettings> pdefaultSettingsClass) {
069        if (pdefaultSettingsClass == null) {
070            throw new IllegalArgumentException("pdefaultSettingsClass == null");
071        }
072        if (defaultSettings != null) {
073            throw new RuntimeException("defaultSettings has already been set to " + defaultSettings);
074        }
075        if (defaultSettingsClass != null) {
076            throw new RuntimeException("defaultSettingsClass has already been set to " + defaultSettingsClass);
077        }
078        defaultSettingsClass = pdefaultSettingsClass;
079    }
080    
081    public static ISettings reload() {
082        settings = null;
083        return load();
084    }
085    
086    private static String calculateOldFileName() { // TODO Remove when all old settings files have been deleted.
087        String tempFileName = settingsFileName.substring(0, settingsFileName.length() - XML_SETTINGS_EXTENSION.length());
088        tempFileName += JAVA_SERIALIZATION_SETTINGS_EXTENSION;
089        return tempFileName;
090    }
091
092    private static boolean loadLocal() {
093        if (!new File(settingsFileName).exists()) {
094            if (warnOnNotExist) {
095                Util.printMessageWithSourceLine("!new File(" + settingsFileName + ").exists()");
096            }
097            if (useXml && settingsFileName.endsWith(XML_SETTINGS_EXTENSION)) {
098                String tempFileName = calculateOldFileName();
099                if (!new File(tempFileName).exists()) {
100                    if (warnOnNotExist) {
101                        Util.printMessageWithSourceLine("!new File(" + tempFileName + ").exists()");
102                    }
103                } else {
104                    settings = (ISettings)SerializableUtil.loadObjectFromFile(tempFileName);
105                    return settings != null;
106                }
107            }
108            return false;
109        }
110        
111        if (useXml) {
112            if (saveXmlOnlyIfChanged) {
113                originalSettingsContent = FileUtil.readFile(settingsFileName, XmlUtil.XML_ENCODING);
114                settings = (ISettings)XmlUtil.xmlStringToObject(originalSettingsContent);
115            } else {
116                settings = (ISettings)SerializableUtil.loadObjectFromFileAsXml(settingsFileName);
117            }
118        } else {
119            settings = (ISettings)SerializableUtil.loadObjectFromFile(settingsFileName);
120        }
121        
122        return settings != null;
123    }
124
125    public static void saveUsingTempFileIfChanged() {
126        saveUsingTempFileIfChanged(settingsFileName);
127    }
128    
129    public static void saveUsingTempFileIfChanged(String fileName) {
130        String currentSettingsXmlString = null;
131        if (useXml && saveXmlOnlyIfChanged) {
132            currentSettingsXmlString = XmlUtil.objectToXmlString(settings);
133            if (currentSettingsXmlString.equals(originalSettingsContent)) {
134                Util.printMessageWithSourceLine("Settings not changed => No save");
135                return ;
136            }
137        }
138        
139        final String currentSettingsXmlStringFinal = currentSettingsXmlString;
140        FileUtil.WriteUsingTempFileAction saveUsingTempFileAction = new FileUtil.WriteUsingTempFileAction() {
141            @Override
142            public void saveFile(String tempFileName, boolean append, String encoding) throws IOException {
143                if (currentSettingsXmlStringFinal != null) {
144                    FileUtil.writeFile(tempFileName, currentSettingsXmlStringFinal, false, XmlUtil.XML_ENCODING);
145                } else {
146                    save(tempFileName);
147                }
148            }
149            
150            @Override
151            public void writeContentOfFile(BufferedWriter out) throws IOException {
152                throw new RuntimeException("Internal error. Should not be called");
153            }
154            
155            @Override
156            public boolean backupOldFile() {
157                return false;
158            }
159        };
160        FileUtil.writeUsingTempFile(fileName, saveUsingTempFileAction);
161    }
162    
163    public static void save() {
164        save(settingsFileName);
165    }
166    
167    public static void save(String fileName) {
168        if (useXml) {
169            SerializableUtil.saveObjectToFileAsXML(fileName, settings);
170            
171            String tempFileName = calculateOldFileName();
172            File file = new File(tempFileName);
173            if (file.exists()) {
174                Util.printMessageWithSourceLine("new File(" + tempFileName + ").exists() => Delete");
175                file.delete();
176            }
177        } else {
178            SerializableUtil.saveObjectToFile(fileName, settings);
179        }
180    }
181}