/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.asterix.tools.external.data;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import org.apache.asterix.external.generator.DataGenerator;

public class DataGeneratorForSpatialIndexEvaluation {

    private static final String DUMMY_SIZE_ADJUSTER = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    private RandomDateGenerator randDateGen;

    private RandomNameGenerator randNameGen;

    private RandomMessageGenerator randMessageGen;

    private RandomLocationGenerator randLocationGen;

    private LocationGeneratorFromOpenStreetMapData locationGenFromOpenStreetMapData;

    private Random random = new Random();

    private TwitterUser twUser = new TwitterUser();

    private TweetMessage twMessage = new TweetMessage();

    public DataGeneratorForSpatialIndexEvaluation(InitializationInfo info) {
        initialize(info, null, 0);
    }

    public DataGeneratorForSpatialIndexEvaluation(InitializationInfo info, String openStreetMapFilePath,
            int locationSampleInterval) {
        initialize(info, openStreetMapFilePath, locationSampleInterval);
    }

    public class TweetMessageIterator implements Iterator<TweetMessage> {

        private int duration;
        private final GULongIDGenerator idGen;
        private long startTime = 0;

        public TweetMessageIterator(int duration, GULongIDGenerator idGen) {
            this.duration = duration;
            this.idGen = idGen;
            this.startTime = System.currentTimeMillis();
        }

        @Override
        public boolean hasNext() {
            if (duration == 0) {
                return true;
            }
            return System.currentTimeMillis() - startTime <= duration * 1000;
        }

        @Override
        public TweetMessage next() {
            TweetMessage msg = null;
            getTwitterUser(null);
            Message message = randMessageGen.getNextRandomMessage();
            Point location = randLocationGen != null ? randLocationGen.getRandomPoint()
                    : locationGenFromOpenStreetMapData.getNextPoint();
            DateTime sendTime = randDateGen.getNextRandomDatetime();
            int btreeExtraFieldKey = random.nextInt();
            if (btreeExtraFieldKey == Integer.MIN_VALUE) {
                btreeExtraFieldKey = Integer.MIN_VALUE + 1;
            }
            twMessage.reset(idGen.getNextULong(), twUser, location, sendTime, message.getReferredTopics(), message,
                    btreeExtraFieldKey, DUMMY_SIZE_ADJUSTER);
            msg = twMessage;
            return msg;
        }

        @Override
        public void remove() {
            // TODO Auto-generated method stub
        }

        public void resetDuration(int duration) {
            this.duration = duration;
            startTime = System.currentTimeMillis();
        }

    }

    public static class InitializationInfo {
        public Date startDate = new Date(1, 1, 2005);
        public Date endDate = new Date(8, 20, 2012);
        public String[] lastNames = DataGenerator.lastNames;
        public String[] firstNames = DataGenerator.firstNames;
        public String[] vendors = DataGenerator.vendors;
        public String[] jargon = DataGenerator.jargon;
        public String[] org_list = DataGenerator.org_list;
    }

    public void initialize(InitializationInfo info, String openStreetMapFilePath, int locationSampleInterval) {
        randDateGen = new RandomDateGenerator(info.startDate, info.endDate);
        randNameGen = new RandomNameGenerator(info.firstNames, info.lastNames);
        if (openStreetMapFilePath == null) {
            randLocationGen = new RandomLocationGenerator(24, 49, 66, 98);
            locationGenFromOpenStreetMapData = null;
        } else {
            locationGenFromOpenStreetMapData = new LocationGeneratorFromOpenStreetMapData();
            locationGenFromOpenStreetMapData.intialize(openStreetMapFilePath, locationSampleInterval);
            randLocationGen = null;
        }
        randMessageGen = new RandomMessageGenerator(info.vendors, info.jargon);
    }

