/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* JavaWorld Library, Copyright 2011 Bryan Chadwick *
* *
* FILE: ./universe/base/UniverseBase.java *
* *
* This file is part of JavaWorld. *
* *
* JavaWorld is free software: you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation, either version *
* 3 of the License, or (at your option) any later version. *
* *
* JavaWorld is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with JavaWorld. If not, see . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package universe.base;
import universe.control.*;
import java.awt.Color;
import java.awt.RenderingHints;
import universe.*;
import javax.swing.*;
import java.awt.Graphics2D;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import image.*;
/* TODO:
*/
/** A Class representing a Universe (a collection of Worlds) of some type, and related methods
* and Function Objects for handling messages and events */
public class UniverseBase{
public static int PORT = 4567;
private Universe initial;
double time;
// Handlers
OnDraw ondraw;
OnTick ontick;
OnNew onnew;
OnDisconnect ondisconnect;
OnMsg onmsg;
public UniverseBase(Universe initial){
this(initial, 0.05, null, null, null, null, null);
}
public UniverseBase onDraw(OnDraw ondraw){
return new UniverseBase(this.initial, this.time,
ondraw, this.ontick, this.onnew, this.ondisconnect, this.onmsg);
}
public UniverseBase onTick(OnTick ontick){
return onTick(ontick, 0.05);
}
public UniverseBase onTick(OnTick ontick, double time){
return new UniverseBase(this.initial, this.time,
this.ondraw, ontick, this.onnew, this.ondisconnect, this.onmsg);
}
public UniverseBase onNew(OnNew onnew){
return new UniverseBase(this.initial, this.time,
this.ondraw, this.ontick, onnew, this.ondisconnect, this.onmsg);
}
public UniverseBase onDisconnect(OnDisconnect ondisconnect){
return new UniverseBase(this.initial, this.time,
this.ondraw, this.ontick, this.onnew, ondisconnect, this.onmsg);
}
public UniverseBase onMsg(OnMsg onmsg){
return new UniverseBase(this.initial, this.time,
this.ondraw, this.ontick, this.onnew, this.ondisconnect, onmsg);
}
private static int SPACE = 5;
public Universe universe(){
if(this.onmsg == null)
throw new RuntimeException("No Universe Message Handler");
if(this.ondraw == null)
throw new RuntimeException("No Universe Draw Handler");
JDialog f = new JDialog((JFrame)null, "Universe", true);
Scene scn = doOnDraw(this.initial);
final Handler handler = new Handler(this, this.initial,
new BufferedImage((int)(scn.width()+2*SPACE), (int)(scn.height()+2*SPACE), BufferedImage.TYPE_INT_RGB),
(int)(this.time*1000), f);
f.setSize((int)(SPACE*2+Math.max(20, 14+scn.width())),
(int)(Math.max(20, SPACE*2+31+scn.height())));
f.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
f.setResizable(false);
f.getContentPane().add(handler);
handler.run.start();
try{
final Server server = new Server(PORT, false, this);
Thread msgs = new Thread(){
public void run(){
while(true){
try{
synchronized(server){ server.wait(); }
if(server.hasMessage()){
// Handle messages...
WithWorld m = server.nextMessage();
Bundle res = null;
if(m.isConnect()){
res = doOnNew(handler.u, m.getWImp());
}else if(m.isDisconnect()){
res = doDisconnect(handler.u, m.getWImp(), server);
}else if(m.isTransfer()){
res = doOnMsg(handler.u, m.getWImp(), m.payload());
}else Server.p("Unknown Message Type");
if(res != null){
handler.replace(res);
for(Mail mail : res.getMails()){
server.processMail(mail, m.getWImp());
}
// res.getWorlds()
}
}
}catch(InterruptedException e){
Server.p("!!Interrupted!!");
}
}
}
};
msgs.start();
f.setVisible(true);
// Kill all the threads
System.exit(0);
//handler.run.stop();
}catch(java.io.IOException e){
throw new RuntimeException(e);
}
return handler.u;
}
// Private constructors...
private UniverseBase(Universe init, double time,
OnDraw ondraw,
OnTick ontick, OnNew onnew,
OnDisconnect ondisconnect, OnMsg onmsg){
this.initial = init;
this.time = time;
this.ondraw = ondraw;
this.ontick = ontick;
this.onnew = onnew;
this.ondisconnect = ondisconnect;
this.onmsg = onmsg;
}
/** Handles the nitty-gritty of Universe updates */
static class Handler extends javax.swing.JComponent
implements ActionListener{
private static final long serialVersionUID = 1L;
UniverseBase univ;
Universe u;
BufferedImage buffer;
Graphics2D graph;
Timer run;
Handler(UniverseBase univ, Universe u,
BufferedImage buff,
int msec, JDialog dia){
this.univ = univ;
this.u = u;
this.run = new Timer(msec, this);
this.buffer = buff;
this.graph = buff.createGraphics();
this.graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
this.graph.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
}
public void actionPerformed(ActionEvent e){
replace(this.univ.doOnTick(this.u));
}
private synchronized void replace(Bundle b){
if(b == null)return;
boolean change = !this.u.equals(b.getUniverse());
this.u = b.getUniverse();
if(change)repaint();
}
public void paint(java.awt.Graphics g){
this.graph.setColor(Color.white);
this.graph.fillRect(0,0, this.getWidth(), this.getHeight());
this.graph.clipRect(SPACE, SPACE, this.buffer.getWidth()-SPACE*2, this.buffer.getHeight()-SPACE*2);
this.univ.doOnDraw(this.u).paint(this.graph,SPACE,SPACE);
g.drawImage(this.buffer, 0, 0, null);
}
}
Scene doOnDraw(Universe u){
return this.ondraw.apply(u);
}
Bundle doOnTick(Universe u){
if(this.ontick == null)return null;
return this.ontick.apply(u);
}
Bundle doOnNew(Universe u, IWorld w){
if(this.onnew == null)return null;
return this.onnew.apply(u, w);
}
Bundle doDisconnect(Universe u, IWorld w, Server server){
if(this.ondisconnect == null)return null;
server.removeWorld(w);
return this.ondisconnect.apply(u, w);
}
Bundle doOnMsg(Universe u, IWorld w, Msg msg){
if(this.onmsg == null)return null;
return this.onmsg.apply(u, w, msg);
}
}