package controllers;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.bson.types.ObjectId;
import com.mongodb.BasicDBObject;
import net.vz.mongodb.jackson.DBCursor;
import net.vz.mongodb.jackson.DBQuery;
import net.vz.mongodb.jackson.DBQuery.Query;
import models.RecordedLocation;
import models.TrackSession;
import models.TrackedAction;
import models.User;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Security;
import setups.AppConfig;
import utils.HeatMap;
import utils.Tools;
@Security.Authenticated(AdminSecurity.class)
public class Heatmaps extends Controller {
public static class HeatMapRequest {
public int multiplier;
public Long start_date;
public Long end_date;
public HeatMapRequest() {
multiplier = 100;
}
}
//http://www.intuit.com/website-building-software/blog/2011/10/how-to-use-heat-maps-to-maximize-your-sites-success/
public static Result filter( String locId ) {
RecordedLocation.Model location = RecordedLocation.coll.findOneById(locId);
if( location == null ) return badRequest();
TrackSession.Model session = TrackSession.coll.findOneById( location.sessionId );
if( session == null ) return badRequest();
User.Model user = User.coll.findOneById( session.userId );
if( user == null ) return badRequest();
return ok( views.html.heatmaps.filter.render( location, session, user ) );
}
public static Result mouseFollowHeat(String locId) {
Form<HeatMapRequest> heatRequest = form(HeatMapRequest.class).bindFromRequest();
RecordedLocation.Model location = RecordedLocation.coll.findOneById(locId);
Query locationsQuery = DBQuery.is("location", location.location);
if( heatRequest.get().start_date != null && heatRequest.get().start_date > 0) locationsQuery.greaterThanEquals("startedAt", new Date( heatRequest.get().start_date ) );
if( heatRequest.get().end_date != null && heatRequest.get().end_date > 0) locationsQuery.lessThanEquals("startedAt", new Date( heatRequest.get().end_date ) );
DBCursor<RecordedLocation.Model> locations = RecordedLocation.coll.find( locationsQuery );
Short maxWidth = 0;
DBCursor< TrackedAction.Model > action;
Collection<ObjectId> locationsCollection = new ArrayList<ObjectId>();
while( locations.hasNext() ) {
RecordedLocation.Model currLoc = locations.next();
locationsCollection.add( new ObjectId( currLoc._id ) );
action = TrackedAction.coll.find( DBQuery.exists("w").is("recLocId", new ObjectId( currLoc._id )) ).limit(1).sort( new BasicDBObject("w", -1) );
maxWidth = (short) Math.max(maxWidth, action.next().w);
}
String pageMap;
// pageMap = AppConfig.temporaryFilesDirectory + UUID.randomUUID().toString()+".jpg";
pageMap = AppConfig.temporaryFilesDirectory + Tools.md5Encode(location.location + ( new Date().getTime() / 86400 ) )+".jpg";
String command = AppConfig.pathToHtmlToImageGenerator + " --width "+maxWidth + " " + location.location + " " + pageMap;
try {
System.out.println( command );
Process p = Runtime.getRuntime().exec( command );
p.waitFor();
} catch (IOException e) {
e.printStackTrace();
return internalServerError();
} catch (InterruptedException e) {
e.printStackTrace();
return internalServerError();
}
List<GeneralPath> points = new ArrayList<GeneralPath>();
GeneralPath path = null;
action = TrackedAction.coll.find( DBQuery.exists("w").exists("x").exists("y").in("recLocId", locationsCollection ).is("e", 2) )
.sort( new BasicDBObject("recLocId", 1) )
.sort( new BasicDBObject("sessionId", 1) )
.sort( new BasicDBObject("ts", 1) );
String currLocId = null;
Point prevPoint = null;
int radius = 32;
while(action.hasNext()) {
TrackedAction.Model curract = action.next();
Short diff = (short) ((maxWidth - curract.w) / 2);
if( currLocId == null || !currLocId.equals( curract.recLocId ) ) {
if( path != null ) {
points.add( path );
}
path = new GeneralPath();
path.moveTo(curract.x + diff, curract.y);
prevPoint = new Point( curract.x + diff, curract.y );
currLocId = curract.recLocId;
} else {
if( Math.asin( prevPoint.x - (curract.x + diff) ) < radius && Math.abs( prevPoint.y - curract.y ) < radius ) continue;
path.lineTo(curract.x + diff, curract.y);
prevPoint = new Point( curract.x + diff, curract.y );
}
}
if( path != null ) points.add( path );
System.out.println( points.size() );
String heatMapOutput = AppConfig.temporaryFilesDirectory + UUID.randomUUID().toString()+".png";
HeatMap hmap = new HeatMap(heatMapOutput, pageMap);
hmap.createLinesHeatMap(0.0F + (float)heatRequest.get().multiplier / 100F, points);
// System.out.println( "Points: " + points.size() );
// System.out.println( "Maxwidth: " + maxWidth );
new File(pageMap).delete();
response().setContentType( "image/png" );
try {
byte[] outB = IOUtils.toByteArray( new FileInputStream(new File( heatMapOutput )) );
return ok( outB );
} catch (FileNotFoundException e) {
e.printStackTrace();
return internalServerError("Error generating the outBuffer");
} catch (IOException e) {
e.printStackTrace();
return internalServerError("Error generating the outBuffer");
}
// return ok( new File( heatMapOutput ) );
}
public static Result siteFoldHeat(String locId) {
Form<HeatMapRequest> heatRequest = form(HeatMapRequest.class).bindFromRequest();
RecordedLocation.Model location = RecordedLocation.coll.findOneById(locId);
Query locationsQuery = DBQuery.is("location", location.location);
if( heatRequest.get().start_date != null && heatRequest.get().start_date > 0) locationsQuery.greaterThanEquals("startedAt", new Date( heatRequest.get().start_date ) );
if( heatRequest.get().end_date != null && heatRequest.get().end_date > 0) locationsQuery.lessThanEquals("startedAt", new Date( heatRequest.get().end_date ) );
DBCursor<RecordedLocation.Model> locations = RecordedLocation.coll.find( locationsQuery );
Short maxWidth = 0;
DBCursor< TrackedAction.Model > action;
Collection<ObjectId> locationsCollection = new ArrayList<ObjectId>();
while( locations.hasNext() ) {
RecordedLocation.Model currLoc = locations.next();
locationsCollection.add( new ObjectId( currLoc._id ) );
action = TrackedAction.coll.find( DBQuery.exists("w").is("recLocId", new ObjectId( currLoc._id )) ).limit(1).sort( new BasicDBObject("w", -1) );
maxWidth = (short) Math.max(maxWidth, action.next().w);
}
String pageMap;
// pageMap = AppConfig.temporaryFilesDirectory + UUID.randomUUID().toString()+".jpg";
pageMap = AppConfig.temporaryFilesDirectory + Tools.md5Encode(location.location + ( new Date().getTime() / 86400 ) )+".jpg";
String command = AppConfig.pathToHtmlToImageGenerator + " --width "+maxWidth + " " + location.location + " " + pageMap;
try {
System.out.println( command );
Process p = Runtime.getRuntime().exec( command );
p.waitFor();
} catch (IOException e) {
e.printStackTrace();
return internalServerError();
} catch (InterruptedException e) {
e.printStackTrace();
return internalServerError();
}
List<Rectangle> points = new ArrayList<Rectangle>();
Iterator< ObjectId > locationsIterator = locationsCollection.iterator();
Rectangle tmpRectangle = null;
Short wDiff;
while( locationsIterator.hasNext() ) {
ObjectId locId1 = locationsIterator.next();
//TODO: get the real max values
action = TrackedAction.coll.find( DBQuery.exists("w").exists("h").is("recLocId", locId1 ).is("e", 0) )
.sort( new BasicDBObject("h", -1) ).limit(1);
int h = 0, t = 0, w = 0;;
if( action.size() > 0 ) {
TrackedAction.Model currentAction = action.next();
h = currentAction.h;
w= currentAction.w;
}
wDiff = (short) ((maxWidth - w) / 2);
tmpRectangle = new Rectangle(wDiff, 0, w, h);
points.add( tmpRectangle );
}
String heatMapOutput = AppConfig.temporaryFilesDirectory + UUID.randomUUID().toString()+".png";
HeatMap hmap = new HeatMap(heatMapOutput, pageMap);
hmap.buildData( points );
hmap.createFoldHeatMap( 0.0F + heatRequest.get().multiplier / 10f );
// System.out.println( "Points: " + points.size() );
// System.out.println( "Maxwidth: " + maxWidth );
new File(pageMap).delete();
response().setContentType( "image/png" );
try {
byte[] outB = IOUtils.toByteArray( new FileInputStream(new File( heatMapOutput )) );
return ok( outB );
} catch (FileNotFoundException e) {
e.printStackTrace();
return internalServerError("Error generating the outBuffer");
} catch (IOException e) {
e.printStackTrace();
return internalServerError("Error generating the outBuffer");
}
// return ok( new File( heatMapOutput ) );
}
public static Result clickHeat(String locId) {
Form<HeatMapRequest> heatRequest = form(HeatMapRequest.class).bindFromRequest();
RecordedLocation.Model location = RecordedLocation.coll.findOneById(locId);
Query locationsQuery = DBQuery.is("location", location.location);
if( heatRequest.get().start_date != null && heatRequest.get().start_date > 0) locationsQuery.greaterThanEquals("startedAt", new Date( heatRequest.get().start_date ) );
if( heatRequest.get().end_date != null && heatRequest.get().end_date > 0) locationsQuery.lessThanEquals("startedAt", new Date( heatRequest.get().end_date ) );
DBCursor<RecordedLocation.Model> locations = RecordedLocation.coll.find( locationsQuery );
Short maxWidth = 0;
DBCursor< TrackedAction.Model > action;
Collection<ObjectId> locationsCollection = new ArrayList<ObjectId>();
while( locations.hasNext() ) {
RecordedLocation.Model currLoc = locations.next();
locationsCollection.add( new ObjectId( currLoc._id ) );
action = TrackedAction.coll.find( DBQuery.exists("w").is("recLocId", new ObjectId( currLoc._id )) ).limit(1).sort( new BasicDBObject("w", -1) );
maxWidth = (short) Math.max(maxWidth, action.next().w);
}
String pageMap;
// pageMap = AppConfig.temporaryFilesDirectory + UUID.randomUUID().toString()+".jpg";
pageMap = AppConfig.temporaryFilesDirectory + Tools.md5Encode(location.location + ( new Date().getTime() / 86400 ) )+".jpg";
String command = AppConfig.pathToHtmlToImageGenerator + " --width "+maxWidth + " " + location.location + " " + pageMap;
try {
System.out.println( command );
Process p = Runtime.getRuntime().exec( command );
p.waitFor();
} catch (IOException e) {
e.printStackTrace();
return internalServerError();
} catch (InterruptedException e) {
e.printStackTrace();
return internalServerError();
}
List<Point> points = new ArrayList<Point>();
action = TrackedAction.coll.find( DBQuery.exists("w").exists("x").exists("y").in("recLocId", locationsCollection ).is("e", 1) )
.sort( new BasicDBObject("x", 1) ).sort( new BasicDBObject("y", 1) );
while(action.hasNext()) {
TrackedAction.Model curract = action.next();
Short diff = (short) ((maxWidth - curract.w) / 2);
points.add( new Point(curract.x + diff, curract.y) );
}
String heatMapOutput = AppConfig.temporaryFilesDirectory + UUID.randomUUID().toString()+".png";
HeatMap hmap = new HeatMap(points, heatMapOutput, pageMap);
hmap.createHeatMap(0.0F + heatRequest.get().multiplier / 10 );
// System.out.println( "Points: " + points.size() );
// System.out.println( "Maxwidth: " + maxWidth );
new File(pageMap).delete();
response().setContentType( "image/png" );
try {
byte[] outB = IOUtils.toByteArray( new FileInputStream(new File( heatMapOutput )) );
return ok( outB );
} catch (FileNotFoundException e) {
e.printStackTrace();
return internalServerError("Error generating the outBuffer");
} catch (IOException e) {
e.printStackTrace();
return internalServerError("Error generating the outBuffer");
}
// return ok( new File( heatMapOutput ) );
}
}