    public void getTwitterUser(String usernameSuffix) {
        String suggestedName = randNameGen.getRandomName();
        String[] nameComponents = suggestedName.split(" ");
        String screenName = nameComponents[0] + nameComponents[1] + randNameGen.getRandomNameSuffix();
        String name = suggestedName;
        if (usernameSuffix != null) {
            name = name + usernameSuffix;
        }
        int numFriends = random.nextInt((100)); // draw from Zipfian
        int statusesCount = random.nextInt(500); // draw from Zipfian
        int followersCount = random.nextInt((200));
        twUser.reset(screenName, numFriends, statusesCount, name, followersCount);
    }

    public static class RandomDateGenerator {

        private final Date startDate;
        private final Date endDate;
        private final Random random = new Random();
        private final int yearDifference;
        private Date workingDate;
        private Date recentDate;
        private DateTime dateTime;

        public RandomDateGenerator(Date startDate, Date endDate) {
            this.startDate = startDate;
            this.endDate = endDate;
            this.yearDifference = endDate.getYear() - startDate.getYear() + 1;
            this.workingDate = new Date();
            this.recentDate = new Date();
            this.dateTime = new DateTime();
        }

        public Date getStartDate() {
            return startDate;
        }

        public Date getEndDate() {
            return endDate;
        }

        public Date getNextRandomDate() {
            int year = random.nextInt(yearDifference) + startDate.getYear();
            int month;
            int day;
            if (year == endDate.getYear()) {
                month = random.nextInt(endDate.getMonth()) + 1;
                if (month == endDate.getMonth()) {
                    day = random.nextInt(endDate.getDay()) + 1;
                } else {
                    day = random.nextInt(28) + 1;
                }
            } else {
                month = random.nextInt(12) + 1;
                day = random.nextInt(28) + 1;
            }
            workingDate.reset(month, day, year);
            return workingDate;
        }

        public DateTime getNextRandomDatetime() {
            Date randomDate = getNextRandomDate();
            dateTime.reset(randomDate);
            return dateTime;
        }

        public Date getNextRecentDate(Date date) {
            int year = date.getYear()
                    + (date.getYear() == endDate.getYear() ? 0 : random.nextInt(endDate.getYear() - date.getYear()));
            int month = (year == endDate.getYear())
                    ? date.getMonth() == endDate.getMonth() ? (endDate.getMonth())
                            : (date.getMonth() + random.nextInt(endDate.getMonth() - date.getMonth()))
                    : random.nextInt(12) + 1;

            int day = (year == endDate.getYear())
                    ? month == endDate.getMonth()
                            ? date.getDay() == endDate.getDay() ? endDate.getDay()
                                    : date.getDay() + random.nextInt(endDate.getDay() - date.getDay())
                            : random.nextInt(28) + 1
                    : random.nextInt(28) + 1;
            recentDate.reset(month, day, year);
            return recentDate;
        }

    }

    public static class DateTime extends Date {

        private String hour = "10";
        private String min = "10";
        private String sec = "00";

        public DateTime(int month, int day, int year, String hour, String min, String sec) {
            super(month, day, year);
            this.hour = hour;
            this.min = min;
            this.sec = sec;
        }

        public DateTime() {
        }

        public void reset(int month, int day, int year, String hour, String min, String sec) {
            super.setDay(month);
            super.setDay(day);
            super.setYear(year);
            this.hour = hour;
            this.min = min;
            this.sec = sec;
        }

        public DateTime(Date date) {
            super(date.getMonth(), date.getDay(), date.getYear());
        }

        public void reset(Date date) {
            reset(date.getMonth(), date.getDay(), date.getYear());
        }

        public DateTime(Date date, int hour, int min, int sec) {
            super(date.getMonth(), date.getDay(), date.getYear());
            this.hour = (hour < 10) ? "0" : "" + hour;
            this.min = (min < 10) ? "0" : "" + min;
            this.sec = (sec < 10) ? "0" : "" + sec;
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("datetime");
            builder.append("(\"");
            builder.append(super.getYear());
            builder.append("-");
            builder.append(super.getMonth() < 10 ? "0" + super.getMonth() : super.getMonth());
            builder.append("-");
            builder.append(super.getDay() < 10 ? "0" + super.getDay() : super.getDay());
            builder.append("T");
            builder.append(hour + ":" + min + ":" + sec);
            builder.append("\")");
            return builder.toString();
        }
    }

