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; } } }