/*******************************************************************************
* This file is part of RedReader.
*
* RedReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RedReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RedReader. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package org.quantumbadger.redreader.io;
import org.quantumbadger.redreader.common.UnexpectedInternalStateException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class WritableHashSet implements WritableObject<String> {
@WritableObjectVersion
public static int DB_VERSION = 1;
private transient HashSet<String> hashSet = null;
@WritableField
private String serialised;
@WritableObjectKey
private final String key;
@WritableObjectTimestamp
private final long timestamp;
public WritableHashSet(HashSet<String> data, long timestamp, String key) {
this.hashSet = data;
this.timestamp = timestamp;
this.key = key;
serialised = listToEscapedString(hashSet);
}
private WritableHashSet(String serializedData, long timestamp, String key) {
this.timestamp = timestamp;
this.key = key;
serialised = serializedData;
}
public WritableHashSet(CreationData creationData) {
this.timestamp = creationData.timestamp;
this.key = creationData.key;
}
@Override
public String toString() {
throw new UnexpectedInternalStateException("Using toString() is the wrong way to serialise a WritableHashSet");
}
public String serializeWithMetadata() {
final ArrayList<String> result = new ArrayList<>(3);
result.add(serialised);
result.add(String.valueOf(timestamp));
result.add(key);
return listToEscapedString(result);
}
public static WritableHashSet unserializeWithMetadata(String raw) {
final ArrayList<String> data = escapedStringToList(raw);
return new WritableHashSet(data.get(0), Long.valueOf(data.get(1)), data.get(2));
}
public synchronized HashSet<String> toHashset() {
if(hashSet != null) return hashSet;
return (hashSet = new HashSet<>(escapedStringToList(serialised)));
}
public String getKey() {
return key;
}
public long getTimestamp() {
return timestamp;
}
public static String listToEscapedString(final Collection<String> list) {
if(list.size() == 0) return "";
final StringBuilder sb = new StringBuilder();
for(final String str : list) {
for(int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
switch(c) {
case '\\':
sb.append("\\\\");
break;
case ';':
sb.append("\\;");
break;
default:
sb.append(c);
break;
}
}
sb.append(';');
}
return sb.toString();
}
public static ArrayList<String> escapedStringToList(String str) {
// Workaround to improve parsing of lists saved by older versions of the app
if(str.length() > 0 && !str.endsWith(";")) str += ";";
final ArrayList<String> result = new ArrayList<>();
if(str != null) {
boolean isEscaped = false;
final StringBuilder sb = new StringBuilder();
for(int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
if(c == ';' && !isEscaped) {
result.add(sb.toString());
sb.setLength(0);
} else if(c == '\\') {
if(isEscaped) sb.append('\\');
} else {
sb.append(c);
}
isEscaped = c == '\\' && !isEscaped;
}
}
return result;
}
}