package com.circlegate.liban.base;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
import com.circlegate.liban.base.ApiDataIO.ApiDataInput;
import com.circlegate.liban.base.ApiDataIO.ApiDataInputStreamWrp;
import com.circlegate.liban.base.ApiDataIO.ApiDataOutput;
import com.circlegate.liban.base.ApiDataIO.ApiDataOutputStreamWrp;
import com.circlegate.liban.base.ApiDataIO.ApiParcelInputWrp;
import com.circlegate.liban.base.ApiDataIO.ApiParcelOutputWrp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class ApiBase {
public interface IApiObject {
void save(ApiDataOutput d, int flags);
}
public interface IApiParcelable extends IApiObject, Parcelable {
// tridy implementujici toto rozhrani musi mit clen public static ApiCreator CREATOR;
}
public static abstract class ApiObject implements IApiObject {
public final void save(ApiDataOutput d) {
save(d, 0);
}
@Override
public abstract void save(ApiDataOutput d, int flags);
public static byte[] saveToByteArray(IApiParcelable obj) {
return saveToByteArray(obj, false);
}
public static byte[] saveToByteArray(IApiParcelable obj, boolean withName) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ApiDataOutputStreamWrp stream = new ApiDataOutputStreamWrp(new DataOutputStream(byteStream));
if (withName)
stream.writeWithName(obj, 0);
else
stream.write(obj, 0);
return byteStream.toByteArray();
}
public static String saveToBase64(IApiParcelable obj, int base64Flags) {
return saveToBase64(obj, base64Flags, false);
}
public static String saveToBase64(IApiParcelable obj, int base64Flags, boolean withName) {
String ret = Base64.encodeToString(saveToByteArray(obj), base64Flags); // Base64.DEFAULT
return ret;
}
public static ApiDataInput loadFromByteArray(byte[] bytes) {
ApiDataInputStreamWrp ret = new ApiDataInputStreamWrp(new DataInputStream(new ByteArrayInputStream(bytes)));
return ret;
}
public static ApiDataInput loadFromBase64(String base64String, int base64Flags) {
return loadFromByteArray(Base64.decode(base64String, base64Flags));
}
}
public static abstract class ApiParcelable extends ApiObject implements IApiParcelable {
public int describeContents() {
return baseDescribeContents();
}
public final void writeToParcel(Parcel dest, int flags) {
baseWriteToParcel(this, dest, flags);
}
public static int baseDescribeContents() {
return 0;
}
public static void baseWriteToParcel(IApiParcelable parcelable, Parcel dest, int flags) {
ApiParcelOutputWrp p = new ApiParcelOutputWrp(dest);
parcelable.save(p, flags);
}
}
public static abstract class ApiCreator<T> implements Parcelable.Creator<T> {
@Override
public final T createFromParcel(Parcel source) {
ApiParcelInputWrp wrp = new ApiParcelInputWrp(source);
return create(wrp);
}
public abstract T create(ApiDataInput d);
}
public static class ApiInstanceCreator {
@SuppressWarnings("rawtypes")
private static final Map<String, ApiCreator> cache = new HashMap<String, ApiCreator>();
private static final Map<String, String> classNamesReplacements = new HashMap<>();
// Kvuli podpore prejmenovani trid resp. jejich presouvani mezi namespacy (napr. kvuli moznosti nacist starsi datovy soubor s parcelables, kdyz nove je trida definovana jinde...)
public static void addClassNameReplacement(String oldName, String newName) {
synchronized (cache) {
classNamesReplacements.put(oldName, newName);
}
}
public static <T extends IApiParcelable> T createInstanceReadClassNameFirst(ApiDataInput d) {
String className = d.readString();
return createInstance(className, d);
}
@SuppressWarnings({"rawtypes", "unchecked"})
public static <T extends IApiParcelable> T createInstance(String className, ApiDataInput d) {
synchronized (cache) {
String newName = classNamesReplacements.get(className);
if (newName != null)
className = newName;
ApiCreator<T> creator = cache.get(className);
if (creator == null) {
try {
Class c = Class.forName(className);
Field f = c.getField("CREATOR");
creator = (ApiCreator<T>)f.get(null);
}
catch (ClassNotFoundException e) {
throw new RuntimeException("Class not found for: " + className);
}
catch (NoSuchFieldException e) {
throw new RuntimeException("CREATOR field not found for: " + className);
}
catch (IllegalAccessException e) {
throw new RuntimeException("IllegalAccessException when unmarshalling: " + className);
}
if (creator == null) {
throw new RuntimeException("CREATOR field not found for (1): " + className);
}
cache.put(className, creator);
}
return creator.create(d);
}
}
}
}