package org.geogebra.web.web.move.ggtapi.models; import org.geogebra.common.main.Localization; import org.geogebra.common.move.ggtapi.models.ClientInfo; import org.geogebra.common.move.ggtapi.models.GeoGebraTubeUser; import org.geogebra.common.move.ggtapi.models.Material; import org.geogebra.common.util.StringUtil; import org.geogebra.common.util.debug.Log; import org.geogebra.web.html5.main.AppW; import org.geogebra.web.html5.main.GeoGebraTubeAPIWSimple; import org.geogebra.web.html5.util.WindowW; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONNumber; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; /** * API Interface for GeoGebraTube requests and responses * * @author Matthias Meisinger * */ public class GeoGebraTubeAPIW extends GeoGebraTubeAPIWSimple { /** * @param url * String * @param client * {@link ClientInfo} */ public GeoGebraTubeAPIW(ClientInfo client, boolean beta) { super(beta); this.client = client; } // /** // * Return a list of all Materials from the specified author // * ! Should be the same search as for materials! // * @param author // */ // public void getAuthorsMaterials(String author, RequestCallback callback) // { // throw new UnsupportedOperationException(); // } /** * Copies the user data from the API response to this user. * * @return true if the data could be parsed successfully, false otherwise */ @Override public boolean parseUserDataFromResponse(GeoGebraTubeUser user, String result) { try { JSONValue tokener = JSONParser.parseStrict(result); JSONObject response = tokener.isObject(); JSONObject userinfo = (JSONObject) response.get("responses"); userinfo = ((JSONArray) userinfo.get("response")).get(0).isObject(); userinfo = (JSONObject) userinfo.get("userinfo"); if (userinfo.get("user_id") instanceof JSONNumber) { user.setUserId((int) (((JSONNumber) userinfo.get("user_id")) .doubleValue())); } else { user.setUserId(Integer.parseInt(((JSONString) userinfo .get("user_id")).stringValue())); } user.setUserName(((JSONString) userinfo.get("username")) .stringValue()); user.setRealName(((JSONString) userinfo.get("realname")) .stringValue()); user.setIdentifier(((JSONString) userinfo.get("identifier")) .stringValue()); if (userinfo.get("image") instanceof JSONString) { user.setImageURL(((JSONString) userinfo.get("image")) .stringValue()); } if (userinfo.get("lang_ui") instanceof JSONString) { user.setLanguage(((JSONString) userinfo.get("lang_ui")) .stringValue()); } if (userinfo.get("token") instanceof JSONString) { user.setToken(((JSONString) userinfo.get("token")) .stringValue()); } // Further fields are not parsed yet, because they are not needed // This is the complete response with all available fields: /* * <responses> <response> <userinfo> <user_id>4711</user_id> * <username>johndoe</username> * <ggt_profile_url>http://tube.geogebra.org/user/profile/id/4711 * </ggt_profile_url> <group>user</group> * <date_created>2012-09-18</date_created> <lang_ui>en</lang_ui> * <lang_content>en,en_US,it</lang_content> * <timezone>America/New_York</timezone> <materials>31</materials> * <favorites>4</favorites> <collections>2</collections> * <identifier>forum:0815</identifier> <realname>John Doe</realname> * <occupation>Maths teacher</occupation> <location>New * York</location> <website>www.thisisme.com</website> * <profilemessage>Any text</profilemessage> </userinfo> </response> * </responses> */ // user.setGGTProfileURL(userinfo.getString("ggt_profile_url")); // user.setGroup(userinfo.getString("group")); // user.setDateCreated(userinfo.getString("date_created")); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * @param app * {@link AppW} * @param sliderName * {@link Material} * @param cb * {@link MaterialCallback} */ public void exportAnimGif(final AppW app, String sliderName, int timing, boolean isLoop) { String data = createGifResponsePage(app.getLocalization()); final JavaScriptObject gifWnd = app.getLAF().isTablet() ? null : WindowW.openFromData(data); WindowW.postMessage(gifWnd, StringUtil.toHTMLString(app.getLocalization().getPlain( "AnimatedGIF.Processing"))); RequestCallback cb = new RequestCallback() { @Override public void onResponseReceived(Request request, Response response) { if (response != null) { try { String respData = response.getText(); if (respData == null || "".equals(respData)) { Log.debug("[ANIMGIF] no response"); return; } Log.debug("[ANIMGIF] respData is: " + respData); JSONValue responseObject = JSONParser .parseStrict(respData); if (responseObject == null || responseObject.isObject() == null) { Log.debug("[ANIMGIF] responseObject is null"); WindowW.postMessage(gifWnd, StringUtil .toHTMLString(app.getLocalization() .getPlain("AnimatedGIF.ErrorA", respData))); return; } JSONValue responses = responseObject.isObject().get( "responses"); if (responses == null || responses.isObject() == null) { JSONValue error = responseObject.isObject() .get("error").isObject().get("-type") .isString(); Log.debug("[ANIMGIF] error is " + error.toString()); WindowW.postMessage( gifWnd, StringUtil .toHTMLString(app .getLocalization() .getPlain( "AnimatedGIF.ErrorA", " " + error.toString() + " (" + response .getStatusCode()))); return; } JSONValue base64 = responses.isObject().get("response") .isObject().get("value"); String downloadUrl = "data:image/gif;base64," + base64.isString().stringValue(); app.getFileManager().exportImage(downloadUrl, "ggbanim.gif", "gif"); WindowW.postMessage(gifWnd, StringUtil.toHTMLString(app .getLocalization().getPlain( "AnimatedGIF.Success"))); } catch (Throwable t) { Log.debug(t.getMessage()); Log.debug("'" + response + "'"); } } } @Override public void onError(Request request, Throwable exception) { Log.debug("[ANIMGIF] EXCEPTION: " + exception); } }; RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, getUrl()); Log.debug("[URL] " + getUrl()); String req = AnimGifRequest.getRequestElement( app.getGgbApi().getBase64(), sliderName, timing, isLoop) .toJSONString(client); Log.debug("[REQUEST]: " + req); try { rb.setHeader("Content-type", "text/plain"); rb.sendRequest(req, cb); } catch (RequestException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static String createGifResponsePage(Localization loc) { StringBuilder sb = new StringBuilder(); sb.append("<!doctype html> \n"); sb.append(" <html> \n"); sb.append(" <head>\n"); sb.append(" <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); sb.append(" <title>" + StringUtil.toHTMLString(loc.getPlain("AnimatedGIFExport")) + "</title>\n"); sb.append(" <script>\n"); sb.append(" window.addEventListener('message',function(event) {\n"); sb.append(" console.log('received response: ',event.data);\n"); sb.append(" var result = document.getElementById('result');\n"); sb.append(" result.innerHTML = event.data;\n"); sb.append(" var button = document.getElementById('close');\n"); sb.append(" button.setAttribute('style', 'display: block');\n"); sb.append(" },false);\n"); sb.append(" </script>\n"); sb.append(" </head>\n"); sb.append(" <body>\n"); sb.append(" <iframe src=\"javascript:''\" id=\"__gwt_historyFrame\" tabIndex='-1' style=\"position:absolute;width:0;height:0;border:0\"></iframe>\n"); sb.append(" <h1>" + StringUtil.toHTMLString(loc.getPlain("CreatingAnimatedGIF")) + "</h1>\n"); sb.append(" <p id=\"result\">" + StringUtil.toHTMLString(loc .getPlain("AnimatedGIF.Calculating")) + "</p>\n"); sb.append(" <button type=\"button\" id=\"close\" onclick=\"window.close();\" style=\"display: none;\">Close</button>\n"); sb.append(" </body>\n"); sb.append("</html>\n"); return sb.toString(); } }