    public static class Message {

        private char[] message = new char[500];
        private List<String> referredTopics;
        private int length;

        public Message(char[] m, List<String> referredTopics) {
            System.arraycopy(m, 0, message, 0, m.length);
            length = m.length;
            this.referredTopics = referredTopics;
        }

        public Message() {
            referredTopics = new ArrayList<String>();
            length = 0;
        }

        public List<String> getReferredTopics() {
            return referredTopics;
        }

        public void reset(char[] m, int offset, int length, List<String> referredTopics) {
            System.arraycopy(m, offset, message, 0, length);
            this.length = length;
            this.referredTopics = referredTopics;
        }

        public int getLength() {
            return length;
        }

        public char charAt(int index) {
            return message[index];
        }

    }

    public static class Point {

        private float latitude;
        private float longitude;

        public float getLatitude() {
            return latitude;
        }

        public float getLongitude() {
            return longitude;
        }

        public Point(float latitude, float longitude) {
            this.latitude = latitude;
            this.longitude = longitude;
        }

        public void reset(float latitude, float longitude) {
            this.latitude = latitude;
            this.longitude = longitude;
        }

        public Point() {
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("point(\"" + latitude + "," + longitude + "\")");
            return builder.toString();
        }
    }

    public static class RandomNameGenerator {

        private String[] firstNames;
        private String[] lastNames;

        private final Random random = new Random();

        private final String[] connectors = new String[] { "_", "#", "$", "@" };

        public RandomNameGenerator(String[] firstNames, String[] lastNames) {
            this.firstNames = firstNames;
            this.lastNames = lastNames;
        }

        public String getRandomName() {
            String name;
            name = getSuggestedName();
            return name;

        }

        private String getSuggestedName() {
            int firstNameIndex = random.nextInt(firstNames.length);
            int lastNameIndex = random.nextInt(lastNames.length);
            String suggestedName = firstNames[firstNameIndex] + " " + lastNames[lastNameIndex];
            return suggestedName;
        }

        public String getRandomNameSuffix() {
            return connectors[random.nextInt(connectors.length)] + random.nextInt(1000);
        }
    }

    public static class RandomMessageGenerator {

        private final MessageTemplate messageTemplate;

        public RandomMessageGenerator(String[] vendors, String[] jargon) {
            List<String> vendorList = new ArrayList<String>();
            for (String v : vendors) {
                vendorList.add(v);
            }
            List<String> jargonList = new ArrayList<String>();
            for (String j : jargon) {
                jargonList.add(j);
            }
            this.messageTemplate = new MessageTemplate(vendorList, jargonList);
        }

        public Message getNextRandomMessage() {
            return messageTemplate.getNextMessage();
        }
    }

    public static class AbstractMessageTemplate {

        protected final Random random = new Random();

        protected String[] positiveVerbs = new String[] { "like", "love" };
        protected String[] negativeVerbs = new String[] { "dislike", "hate", "can't stand" };

        protected String[] negativeAdjectives = new String[] { "horrible", "bad", "terrible", "OMG" };
        protected String[] postiveAdjectives = new String[] { "good", "awesome", "amazing", "mind-blowing" };

        protected String[] otherWords = new String[] { "the", "its" };
    }

    public static class MessageTemplate extends AbstractMessageTemplate {

        private List<String> vendors;
        private List<String> jargon;
        private CharBuffer buffer;
        private List<String> referredTopics;
        private Message message = new Message();

        public MessageTemplate(List<String> vendors, List<String> jargon) {
            this.vendors = vendors;
            this.jargon = jargon;
            buffer = CharBuffer.allocate(2500);
            referredTopics = new ArrayList<String>();
        }

