package zeta.handler.statistic;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Label;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.servlet.ServletException;
import zeta.ZetaServlet;
import zeta.util.CachedQueries;
import zeta.util.DatabaseUtils;
import zeta.util.Graphics;
import zeta.util.QueryWithSum;
import zeta.util.Table;
import zeta.util.ThrowableHandler;
public class LocationsHandler extends AbstractHandler {
public LocationsHandler(ZetaServlet servlet) {
super(servlet, 43200000, 43200000, 86400000); }
public String createPage(Connection con) throws SQLException, ServletException {
Map locations = new TreeMap();
synchronized (countryPos) {
if (isoCountryCode.size() == 0) {
Statement stmt = null;
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT code,country,x,y FROM zeta.iso_country_code ORDER BY code");
while (rs.next()) {
isoCountryCode.add(rs.getString(1).substring(1));
Object[] o = new Object[3];
o[0] = rs.getString(2);
int x = rs.getInt(3);
int y = rs.getInt(4);
if (x == 0 && y == 0) {
o[1] = o[2] = null;
} else {
o[1] = new Integer(x);
o[2] = new Integer(y);
}
countryData.add(o);
}
rs.close();
} catch (SQLException e) {
throw e;
} finally {
DatabaseUtils.close(stmt);
}
}
countryPos.clear();
computers.clear();
Table table = CachedQueries.getWorkstationTable();
if (table == null) {
new WorkstationsHandler(null).createPage(con);
table = CachedQueries.getWorkstationTable();
}
for (int i = 0, l = table.getRowCount(); i < l; ++i) {
String location = "Unresolved/Unknown";
String name = ((String)table.getValue(i, 0)).toLowerCase();
int idx2 = name.lastIndexOf(',');
int idx1 = name.lastIndexOf(',', Math.max(0, idx2-1));
if (idx1 < idx2 && idx1 >= 0) {
idx1 = name.indexOf('@', idx1+1);
int idx3 = name.indexOf('.', idx1);
if (idx1 < idx3 && idx3 < idx2) {
idx1 = isoCountryCode.indexOf(name.substring(idx1+1, idx3));
if (idx1 < 0 || idx3+1 == idx2 || name.indexOf('.', idx3+1) < 0) { idx3 = name.lastIndexOf('.', idx2);
if (idx3+1 < idx2) {
idx1 = isoCountryCode.indexOf(name.substring(idx3+1, idx2));
}
}
if (idx1 >= 0) {
location = (String)((Object[])countryData.get(idx1))[0];
}
}
}
Set users = (Set)locations.get(location);
if (users == null) {
users = new HashSet(100);
locations.put(location, users);
if (idx1 >= 0) {
Object[] o = (Object[])countryData.get(idx1);
if (o[1] != null && o[2] != null) {
countryPos.add(o);
}
}
}
if (idx2 > 0) {
name = name.substring(0, idx2);
}
if (!users.contains(name)) {
users.add(name);
Integer count = (Integer)computers.get(location);
computers.put(location, new Integer(CachedQueries.getMaxComputersUsed(name) + ((count == null)? 0 : count.intValue())));
}
}
}
HtmlTableGenerator generator = new HtmlTableGeneratorWithSum(servlet);
Table table = new Table(3);
table.setColumnName(0, "country");
table.setType(0, Types.VARCHAR);
table.setAlignment(0, Table.LEFT);
table.setColumnName(1, "users");
table.setType(1, Types.INTEGER);
table.setAlignment(1, Table.RIGHT);
table.setColumnName(2, "computers");
table.setType(2, Types.INTEGER);
table.setAlignment(2, Table.RIGHT);
Iterator i = locations.keySet().iterator();
for (int row = 0; i.hasNext();) {
String country = (String)i.next();
Integer count = (Integer)computers.get(country);
if (count != null) {
table.addRow();
table.setValue(row, 0, country);
table.setValue(row, 1, new Integer(((Collection)locations.get(country)).size()));
table.setValue(row, 2, count);
++row;
}
}
QueryWithSum.addSum(table);
StringBuffer buffer = new StringBuffer(70*1024);
buffer.append("<tr><td colspan=\"6\"><p><center><img src=\"locations?image=map\" height=");
buffer.append(WorldmapBuffer.HEIGHT);
buffer.append(" width=");
buffer.append(WorldmapBuffer.WIDTH);
buffer.append("></center></td></tr>\n");
buffer.append("<tr><td colspan=\"6\" height=\"30pt\" class=\"second-head-gray\"><center>Locations:</center></td></tr>");
buffer.append("<tr><td colspan=\"6\">");
buffer.append("<br><center>");
buffer.append(generator.generate(table));
buffer.append("</center></td></tr>");
return buffer.toString();
}
public BufferedImage createImage(Connection con, String imageName) throws SQLException, ServletException {
if (isoCountryCode.size() == 0) {
createPage(con);
}
Color notFillColor = new Color(255, 255, 255);
Image image = Toolkit.getDefaultToolkit().createImage(WorldmapBuffer.getImage());
MediaTracker tracker = new MediaTracker(new Label());
tracker.addImage(image, 0);
try {
tracker.waitForID(0);
tracker.removeImage(image);
int maxValue = 0;
List coordinates = null;
synchronized (countryPos) {
final int l = countryPos.size();
for (int i = 0; i < l; ++i) {
Object[] o = (Object[])countryPos.get(i);
Integer count = (Integer)computers.get(o[0]);
if (count != null) {
int c = count.intValue();
if (maxValue < c) {
maxValue = c;
}
}
}
coordinates = new ArrayList(l);
for (int value = 1; value <= maxValue; value *= 10) {
int valueHigh = value*10;
for (int i = 0; i < l; ++i) {
Object[] o = (Object[])countryPos.get(i);
Integer count = (Integer)computers.get(o[0]);
if (count != null) {
int c = count.intValue();
if (c >= value && c < valueHigh) {
coordinates.add(new Object[] { o[1], o[2], getColor(c) });
}
}
}
}
}
image = Graphics.floodFill(image, coordinates, notFillColor);
BufferedImage bImage = new BufferedImage(WorldmapBuffer.WIDTH, WorldmapBuffer.HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bImage.createGraphics();
g.drawImage(image, 0, 0, WorldmapBuffer.WIDTH, WorldmapBuffer.HEIGHT, null);
int sz = coordinates.size();
for (int i = 0; i < sz; ++i) {
Object[] o = (Object[])coordinates.get(i);
int x = ((Integer)o[0]).intValue();
int y = ((Integer)o[1]).intValue();
g.setPaint((Color)o[2]);
g.fillArc(x-3, y-3, 8, 8, 0, 360);
}
g.setFont(new Font(g.getFont().getName(), Font.PLAIN, 10));
for (int value = 1, pos = WorldmapBuffer.HEIGHT+15-18*((int)Math.round(0.5+Math.log(maxValue)*0.43429448190325182765112891891661)); value <= maxValue; pos += 15) {
g.setPaint(getColor(value));
g.fillArc(5, pos-4, 8, 8, 0, 360);
int nextValue = value*10;
g.drawString("between " + value + " and " + (nextValue-1) + " computers", 15, pos+3);
value = nextValue;
}
g.dispose();
return bImage;
} catch (InterruptedException e) {
return null;
}
}
private static Color getColor(int value) {
if (value >= 10000) {
return new Color(255, 255, 0);
} else if (value >= 1000) {
return new Color(255, 240, 0);
} else if (value >= 100) {
return new Color(255, 160, 0);
} else if (value >= 10) {
return new Color(200, 80, 0);
}
return new Color(255, 0, 0);
}
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("USAGE: <name> <password>");
return;
}
try {
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
Connection con = java.sql.DriverManager.getConnection("jdbc:db2:zeta", args[0], args[1]);
LocationsHandler handler = new LocationsHandler(null);
BufferedImage bImage = handler.createImage(con, "map");
ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream(32*1024);
com.sun.jimi.core.encoder.png.PNGEncoder encoder = new com.sun.jimi.core.encoder.png.PNGEncoder();
encoder.encodeImage(com.sun.jimi.core.Jimi.createRasterImage(bImage.getSource()), imageBuffer);
imageBuffer.close();
zeta.util.StreamUtils.writeData(new java.io.ByteArrayInputStream(imageBuffer.toByteArray()), new java.io.FileOutputStream("map.png"), true, true);
Iterator i = handler.computers.keySet().iterator();
while (i.hasNext()) {
String location = (String)i.next();
final int l = handler.countryData.size();
int idx = -1;
while (++idx < l && !((Object[])handler.countryData.get(idx))[0].equals(location));
if (idx == l || ((Object[])handler.countryData.get(idx))[1] == null) {
System.out.println(location + " has no valid position");
}
}
} catch (Exception ex) {
ThrowableHandler.handle(ex);
}
System.exit(1);
}
private Map computers = new HashMap(150);
private List isoCountryCode = new ArrayList(300);
private List countryData = new ArrayList(300);
private List countryPos = new ArrayList(100);
}