package er.extensions.components;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import org.apache.commons.lang3.CharEncoding;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WODisplayGroup;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSMutableSet;
import com.webobjects.foundation.NSPropertyListSerialization;
import er.extensions.eof.ERXS;
import er.extensions.foundation.ERXFileUtilities;
import er.extensions.foundation.ERXProperties;
import er.extensions.foundation.ERXStringUtilities;
import er.extensions.localization.ERXLocalizer;
/**
* Editor page for the localized files that are supplied in your settings. Note that the "save"
* overwrites the files in the bundle, so be sure to have it pointed to the original file and not
* the built bundle.
*
* @author ak
*/
public class ERXLocalizationEditor extends WOComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
public String currentLanguage;
public String currentFilename;
public String currentFramework;
public NSMutableArray<NSMutableDictionary<String, Object>> data;
public NSMutableDictionary currentEntry;
public String selectedFramework;
public String selectedFilename;
public String UNSET = "***UNSET***";
public WODisplayGroup displayGroup;
public String keyToAdd;
public ERXLocalizationEditor(WOContext context) {
super(context);
displayGroup = new WODisplayGroup();
displayGroup.setSortOrderings(ERXS.ascInsensitives("key"));
displayGroup.setNumberOfObjectsPerBatch(20);
displayGroup.setDefaultStringMatchFormat("*%@*");
displayGroup.setDefaultStringMatchOperator(EOQualifier.QualifierOperatorCaseInsensitiveLike.name());
}
@Override
public void awake() {
super.awake();
keyToAdd = null;
if (displayGroup != null) {
displayGroup.setSelectedObject(null);
}
}
public NSArray<String> availableLanguages() {
return ERXLocalizer.availableLanguages();
}
public NSArray<String> frameworkSearchPath() {
return ERXLocalizer.frameworkSearchPath();
}
public NSArray<String> fileNamesToWatch() {
return ERXLocalizer.fileNamesToWatch();
}
public URL urlForCurrentFile() {
return ERXFileUtilities.pathURLForResourceNamed(currentFilename, currentFramework, new NSArray<String>(currentLanguage));
}
public URL urlForSelectedFile() {
return ERXFileUtilities.pathURLForResourceNamed(selectedFilename, selectedFramework, new NSArray<String>(currentLanguage));
}
public boolean fileExistsInLanguage() {
return urlForCurrentFile() != null;
}
public void editFramework() {
data = new NSMutableArray<NSMutableDictionary<String, Object>>();
NSMutableDictionary dataDictionary = new NSMutableDictionary();
selectedFilename = currentFilename;
selectedFramework = currentFramework;
NSMutableSet<String> allKeys = new NSMutableSet<>();
for (String language : availableLanguages()) {
NSArray<String> languageArray = new NSArray<>(language);
URL url = ERXFileUtilities.pathURLForResourceNamed(currentFilename, currentFramework, languageArray);
if (url != null) {
NSDictionary<String, Object> dict = (NSDictionary<String, Object>)ERXFileUtilities.readPropertyListFromFileInFramework(currentFilename, currentFramework, languageArray);
allKeys.addObjectsFromArray(dict.allKeys());
for (String key : dict.allKeys()) {
NSMutableDictionary<String, Object> entry = (NSMutableDictionary<String, Object>) dataDictionary.objectForKey(key);
if(entry == null) {
entry = new NSMutableDictionary<>();
entry.setObjectForKey(key, "key");
dataDictionary.setObjectForKey(entry, key);
data.addObject(entry);
}
entry.setObjectForKey(dict.objectForKey(key), language);
}
}
}
for (String key : allKeys) {
NSMutableDictionary<String, Object> entry = (NSMutableDictionary<String, Object>) dataDictionary.objectForKey(key);
for (String language : availableLanguages()) {
if (entry.objectForKey(language) == null) {
entry.setObjectForKey(UNSET, language);
}
}
}
displayGroup.setObjectArray(data);
}
public boolean isLargeEntry() {
String language = currentLanguage;
Object object = currentEntry.objectForKey(language);
if (object != null && (object.toString().length() > 25
|| object.toString().indexOf('\n') >= 0 || !(object instanceof String))) {
return true;
}
return false;
}
/**
* Returns a colored border style for unset values
* @return CSS class name
*/
public String highlightClass() {
if (!hasCurrentValue()) {
return "unset";
}
return "inputfield";
}
/**
* Returns a width for the current columns
* @return width string
*/
public String valueCellWidth() {
int width = 100 / availableLanguages().count();
return "" + width + "%";
}
public int colspanForBatchNavigation() {
if (availableLanguages() != null && availableLanguages().count() > 1) {
return availableLanguages().count() - 1;
}
return 1;
}
public String valueComponentName() {
return isLargeEntry()? "WOText" : "WOTextField";
}
public void saveFramework() throws IOException {
for (String language : availableLanguages()) {
NSArray<String> languageArray = new NSArray<>(language);
URL url = ERXFileUtilities.pathURLForResourceNamed(selectedFilename, selectedFramework, languageArray);
NSMutableDictionary dict = new NSMutableDictionary();
for (Enumeration entries = data.objectEnumerator(); entries.hasMoreElements();) {
NSDictionary entry = (NSDictionary) entries.nextElement();
String key = (String) entry.objectForKey("key");
Object value = entry.objectForKey(language);
if (value != null && !value.equals(UNSET)) {
dict.setObjectForKey(value, key);
}
}
String result = ERXStringUtilities.stringFromDictionary(dict);
NSDictionary newDict = (NSDictionary) NSPropertyListSerialization.propertyListFromString(result);
if (!newDict.equals(dict)) {
throw new IllegalStateException("Data wasn't equal when comparing before save");
} else if (url != null) {
ERXFileUtilities.stringToFile(result, new File(url.getFile()), ERXProperties.stringForKeyWithDefault("er.extensions.ERXLocalizationEditor.endoding", CharEncoding.UTF_16BE));
}
}
}
private Object currentValueObject() {
Object result = null;
if (currentEntry != null) {
result = currentEntry.objectForKey(currentLanguage);
}
return result;
}
public boolean hasCurrentValue() {
return !UNSET.equals(currentValueObject());
}
public String currentValue() {
String result = null;
if(currentEntry != null) {
Object item = currentEntry.objectForKey(currentLanguage);
if (item instanceof String) {
result = (String)item;
} else {
result = NSPropertyListSerialization.stringFromPropertyList(item);
}
}
return result;
}
public void setCurrentValue(String value) {
if(currentEntry != null) {
Object item = currentEntry.objectForKey(currentLanguage);
Object newValue;
if (item instanceof String) {
newValue = value;
} else {
newValue = NSPropertyListSerialization.propertyListFromString(value);
}
if (newValue == null) {
newValue = UNSET;
}
currentEntry.setObjectForKey(newValue, currentLanguage);
}
}
/**
* Sorts the entries ascending with the selected language, brings empty entries to the first batches
*
* @return current page
*/
public WOComponent sortEntries() {
displayGroup.setSortOrderings(ERXS.ascs(currentLanguage));
displayGroup.qualifyDisplayGroup();
return context().page();
}
/**
* Add an entry to the array of objects
*
* @return current page
*/
public WOComponent addEntry() {
if (keyToAdd != null && data != null && displayGroup != null) {
NSMutableDictionary entry = new NSMutableDictionary();
entry.setObjectForKey(keyToAdd, "key");
for (String language : availableLanguages()) {
entry.setObjectForKey(UNSET, language);
}
data.addObject(entry);
displayGroup.setObjectArray(data);
displayGroup.qualifyDataSource();
displayGroup.setSelectedObject(entry);
displayGroup.displayBatchContainingSelectedObject();
}
return context().page();
}
/**
* Removes the current entry from all languages
*
* @return current page
*/
public WOComponent removeEntry() {
if (currentEntry != null) {
data.removeObject(currentEntry);
displayGroup.setObjectArray(data);
displayGroup.qualifyDisplayGroup();
}
return context().page();
}
}