package org.solovyev.android.calculator.functions;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import jscl.math.function.CustomFunction;
import jscl.math.function.IFunction;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.json.Json;
import org.solovyev.android.calculator.json.Jsonable;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static java.util.Arrays.asList;
public class CppFunction implements Jsonable, Parcelable {
public static final Json.Creator<CppFunction> JSON_CREATOR = new Json.Creator<CppFunction>() {
@NonNull
@Override
public CppFunction create(@NonNull JSONObject json) throws JSONException {
return new CppFunction(json);
}
};
public static final Creator<CppFunction> CREATOR = new Creator<CppFunction>() {
@Override
public CppFunction createFromParcel(Parcel in) {
return new CppFunction(in);
}
@Override
public CppFunction[] newArray(int size) {
return new CppFunction[size];
}
};
public static final int NO_ID = -1;
private static final String JSON_NAME = "n";
private static final String JSON_BODY = "b";
private static final String JSON_PARAMETERS = "ps";
private static final String JSON_DESCRIPTION = "d";
@Nonnull
protected final List<String> parameters = new ArrayList<>();
protected int id = NO_ID;
@Nonnull
protected String name;
@Nonnull
protected String body;
@Nonnull
protected String description = "";
private CppFunction(@Nonnull String name, @Nonnull String body) {
this.name = name;
this.body = body;
}
private CppFunction(@NonNull JSONObject json) throws JSONException {
final JSONArray array = json.optJSONArray(JSON_PARAMETERS);
if (array != null) {
for (int i = 0; i < array.length(); i++) {
final String parameter = array.getString(i);
if (!TextUtils.isEmpty(parameter)) {
parameters.add(parameter);
}
}
}
name = json.getString(JSON_NAME);
body = json.getString(JSON_BODY);
description = json.optString(JSON_DESCRIPTION, "");
}
private CppFunction(@NonNull CppFunction that) {
id = that.id;
parameters.addAll(that.parameters);
name = that.name;
body = that.body;
description = that.description;
}
private CppFunction(@NonNull IFunction that) {
id = that.isIdDefined() ? that.getId() : NO_ID;
parameters.addAll(that.getParameterNames());
name = that.getName();
body = that.getContent();
description = Strings.getNotEmpty(that.getDescription(), "");
}
protected CppFunction(Parcel in) {
id = in.readInt();
parameters.addAll(in.createStringArrayList());
name = in.readString();
body = in.readString();
description = in.readString();
}
@Nonnull
public static Builder builder(@Nonnull String name, @Nonnull String body) {
return new Builder(name, body);
}
@Nonnull
public static Builder builder(@Nonnull CppFunction function) {
return new Builder(function);
}
@Nonnull
public static Builder builder(@Nonnull IFunction function) {
return new Builder(function);
}
@Nonnull
@Override
public JSONObject toJson() throws JSONException {
Check.isNotEmpty(name);
Check.isNotEmpty(body);
final JSONObject json = new JSONObject();
if (!parameters.isEmpty()) {
final JSONArray array = new JSONArray();
int j = 0;
for (int i = 0; i < parameters.size(); i++) {
final String parameter = parameters.get(i);
if (!TextUtils.isEmpty(parameter)) {
array.put(j++, parameter);
}
}
json.put(JSON_PARAMETERS, array);
}
json.put(JSON_NAME, name);
json.put(JSON_BODY, body);
if (!TextUtils.isEmpty(description)) {
json.put(JSON_DESCRIPTION, description);
}
return json;
}
public int getId() {
return id;
}
@Nonnull
public String getBody() {
return body;
}
@Nonnull
public String getDescription() {
return description;
}
@Nonnull
public List<String> getParameters() {
return parameters;
}
@Nonnull
public String getName() {
return name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeStringList(parameters);
dest.writeString(name);
dest.writeString(body);
dest.writeString(description);
}
@Nonnull
public CustomFunction.Builder toJsclBuilder() {
final CustomFunction.Builder builder = new CustomFunction.Builder(name, parameters, body);
builder.setDescription(description);
if (id != NO_ID) {
builder.setId(id);
}
return builder;
}
@Override
public String toString() {
if (id == NO_ID) {
return name + parameters.toString() + "{" + body + "}";
} else {
return name + "[#" + id + "]" + parameters.toString() + "{" + body + "}";
}
}
public static final class Builder {
@NonNull
private final CppFunction function;
private boolean built;
private Builder(@Nonnull String name, @Nonnull String body) {
function = new CppFunction(name, body);
}
public Builder(@NonNull CppFunction that) {
function = new CppFunction(that);
}
public Builder(@NonNull IFunction that) {
function = new CppFunction(that);
}
@Nonnull
public Builder withDescription(@Nonnull String description) {
Check.isTrue(!built);
function.description = description;
return this;
}
@Nonnull
public Builder withParameters(@Nonnull Collection<? extends String> parameters) {
Check.isTrue(!built);
function.parameters.addAll(parameters);
return this;
}
@Nonnull
public Builder withParameters(@Nonnull String... parameters) {
Check.isTrue(!built);
function.parameters.addAll(asList(parameters));
return this;
}
@Nonnull
public Builder withParameter(@Nonnull String parameter) {
Check.isTrue(!built);
function.parameters.add(parameter);
return this;
}
@Nonnull
public Builder withId(int id) {
Check.isTrue(!built);
function.id = id;
return this;
}
@Nonnull
public CppFunction build() {
built = true;
return function;
}
}
}