package org.geogebra.common.move.ggtapi.models;
import java.util.ArrayList;
import org.geogebra.common.move.ggtapi.TubeAvailabilityCheckEvent;
import org.geogebra.common.move.ggtapi.events.LoginEvent;
import org.geogebra.common.move.ggtapi.models.Material.MaterialType;
import org.geogebra.common.move.ggtapi.models.json.JSONObject;
import org.geogebra.common.move.ggtapi.models.json.JSONTokener;
import org.geogebra.common.move.ggtapi.operations.LogInOperation;
import org.geogebra.common.move.ggtapi.requests.DeleteRequest;
import org.geogebra.common.move.ggtapi.requests.MaterialCallbackI;
import org.geogebra.common.move.ggtapi.requests.ShareRequest;
import org.geogebra.common.move.ggtapi.requests.SyncCallback;
import org.geogebra.common.move.ggtapi.requests.SyncRequest;
import org.geogebra.common.move.ggtapi.requests.UploadRequest;
import org.geogebra.common.util.HttpRequest;
import org.geogebra.common.util.debug.Log;
/**
* @author gabor Common base for GeoGebraTubeApi
*/
public abstract class GeoGebraTubeAPI {
/**
* The Standard Result Quantity
*/
public static final int STANDARD_RESULT_QUANTITY = 30;
/** Public url DO NOT CHANGE!s */
public static final String url = "https://www.geogebra.org/api/json.php";
/** For beta version */
public static final String urlBeta = "https://beta.geogebra.org/api/json.php";
/** Public login url DO NOT CHANGE! */
public static final String login_url = "https://accounts.geogebra.org/api/index.php";
/** Login for beta */
public static final String login_urlBeta = "https://accounts-beta.geogebra.org/api/index.php";
static public final int LOGIN_TOKEN_VALID = 0;
static public final int LOGIN_TOKEN_INVALID = 1;
static public final int LOGIN_REQUEST_FAILED = -2;
protected boolean available = true;
protected boolean availabilityCheckDone = false;
protected ClientInfo client;
private String materialsURL;
private String loginURL;
/**
* @param beta
*/
public GeoGebraTubeAPI(boolean beta) {
this.materialsURL = beta ? urlBeta : url;
this.loginURL = beta ? login_urlBeta : login_url;
}
public void setURL(String url1) {
this.materialsURL = url1;
}
public void setLoginURL(String loginAPIurl) {
this.loginURL = loginAPIurl;
}
/**
* Private method performing the request given by requestString
*
* @param requestString
* JSON request String for the GeoGebraTubeAPI
* @return The HttpRequest object that contains the response and error
* information
*/
protected final void performRequest(String requestString, boolean login,
AjaxCallback callback) {
HttpRequest request = createHttpRequest();
request.sendRequestPost(login ? getLoginUrl() : getUrl(), requestString,
callback);
}
public final String getLoginUrl() {
return loginURL;
}
protected final String getUrl() {
return materialsURL;
}
/**
* Creates a new Http request
*
* @return The new http request
*/
protected abstract HttpRequest createHttpRequest();
protected abstract boolean parseUserDataFromResponse(GeoGebraTubeUser user,
String response);
/**
* Sends a request to the GeoGebraTube API to check if the login token which
* is defined in the specified GeoGebraTubeUser is valid.
*
* @param user
* The user that should be authorized.
* @return One of the following return codes: LOGIN_TOKEN_VALID,
* LOGIN_TOKEN_INVALID, LOGIN_REQUEST_FAILED
*/
public final void authorizeUser(final GeoGebraTubeUser user,
final LogInOperation op, final boolean automatic) {
performRequest(
buildTokenLoginRequest(user.getLoginToken(), user.getCookie()),
true, new AjaxCallback() {
@Override
public void onSuccess(String responseStr) {
try {
GeoGebraTubeAPI.this.availabilityCheckDone = true;
GeoGebraTubeAPI.this.available = true;
// Parse the userdata from the response
if (!parseUserDataFromResponse(user, responseStr)) {
op.onEvent(new LoginEvent(user, false,
automatic, responseStr));
return;
}
op.onEvent(new LoginEvent(user, true, automatic,
responseStr));
// GeoGebraTubeAPID.this.available = false;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onError(String error) {
GeoGebraTubeAPI.this.availabilityCheckDone = true;
GeoGebraTubeAPI.this.available = false;
op.onEvent(
new LoginEvent(user, false, automatic, null));
}
});
}
/**
* Builds the request to check if the login token of a user is valid. This
* request will send detailed user information as response.
*
* @param token
* The user that should be logged in
* @param cookie
* cookie (for web)
* @return The JSONObject that contains the request.
*/
protected static final String buildTokenLoginRequest(String token,
String cookie) {
JSONObject requestJSON = new JSONObject();
JSONObject apiJSON = new JSONObject();
JSONObject loginJSON = new JSONObject();
try {
if (token != null) {
loginJSON.put("token", token);
} else {
loginJSON.put("cookie", cookie);
}
loginJSON.put("getuserinfo", "true");
apiJSON.put("login", loginJSON);
apiJSON.put("api", "1.0.0");
requestJSON.put("request", apiJSON);
} catch (Exception e) {
Log.debug("problem building request: " + e.getMessage());
return null;
}
return requestJSON.toString();
}
public boolean checkAvailable(LogInOperation op) {
if (this.availabilityCheckDone && op != null) {
op.onEvent(new TubeAvailabilityCheckEvent(this.available));
}
checkIfAvailable(op, getClientInfo());
return this.available;
}
public boolean isAvailable() {
return this.available;
}
protected String getClientInfo() {
return "";
}
/**
* Sends a test request to GeoGebraTube to check if it is available The
* result is stored in a boolean variable. Subsequent calls to isAvailable()
* will return the value of the stored variable and don't send the request
* again.
*
* @return boolean if the request was successful.
*/
private boolean checkIfAvailable(final LogInOperation op,
String clientInfo) {
if (!this.availabilityCheckDone) {
this.available = false;
}
this.availabilityCheckDone = false;
try {
performRequest(
"{\"request\": {\"-api\": \"1.0.0\"," + clientInfo
+ "\"task\": {\"-type\": \"info\"}}}",
false, new AjaxCallback() {
@Override
public void onSuccess(String response) {
GeoGebraTubeAPI.this.availabilityCheckDone = true;
GeoGebraTubeAPI.this.available = true;
if (op != null) {
op.onEvent(
new TubeAvailabilityCheckEvent(true));
}
}
@Override
public void onError(String error) {
GeoGebraTubeAPI.this.availabilityCheckDone = true;
GeoGebraTubeAPI.this.available = false;
if (op != null) {
op.onEvent(
new TubeAvailabilityCheckEvent(true));
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return this.available;
}
public void setUserLanguage(String lang, String token) {
performRequest("{\"request\": {" + "\"api\":\"1.0.0\","
+ "\"login\": {\"token\":\"" + token
+ "\", \"getuserinfo\":\"false\"},"
+ "\"task\": {\"type\":\"setuserlang\", \"lang\":\"" + lang
+ "\"}}}", true, new AjaxCallback() {
@Override
public void onSuccess(String response) {
// yay, it worked
}
@Override
public void onError(String error) {
Log.error(error);
}
});
}
public void logout(String token) {
performRequest("{\"request\": {" + "\"api\":\"1.0.0\","
+ "\"logout\": {\"token\":\"" + token
+ "\", \"getuserinfo\":\"false\"}}}", true, new AjaxCallback() {
@Override
public void onSuccess(String response) {
// yay, it worked
}
@Override
public void onError(String error) {
Log.error(error);
}
});
}
public void favorite(int id, boolean favorite) {
performRequest("{\"request\": {" + "\"-api\":\"1.0.0\","
+ "\"login\": {\"-token\":\"" + getToken() + "\"},"
+ "\"task\": {\"-type\":\"favorite\", \"id\":\"" + id
+ "\",\"favorite\":\"" + favorite + "\"}}}", false,
new AjaxCallback() {
@Override
public void onSuccess(String response) {
// yay, it worked
}
@Override
public void onError(String error) {
Log.error(error);
}
});
}
/**
* to rename materials on ggt; TODO no use of base64
*
* @param app
* {@link AppW}
* @param mat
* {@link Material}
* @param cb
* {@link MaterialCallbackI}
*/
public void uploadRenameMaterial(Material mat, final MaterialCallbackI cb) {
performRequest(
UploadRequest.getRequestElement(mat.getTitle(), mat.getId())
.toJSONString(client),
cb);
}
/**
* Uploads a local saved file (web - localStorage; touch - device) to ggt
*
* @param app
* {@link AppW}
* @param mat
* {@link Material}
* @param cb
* {@link MaterialCallbackI}
*/
public void uploadLocalMaterial(final Material mat,
final MaterialCallbackI cb) {
performRequest(
UploadRequest.getRequestElement(mat).toJSONString(client), cb);
}
/**
* @param app
* {@link AppW}
* @param material
* {@link Material}
* @param cb
* {@link MaterialCallbackI}
*/
public void deleteMaterial(Material material, final MaterialCallbackI cb) {
performRequest(
DeleteRequest.getRequestElement(material).toJSONString(client),
cb);
}
public void shareMaterial(Material material, String to, String message,
final MaterialCallbackI cb) {
performRequest(ShareRequest.getRequestElement(material, to, message)
.toJSONString(client), cb);
}
/**
* @param userId
* int
* @param cb
* {@link MaterialCallbackI}
*/
public void getUsersMaterials(MaterialCallbackI cb) {
performRequest(
MaterialRequest.forCurrentUser(client).toJSONString(client),
cb);
}
public void getUsersOwnMaterials(MaterialCallbackI cb) {
System.out.println(client.getModel().getUserId());
performRequest(
MaterialRequest.forUser(client.getModel().getUserId(), client)
.toJSONString(client),
cb);
}
/**
* @param requestString
* json string representing the request
* @param cb
* {@link MaterialCallbackI}
*/
protected final void performRequest(String requestString,
final MaterialCallbackI cb) {
HttpRequest req = createHttpRequest();
req.sendRequestPost(getUrl(), requestString, new AjaxCallback() {
@Override
public void onSuccess(String response) {
ArrayList<Material> result = new ArrayList<Material>();
ArrayList<Chapter> meta = JSONParserGGT.prototype
.parseResponse(response, result);
cb.onLoaded(result, meta);
}
@Override
public void onError(String error) {
cb.onError(new Exception(error));
}
});
}
/**
* @param id
* int
* @param cb
* {@link MaterialCallbackI}
*/
public void getBookItems(int id, MaterialCallbackI cb) {
performRequest(MaterialRequest.forBook(id, client).toJSONString(client),
cb);
}
public void getWorksheetItems(int id, MaterialCallbackI cb) {
performRequest(
MaterialRequest.forWorksheet(id, client).toJSONString(client),
cb);
}
/**
* Uploads the actual opened application to ggt
*
* @param app
* AppW
* @param filename
* String
* @param cb
* MaterialCallback
*/
public void uploadMaterial(int tubeID, String visibility,
final String filename, String base64, final MaterialCallbackI cb,
MaterialType type) {
performRequest(UploadRequest
.getRequestElement(tubeID, visibility, filename, base64, type)
.toJSONString(client), cb);
}
/**
* Search for materials containing the String query
*
* @param query
* search String
* @param callback
* {@link MaterialCallbackI}
*/
public void search(String query, MaterialCallbackI callback) {
performRequest(new MaterialRequest(query, client).toJSONString(client),
callback);
}
/**
* Returns materials in the given amount and order
*
* @param callback
* {@link MaterialCallbackI}
*/
public void getFeaturedMaterials(MaterialCallbackI callback) {
performRequest(MaterialRequest.forFeatured(client).toJSONString(client),
callback);
}
// /**
// * Returns a String-Array of popular tags fetched from the GGT API
// *
// */
// public String[] getPopularTags()
// {
// // TODO fetch popular tags from the API
// return new String[] { "algebra", "dment", "pythagorean", "circle",
// "triangle", "functions", "jerzy", "geometry", "trigonometry", "3d" };
// }
/**
* Return a specific Material by its ID
*
* @param id
* int
* @param callback
* {@link MaterialCallbackI}
*/
public void getItem(String id, MaterialCallbackI callback) {
performRequest(MaterialRequest.forId(id, client).toJSONString(client),
callback);
}
public boolean isCheckDone() {
return availabilityCheckDone;
}
public void sync(long timestamp, final SyncCallback cb) {
this.performRequest(new SyncRequest(timestamp).toJSONString(client),
false, new AjaxCallback() {
@Override
public void onSuccess(String response) {
ArrayList<SyncEvent> events = new ArrayList<SyncEvent>();
try {
JSONTokener tok = new JSONTokener(response);
JSONObject responseObj = (JSONObject) ((JSONObject) new JSONObject(
tok).get("responses"))
.get("response");
Object items = responseObj.get("item");
JSONParserGGT.prototype.addEvents(events, items);
cb.onSync(events);
} catch (Exception e) {
Log.error("SYNC parse error" + e.getMessage());
}
}
@Override
public void onError(String error) {
Log.error("SYNCE error" + error);
}
});
}
protected String getToken() {
return client.getModel().getLoginToken();
}
public void setClient(ClientInfo clientInfo) {
this.client = clientInfo;
}
}