/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package net.puppygames.applet.screens; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.rmi.Naming; import java.rmi.RemoteException; import java.util.StringTokenizer; import net.puppygames.applet.Area; import net.puppygames.applet.Game; import net.puppygames.applet.MiniGame; import net.puppygames.applet.NagState; import net.puppygames.applet.PrizeFeature; import net.puppygames.applet.Res; import net.puppygames.applet.Screen; import net.puppygames.applet.TickableObject; import net.puppygames.applet.effects.SFX; import net.puppygames.applet.widgets.TextField; import net.puppygames.gamecommerce.shared.GenericServerRemote; import net.puppygames.gamecommerce.shared.NewsletterIncentive; import net.puppygames.gamecommerce.shared.ValidateUtil; import org.lwjgl.input.Mouse; import org.lwjgl.util.Rectangle; import com.shavenpuppy.jglib.opengl.GLFont; import com.shavenpuppy.jglib.resources.MappedColor; import com.shavenpuppy.jglib.util.CheckOnline; import com.shavenpuppy.jglib.util.HexDecoder; import static org.lwjgl.opengl.GL11.*; /** * Special screen for non-Puppygames customers that allows them to join our newsletter for a little prize. */ public class SignUpScreen extends Screen { private static final long serialVersionUID = 1L; /** Singleton */ private static SignUpScreen instance; private static final Object cancelLock = new Object(); /* * Areas */ private static final String EMAIL = "email"; private static final String SIGNUP = "signup"; private static final String LATER = "later"; private static final String MESSAGE = "signup-nag"; private static final String DONTSHOWAGAIN = "dontShowAgain"; private static final String DONTSHOWAGAIN_ON = "dontShowAgain_on"; private static final String DONTSHOWAGAIN_OFF = "dontShowAgain_off"; /* * Layout */ private MappedColor topColor, bottomColor, color; private Rectangle emailInsets; private String font; private transient TextField emailField; private transient boolean valid; private transient GLFont fontResource; private transient DialogScreen waitDialog; private transient Thread signUpThread; private transient boolean cancelSignUp; private transient Runnable thingToDo; private transient boolean waitForMouse; private transient TickableObject emailObject; private transient PrizeFeature prize; /** * C'tor */ public SignUpScreen(String name) { super(name); } @Override protected void doCreateScreen() { emailField = new TextField(64, getArea(EMAIL).getBounds().getWidth()) { @Override public boolean acceptChar(char c) { return Character.isLetterOrDigit(c) || c >= ' ' && c <= 127; } @Override protected void onChangeFocus() { SFX.textEntered(); requestFocus(getArea(SIGNUP)); } @Override protected void onEdited() { SFX.keyTyped(); checkValid(); } }; emailField.setFont(fontResource); if (color != null) { emailField.setColour(color); } if (topColor != null) { emailField.setTopColour(topColor); } if (bottomColor != null) { emailField.setBottomColour(bottomColor); } } @Override protected void onResized() { Area emailArea = getArea(EMAIL); emailField.setLocation(emailArea.getBounds().getX() + emailInsets.getX(), emailArea.getBounds().getY() + emailInsets.getY()); emailField.setWidth(emailArea.getBounds().getWidth() - emailInsets.getWidth()); } @Override protected void doRegister() { instance = this; } @Override protected void doDeregister() { instance = null; } /** * Show the registration screen */ public static void show(PrizeFeature prize) { if (!instance.isCreated()) { try { instance.create(); } catch (Exception e) { e.printStackTrace(System.err); } } instance.prize = prize; instance.open(); } @Override protected void onOpen() { Game.setPauseEnabled(false); emailField.setEditing(true); waitForMouse = true; checkValid(); emailObject = new TickableObject() { @Override protected void render() { emailField.render(this); } }; emailObject.setLayer(100); emailObject.spawn(this); getArea(MESSAGE).setText(prize.getScreenMessage()); enableButtons(); } @Override protected void onClose() { Game.setPauseEnabled(true); if (emailObject != null) { emailObject.remove(); emailObject = null; } MiniGame.showTitleScreen(); } @Override protected void onClicked(String id) { if (waitForMouse) { return; } if (id.equals(EMAIL)) { emailField.setEditing(true); } else if (id.equals(SIGNUP)) { signUp(); } else if (id.equals(LATER)) { close(); } else if (id.equals(DONTSHOWAGAIN)) { NagState nagState = MiniGame.getNagState(); switch (nagState) { case DONT_NAG: nagState = NagState.NOT_YET_SHOWN; break; case NOT_YET_SHOWN: nagState = NagState.DONT_NAG; break; default: assert false : "Shouldn't have nag state "+nagState; return; } MiniGame.setNagState(nagState); enableButtons(); } } private void enableButtons() { boolean dontShowAgain = MiniGame.getNagState() == NagState.DONT_NAG; setVisible(DONTSHOWAGAIN_ON, dontShowAgain); setVisible(DONTSHOWAGAIN_OFF, !dontShowAgain); getArea(DONTSHOWAGAIN_OFF).init(); getArea(DONTSHOWAGAIN_ON).init(); } private static void addParam(String param, String data, StringBuilder sb) throws UnsupportedEncodingException { if (sb.length() > 0) { sb.append('&'); } sb.append(param); sb.append('='); sb.append(URLEncoder.encode(data, "utf8")); } private void signUp() { if (!checkValid()) { return; } if (!CheckOnline.isOnline()) { String msg = Game.getMessage("lwjglapplets.signupscreen.failed_message"); msg = msg.replace("[title]", Game.getDisplayTitle()); signUpFailed(msg, true); } else { waitDialog = net.puppygames.applet.Res.getCancelDialog(); String msg = Game.getMessage("lwjglapplets.signupscreen.wait_message"); msg = msg.replace("[title]", Game.getDisplayTitle()); waitDialog.doModal(Game.getMessage("lwjglapplets.signupscreen.wait_title"), msg, new Runnable() { @Override public void run() { int option = waitDialog.getOption(); // Cancel registration if (option != DialogScreen.NONE) { waitForMouse = true; synchronized (cancelLock) { cancelSignUp = true; if (signUpThread != null) { signUpThread.interrupt(); } } } waitDialog = null; } }); signUpThread = new Thread() { @Override public void run() { try { GenericServerRemote server; try { server = (GenericServerRemote) Naming.lookup(GenericServerRemote.RMI_URL); } catch (Exception e) { e.printStackTrace(System.err); synchronized (cancelLock) { if (!cancelSignUp) { String msg = Game.getMessage("lwjglapplets.signupscreen.connect_failed_message"); msg = msg.replace("[email]", Game.getSupportEmail()); signUpFailed(msg, false); } cancelSignUp = false; } return; } String ret; StringBuilder command = new StringBuilder(256); try { addParam("cmd", "signup", command); addParam("email", emailField.getText(), command); addParam("installation", String.valueOf(Game.getInstallation()), command); addParam("game", Game.getTitle(), command); addParam("version", Game.getVersion(), command); addParam("prize", prize.getName(), command); addParam("message", prize.getEmailMessage(), command); System.out.println("Executing remote command "+command); ret = server.doCommand(command.toString()); System.out.println("Remote command result "+ret); String result = getParam(ret, "result", "FAILED"); if ("SUCCESS".equals(result)) { String code = getParam(ret, "code", ""); NewsletterIncentive ni = new NewsletterIncentive(emailField.getText(), Game.getTitle(), Game.getVersion(), Game.getInstallation(), prize.getName()); ni.setCode(HexDecoder.decode(code)); signUpSuccess(ni); } else if ("FAILED".equals(result)) { signUpFailed(getParam(ret, "reason", Game.getMessage("lwjglapplets.signupscreen.unknown_reasons")), true); } else { throw new Exception("Don't understand server response "+ret); } } catch (RemoteException e) { e.printStackTrace(System.err); signUpFailed(e.getMessage(), true); return; } catch (Throwable e) { e.printStackTrace(System.err); synchronized (cancelLock) { if (!cancelSignUp) { Game.onRegistrationDisaster(); String msg = Game.getMessage("lwjglapplets.signupscreen.signup_failed_message"); msg = msg.replace("[email]", Game.getSupportEmail()); signUpFailed(msg, true); cancelSignUp = false; } } return; } } finally { synchronized (cancelLock) { signUpThread = null; } } } }; signUpThread.start(); } } /** * Called when registration fails * @param message The failure message * @param nextPhase The phase to go to next */ private void signUpFailed(final String message, final boolean fatal) { thingToDo = new Runnable() { @Override public void run() { if (waitDialog != null && waitDialog.isOpen()) { waitDialog.close(); waitDialog = null; } Res.getInfoDialog().doModal ( Game.getMessage("lwjglapplets.signupscreen.failed"), Game.getMessage("lwjglapplets.signupscreen.general_failure_message")+"\n\n"+message, new Runnable() { @Override public void run() { net.puppygames.applet.Res.getInfoDialog().getOption(); if (fatal) { MiniGame.setNagState(NagState.DONT_NAG); MiniGame.showTitleScreen(); } waitForMouse = true; } } ); } }; } /** * Called when signup call succeeds */ private void signUpSuccess(final NewsletterIncentive ni) { thingToDo = new Runnable() { @Override public void run() { Game.onRemoteCallSuccess(); if (waitDialog != null && waitDialog.isOpen()) { waitDialog.close(); waitDialog = null; } // Serialize the nag incentive FileOutputStream fos = null; BufferedOutputStream bos = null; ObjectOutputStream oos = null; try { fos = new FileOutputStream(MiniGame.getIncentiveFile()); bos = new BufferedOutputStream(fos); oos = new ObjectOutputStream(bos); oos.writeObject(ni); } catch (IOException e) { e.printStackTrace(System.err); } finally { try { if (oos != null) { oos.flush(); oos.close(); } } catch (IOException e) { } } MiniGame.setNagState(NagState.PRIZE_AWAITS); UnlockBonusScreen.show(ni); } }; } private static final String getParam(String data, String param, String _default) { StringTokenizer st = new StringTokenizer(data, "&", false); param += "="; while (st.hasMoreTokens()) { String t = st.nextToken(); if (t.startsWith(param)) { try { return URLDecoder.decode(t.substring(param.length()), "utf8"); } catch (UnsupportedEncodingException e) { System.err.println("Failed to decode "+data); e.printStackTrace(System.err); } } } return _default; } @Override protected void doTick() { if (!isBlocked()) { if (!Mouse.isButtonDown(0)) { waitForMouse = false; } emailField.tick(); boolean wasEnabled = getArea(SIGNUP).isEnabled(); if (wasEnabled != valid) { setEnabled(SIGNUP, valid); } } if (thingToDo != null) { thingToDo.run(); thingToDo = null; } } /** * Check validity and enable/disable the Register button */ private boolean checkValid() { valid = ValidateUtil.isEmail(emailField.getText()); return valid; } @Override protected void preRender() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); } }