/** @param args */
  public static void main(String[] args) {
    if (args.length != 3) {
      logger.log(Level.SEVERE, "usage: <logdir> <zonefile> <outdir>");
      System.exit(-1);
    }
    try {
      cLat = 52.987253;
      cLon = -1.8895595;
      cX = Mercator.mercX(cLon);
      cY = Mercator.mercY(cLat);
      // http://maps.googleapis.com/maps/api/staticmap?center=40.714728,-73.998672&zoom=12&size=400x400&maptype=satellite&sensor=false
      // INFO: lon: -1.896922 to -1.882197, lat: 52.984308 to 52.990198
      // http://maps.googleapis.com/maps/api/staticmap?center=52.987253,-1.8895595&zoom=14&size=640x640&maptype=satellite&sensor=false
      List<UserData> users = LogReader.readLogs(new File(args[0]));
      Map<Integer, Zone> zones = LogReader.readZones(new File(args[1]));
      logger.log(Level.INFO, "Read " + zones.size() + " zones");
      File outdir = new File(args[2]);
      if (!outdir.isDirectory()) {
        logger.log(Level.SEVERE, "Output directory not valid: " + outdir);
        System.exit(-1);
      }

      width = 2000;

      SvgFile svg = createBackgroundFile(new File(outdir, "park.svg"));
      {
        double minX = Double.MAX_VALUE,
            minY = Double.MAX_VALUE,
            maxX = -Double.MAX_VALUE,
            maxY = -Double.MAX_VALUE;
        double minLat = Double.MAX_VALUE,
            minLon = Double.MAX_VALUE,
            maxLat = -Double.MAX_VALUE,
            maxLon = -Double.MAX_VALUE;
        float minHOD = Float.MAX_VALUE, maxHOD = -Float.MAX_VALUE;
        float minHOD2 = Float.MAX_VALUE, maxHOD2 = -Float.MAX_VALUE;
        for (UserData user : users) {
          for (Position p : user.getPositions()) {
            if (p.isTruncated()) continue;

            double x = p.getX();
            double y = p.getY();
            if (x < minX) minX = x;
            if (x > maxX) maxX = x;
            if (y < minY) minY = y;
            if (y > maxY) maxY = y;
            double lat = p.getLat();
            double lon = p.getLon();
            if (lat < minLat) minLat = lat;
            if (lat > maxLat) maxLat = lat;
            if (lon < minLon) minLon = lon;
            if (lon > maxLon) maxLon = lon;
            float hod = p.getHourOfDay();
            if (hod < minHOD) minHOD = hod;
            if (hod > maxHOD) maxHOD = hod;
          }
          for (Event e : user.getEvents()) {
            Float hod = e.getHourOfDay();
            if (hod == null) continue;
            if (hod < minHOD2) minHOD2 = hod;
            if (hod > maxHOD2) maxHOD2 = hod;
          }
        }
        logger.log(
            Level.INFO, "Ranges, x: " + minX + " to " + maxX + ", y: " + minY + " to " + maxY);
        logger.log(
            Level.INFO,
            "Ranges, lon: " + minLon + " to " + maxLon + ", lat: " + minLat + " to " + maxLat);
        logger.log(Level.INFO, "Ranges, HOD: " + minHOD + " to " + maxHOD);
        logger.log(Level.INFO, "Ranges, HOD2: " + minHOD2 + " to " + maxHOD2);
        minX -= BORDER_M;
        minY -= BORDER_M;
        maxX += BORDER_M;
        maxY += BORDER_M;
      }
      // String stroke = "#ff0000";
      drawPositions(svg, users, "#222", false);
      drawZones(svg, zones);

      svg.close();
      svg = createBackgroundFile(new File(outdir, "allusers.svg"));
      drawPositions(svg, users, null, false);
      svg.close();

      svg = createBackgroundFile(new File(outdir, "allevents.svg"));
      drawPositions(svg, users, null, false);
      drawEvents(svg, users, null, zones);
      svg.close();

      svg.close();
      svg = createBackgroundFile(new File(outdir, "allusershod.svg"));
      drawPositionsHod(svg, users, false);
      drawEventsHod(svg, users, zones);
      svg.close();

      svg = createBackgroundFile(new File(outdir, "allusershodtl.svg"));
      drawZones2(svg, zones);
      drawPositionsHod(svg, users, false);
      drawTimelineEventsHod(svg, users, zones);
      svg.close();

      Set<String> groups = new HashSet<String>();
      for (UserData u : users) {
        groups.add(u.getTrialid());
      }
      for (String group : groups) {
        logger.info("Group " + group);
        svg = createBackgroundFile(new File(outdir, "allusershod-" + group + ".svg"));
        List<UserData> members = new LinkedList<UserData>();
        for (UserData u : users) if (u.getTrialid().equals(group)) members.add(u);
        drawPositionsHod(svg, members, false);
        drawEventsHod(svg, members, zones);
        svg.close();

        svg = createBackgroundFile(new File(outdir, "allusershodtl-" + group + ".svg"));
        drawZones2(svg, zones);
        drawPositionsHod(svg, members, false);
        drawTimelineEventsHod(svg, members, zones);
        svg.close();
      }
      for (UserData user : users) {
        logger.info("User " + user.getTrialid() + " " + user.getTrialuserid());
        svg =
            createBackgroundFile(
                new File(
                    outdir,
                    "allusershod-" + user.getTrialid() + "-" + user.getTrialuserid() + ".svg"));
        List<UserData> members = new LinkedList<UserData>();
        members.add(user);
        drawPositionsHod(svg, members, false);
        drawEventsHod(svg, members, zones);
        svg.close();

        svg =
            createBackgroundFile(
                new File(
                    outdir,
                    "allusershodtl-" + user.getTrialid() + "-" + user.getTrialuserid() + ".svg"));
        drawZones2(svg, zones);
        drawPositionsHod(svg, members, false);
        drawTimelineEventsHod(svg, members, zones);
        svg.close();
      }

    } catch (Exception e) {
      logger.log(Level.SEVERE, "Error creating " + args[1], e);
    }
  }