        public Message getNextMessage() {
            buffer.position(0);
            buffer.limit(2500);
            referredTopics.clear();
            boolean isPositive = random.nextBoolean();
            String[] verbArray = isPositive ? positiveVerbs : negativeVerbs;
            String[] adjectiveArray = isPositive ? postiveAdjectives : negativeAdjectives;
            String verb = verbArray[random.nextInt(verbArray.length)];
            String adjective = adjectiveArray[random.nextInt(adjectiveArray.length)];

            buffer.put(" ");
            buffer.put(verb);
            buffer.put(" ");
            String vendor = vendors.get(random.nextInt(vendors.size()));
            referredTopics.add(vendor);
            buffer.append(vendor);
            buffer.append(" ");
            buffer.append(otherWords[random.nextInt(otherWords.length)]);
            buffer.append(" ");
            String jargonTerm = jargon.get(random.nextInt(jargon.size()));
            referredTopics.add(jargonTerm);
            buffer.append(jargonTerm);
            buffer.append(" is ");
            buffer.append(adjective);
            if (random.nextBoolean()) {
                buffer.append(isPositive ? ":)" : ":(");
            }

            buffer.flip();
            message.reset(buffer.array(), 0, buffer.limit(), referredTopics);
            return message;
        }
    }

    public static class RandomUtil {

        public static Random random = new Random();

        public static int[] getKFromN(int k, int n) {
            int[] result = new int[k];
            int cnt = 0;
            HashSet<Integer> values = new HashSet<Integer>();
            while (cnt < k) {
                int val = random.nextInt(n + 1);
                if (values.contains(val)) {
                    continue;
                }

                result[cnt++] = val;
                values.add(val);
            }
            return result;
        }
    }

    public static class RandomLocationGenerator {

        private Random random = new Random();

        private final int beginLat;
        private final int endLat;
        private final int beginLong;
        private final int endLong;

        private Point point;

        public RandomLocationGenerator(int beginLat, int endLat, int beginLong, int endLong) {
            this.beginLat = beginLat;
            this.endLat = endLat;
            this.beginLong = beginLong;
            this.endLong = endLong;
            this.point = new Point();
        }

        public Point getRandomPoint() {
            int latMajor = beginLat + random.nextInt(endLat - beginLat);
            int latMinor = random.nextInt(100);
            float latitude = latMajor + ((float) latMinor) / 100;

            int longMajor = beginLong + random.nextInt(endLong - beginLong);
            int longMinor = random.nextInt(100);
            float longitude = longMajor + ((float) longMinor) / 100;

            point.reset(latitude, longitude);
            return point;
        }

    }

    public static class LocationGeneratorFromOpenStreetMapData {
        /**
         * the source of gps data:
         * https://blog.openstreetmap.org/2012/04/01/bulk-gps-point-data/
         */
        private String openStreetMapFilePath;
        private long sampleInterval;
        private long lineCount = 0;
        private BufferedReader br;
        private String line;
        private String strPoints[] = null;
        private StringBuilder sb = new StringBuilder();
        private Point point = new Point();
        private float[] floatPoint = new float[2];

        public void intialize(String openStreetMapFilePath, int sampleInterval) {
            this.openStreetMapFilePath = openStreetMapFilePath;
            this.sampleInterval = sampleInterval;
            try {
                br = new BufferedReader(new FileReader(openStreetMapFilePath));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new IllegalStateException(e);
            }
        }

        public Point getNextPoint() {
            try {
                while (true) {
                    if ((line = br.readLine()) == null) {
                        br = new BufferedReader(new FileReader(openStreetMapFilePath));
                        line = br.readLine(); //can't be null
                    }
                    if (lineCount++ % sampleInterval != 0) {
                        continue;
                    }
                    sb.setLength(0);
                    strPoints = line.split(",");
                    if (strPoints.length != 2) {
                        //ignore invalid point
                        continue;
                    } else {
                        break;
                    }
                }
                if (line == null) {
                    //roll over the data from the same file.
                    br.close();
                    br = null;
                    lineCount = 0;
                    br = new BufferedReader(new FileReader(openStreetMapFilePath));
                    while ((line = br.readLine()) != null) {
                        if (lineCount++ % sampleInterval != 0) {
                            continue;
                        }
                        sb.setLength(0);
                        strPoints = line.split(",");
                        if (strPoints.length != 2) {
                            //ignore invalid point
                            continue;
                        } else {
                            break;
                        }
                    }
                }
                floatPoint[0] = Float.parseFloat(strPoints[0]) / 10000000; //latitude (y value)
                floatPoint[1] = Float.parseFloat(strPoints[1]) / 10000000; //longitude (x value)
                point.reset(floatPoint[1], floatPoint[0]);
            } catch (Exception e) {
                e.printStackTrace();
                throw new IllegalStateException(e);
            }
            return point;
        }

        @Override
        public void finalize() {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new IllegalStateException(e);
                }
            }
        }
    }

    public static class TweetMessage {

        private static int NUM_BTREE_EXTRA_FIELDS = 8;

        private long tweetid;
        private TwitterUser user;
        private Point senderLocation;
        private DateTime sendTime;
        private List<String> referredTopics;
        private Message messageText;
        private int[] btreeExtraFields;
        private String dummySizeAdjuster;

        public TweetMessage() {
            this.btreeExtraFields = new int[NUM_BTREE_EXTRA_FIELDS];
        }

        public TweetMessage(long tweetid, TwitterUser user, Point senderLocation, DateTime sendTime,
                List<String> referredTopics, Message messageText, int btreeExtraField, String dummySizeAdjuster) {
            this.tweetid = tweetid;
            this.user = user;
            this.senderLocation = senderLocation;
            this.sendTime = sendTime;
            this.referredTopics = referredTopics;
            this.messageText = messageText;
            this.btreeExtraFields = new int[NUM_BTREE_EXTRA_FIELDS];
            setBtreeExtraFields(btreeExtraField);
            this.dummySizeAdjuster = dummySizeAdjuster;
        }

        private void setBtreeExtraFields(int fVal) {
            for (int i = 0; i < btreeExtraFields.length; ++i) {
                btreeExtraFields[i] = fVal;
            }
        }

        public void reset(long tweetid, TwitterUser user, Point senderLocation, DateTime sendTime,
                List<String> referredTopics, Message messageText, int btreeExtraField, String dummySizeAdjuster) {
            this.tweetid = tweetid;
            this.user = user;
            this.senderLocation = senderLocation;
            this.sendTime = sendTime;
            this.referredTopics = referredTopics;
            this.messageText = messageText;
            setBtreeExtraFields(btreeExtraField);
            this.dummySizeAdjuster = dummySizeAdjuster;
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("{");
            builder.append("\"tweetid\":");
            builder.append("int64(\"" + tweetid + "\")");
            builder.append(",");
            builder.append("\"user\":");
            builder.append(user);
            builder.append(",");
            builder.append("\"sender-location\":");
            builder.append(senderLocation);
            builder.append(",");
            builder.append("\"send-time\":");
            builder.append(sendTime);
            builder.append(",");
            builder.append("\"referred-topics\":");
            builder.append("{{");
            for (String topic : referredTopics) {
                builder.append("\"" + topic + "\"");
                builder.append(",");
            }
            if (referredTopics.size() > 0) {
                builder.deleteCharAt(builder.lastIndexOf(","));
            }
            builder.append("}}");
            builder.append(",");
            builder.append("\"message-text\":");
            builder.append("\"");
            for (int i = 0; i < messageText.getLength(); i++) {
                builder.append(messageText.charAt(i));
            }
            builder.append("\"");
            builder.append(",");
            for (int i = 0; i < btreeExtraFields.length; ++i) {
                builder.append("\"btree-extra-field" + (i + 1) + "\":");
                builder.append(btreeExtraFields[i]);
                if (i != btreeExtraFields.length - 1) {
                    builder.append(",");
                }
            }
            builder.append(",");
            builder.append("\"dummy-size-adjuster\":");
            builder.append("\"");
            builder.append(dummySizeAdjuster);
            builder.append("\"");
            builder.append("}");
            return new String(builder);
        }

        public long getTweetid() {
            return tweetid;
        }

        public void setTweetid(long tweetid) {
            this.tweetid = tweetid;
        }

        public TwitterUser getUser() {
            return user;
        }

        public void setUser(TwitterUser user) {
            this.user = user;
        }

        public Point getSenderLocation() {
            return senderLocation;
        }

        public void setSenderLocation(Point senderLocation) {
            this.senderLocation = senderLocation;
        }

        public DateTime getSendTime() {
            return sendTime;
        }

        public void setSendTime(DateTime sendTime) {
            this.sendTime = sendTime;
        }

        public List<String> getReferredTopics() {
            return referredTopics;
        }

        public void setReferredTopics(List<String> referredTopics) {
            this.referredTopics = referredTopics;
        }

        public Message getMessageText() {
            return messageText;
        }

        public void setMessageText(Message messageText) {
            this.messageText = messageText;
        }

    }

    public static class TwitterUser {

        private String screenName;
        private String lang = "en";
        private int friendsCount;
        private int statusesCount;
        private String name;
        private int followersCount;

        public TwitterUser() {

        }

        public TwitterUser(String screenName, int friendsCount, int statusesCount, String name, int followersCount) {
            this.screenName = screenName;
            this.friendsCount = friendsCount;
            this.statusesCount = statusesCount;
            this.name = name;
            this.followersCount = followersCount;
        }

        public void reset(String screenName, int friendsCount, int statusesCount, String name, int followersCount) {
            this.screenName = screenName;
            this.friendsCount = friendsCount;
            this.statusesCount = statusesCount;
            this.name = name;
            this.followersCount = followersCount;
        }

        public String getScreenName() {
            return screenName;
        }

        public int getFriendsCount() {
            return friendsCount;
        }

        public int getStatusesCount() {
            return statusesCount;
        }

        public String getName() {
            return name;
        }

        public int getFollowersCount() {
            return followersCount;
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("{");
            builder.append("\"screen-name\":" + "\"" + screenName + "\"");
            builder.append(",");
            builder.append("\"lang\":" + "\"" + lang + "\"");
            builder.append(",");
            builder.append("\"friends_count\":" + friendsCount);
            builder.append(",");
            builder.append("\"statuses_count\":" + statusesCount);
            builder.append(",");
            builder.append("\"name\":" + "\"" + name + "\"");
            builder.append(",");
            builder.append("\"followers_count\":" + followersCount);
            builder.append("}");
            return builder.toString();
        }

    }

    public static class Date {

        private int day;
        private int month;
        private int year;

        public Date(int month, int day, int year) {
            this.month = month;
            this.day = day;
            this.year = year;
        }

        public void reset(int month, int day, int year) {
            this.month = month;
            this.day = day;
            this.year = year;
        }

        public int getDay() {
            return day;
        }

        public int getMonth() {
            return month;
        }

        public int getYear() {
            return year;
        }

        public Date() {
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("date");
            builder.append("(\"");
            builder.append(year);
            builder.append("-");
            builder.append(month < 10 ? "0" + month : "" + month);
            builder.append("-");
            builder.append(day < 10 ? "0" + day : "" + day);
            builder.append("\")");
            return builder.toString();
        }

        public void setDay(int day) {
            this.day = day;
        }

        public void setMonth(int month) {
            this.month = month;
        }

        public void setYear(int year) {
            this.year = year;
        }
    }

    public static void main(String[] args) throws Exception {
        DataGeneratorForSpatialIndexEvaluation dg = new DataGeneratorForSpatialIndexEvaluation(
                new InitializationInfo());
        TweetMessageIterator tmi = dg.new TweetMessageIterator(1, new GULongIDGenerator(0, (byte) 0));
        int len = 0;
        int count = 0;
        while (tmi.hasNext()) {
            String tm = tmi.next().toString();
            System.out.println(tm);
            len += tm.length();
            ++count;
        }
        System.out.println(DataGeneratorForSpatialIndexEvaluation.DUMMY_SIZE_ADJUSTER.length());
        System.out.println(len);
        System.out.println(count);
        System.out.println(len / count);
    }
}