/**
 * Time the amount of time it takes to run pieces of code, by setting messages
 * every so often, and then figure out the times inbetween messages.
 * <p/>
 * This is a JS version of what is in com.cnetnetworks.util.Timer as Java code.
 * <p/>
 *
 * @author Adam Goldband (adam.goldband@cnet.com)
 * @version $Revision: 1.10 $
 */


var Timer = Class.create();
Timer.prototype = {

    /* Constants */
    BUFFER_LENGTH : 256,
    OPEN_HTML_TABLE : "<table border=1 cellpadding='3' cellspacing='3'>",
    OPEN_HTML_TABLE_ROW : "<tr>",
    OPEN_HTML_TABLE_CELL : "<td>",
    CLOSE_HTML_TABLE_ROW : "</tr>",
    CLOSE_HTML_TABLE_CELL : "</td>",
    CLOSE_HTML_TABLE : "</table>",


    /**
     * Allow instantiation
     */
    initialize: function() {
        this.allMessagesMap = new Object(); // letting it order naturally, since Long values are the keys...
        this.allMessagesMap2 = new Object(); // This is the reverse of the one above...
        this.msgList = new Array();
        return this;
    },

    /**
     * Adds a new message to the timer, which is timestamped internally.
     *
     * @param msg the mesage you want added
     */
    addMessage : function(msg) {
        this.msgList.push(msg);
        var currentTimeMillis = new Date().getTime();
        this.allMessagesMap[currentTimeMillis] = msg;
        this.allMessagesMap2[msg] = currentTimeMillis;
    },

    /**
     * Get the pre sorted (from first set to last) {@link Map.Entry} object,
     * whose key is the message and value is the {@link Long} timeInMilliseconds for each
     * message added.
     *
     * @return Set of unique entries, or null if no <code>Map.Entry</code>'s can be found
    public Set getAllEntries() {
        return allMessagesMap.entrySet();
    }
     */

    /**
     * Retieve the <code>long</code> that was set at the time the given message was added.
     *
     * @param message that was added
     * @return long the time in milliseconds since Epoch that the message was added, or -1 if the entry cannot be found
     */
    getLongTimeForMessage : function(message) {
//        Set allEntries = getAllEntries();
//        long longToReturn = -1;
//        for (Iterator i = allEntries.iterator(); i.hasNext();) {
//            Map.Entry entry = (Map.Entry)i.next();
//            if (message.equals(entry.getValue())) {
//                longToReturn = ((Long)entry.getKey()).longValue();
//            }
//        }
//        return longToReturn;
        return this.allMessagesMap2[message];
    },

    /**
     * Retieve the <code>Date</code> that was set at the time the given message was added.
     *
     * @param message that was added
     * @return Date the Date value for when the given message was added, or null if the entry cannot be found
     */
    getDateForMessage : function(message) {
        return new Date(getLongTimeForMessage(message));
    },

    /**
     * Retrieve the <code>Long</code> value of the number of milliseconds since
     * Epoch for when the first message was added.
     *
     * @return Long number of milliseconds since Epoch for when the first message was added
     * @throws java.util.NoSuchElementException if no messages have been added yet
     */
    getStartTimeInMilliseconds : function() {
        for (message in this.allMessagesMap) {
            return this.allMessagesMap[message]; // return the first one...
        }
//        return this.allMessagesMap.keys()[0];
//        return ((Long)allMessagesMap.firstKey()).longValue();
    },

    /**
     * Retrieve the <code>Long</code> value of the number of milliseconds since
     * Epoch for when the last message was added.
     *
     * @return Long number of milliseconds since Epoch for when the last message was added
     * @throws java.util.NoSuchElementException if no messages have been added yet
     */
    getEndTimeInMilliseconds : function() {
        var lastOne = null;
        for (message in this.allMessagesMap) {
            lastOne = this.allMessagesMap[message]; // keep setting till we get to the last one...
        }
        return lastOne;
//
        //        return this.allMessagesMap.keys()[this.allMessagesMap.keys().length - 1];
//        return ((Long)allMessagesMap.lastKey()).longValue();
    },

    /**
     * Calculates the amount of time in milliseconds from the first entry to the last.
     * Calculation is simply the EndTime - StartTime
     *
     * @return Long the difference between endDate and startDate, in milliseconds
     * @throws java.util.NoSuchElementException if no messages have been added yet
     */
    getTotalTimeTaken : function() {
        return this.getEndTimeInMilliseconds() - this.getStartTimeInMilliseconds();
    },

    /**
     * Finds the times foreach message given, and returns their difference.
     * Will always return a positive value, or 0, because internally it looks to see which
     * value is larger before doing the calculation.
     *
     * @param message1 The first message to pull a value for
     * @param message2 The second message to pull a value for
     * @return long which will be positive if both messages have been previously added, or 0 if the message are the same
     * or managed to get added so fast that there is no difference in their times
     * @throws java.util.NoSuchElementException if either of the messages had not previously been added
     */
    computeTimeBetweenMessages : function(message1, message2) {
        var msg1Time = getLongTimeForMessage(message1);
        var msg2Time = getLongTimeForMessage(message2);

        if (msg1Time > msg2Time) {
            return msg1Time - msg2Time;
        } else if (msg2Time > msg1Time) {
            return msg2Time - msg1Time;
        } else {
            // O-Boy, they are the same... how did that happen...
            return 0;
        }
    },

    /**
     * Runs throw all the current messages and values and builds a String that
     * shows each set in the form of: (Message) - (difference from previous message),
     * along with the start and end {@link Date} values at the beginning and end, respectively.
     *
     * @return String the value described above, or the message &quot;No current values&quot;
     * if no messages have been added yet
     */
    toString : function() {
        this.addMessage("calling toString on Timer");
        if (this.msgList == 0) {
            return "No current values";
        } else {
            var buf = "";
//            buf += "StartTime: " + new Date(this.getStartTimeInMilliseconds()) + "\n";

            // loop through all values...
            var timeOfLastEntry;
            var num;
            if (null != this.msgList && (num = this.msgList.length) > 0) {
                for (var i = 0; i < num; i++) {
                    var msg = this.msgList[i];
                    var thisOnesTime = this.allMessagesMap2[msg];
                    buf += "  " + msg + " - ";
                    if (null != timeOfLastEntry && null != thisOnesTime) {
                        buf += (parseFloat(thisOnesTime) - parseFloat(timeOfLastEntry));
                    } else {
                        buf += "0";
                    }
                    buf += "\n";
                    timeOfLastEntry = thisOnesTime;
                }
            }

            var endTime = this.getEndTimeInMilliseconds();
            buf += "\nTotal time: " + this.getTotalTimeTaken() + " ms";
            return buf;
        }
    }

    /**
     * Outputs the info in a simple HTML table format
     *
     * @return String the html table
    public String toHtmlTable() {
        StringBuffer buf = new StringBuffer(BUFFER_LENGTH);
        buf += OPEN_HTML_TABLE);

        if (allMessagesMap.isEmpty()) {
            buf += OPEN_HTML_TABLE_ROW);
            buf += OPEN_HTML_TABLE_CELL);
            buf += "No current values");
            buf += CLOSE_HTML_TABLE_CELL);
            buf += CLOSE_HTML_TABLE_ROW);
        } else {
            buf += OPEN_HTML_TABLE_ROW);
            buf += OPEN_HTML_TABLE_CELL);
            buf += "StartTime: ");
            buf += CLOSE_HTML_TABLE_CELL);
            buf += OPEN_HTML_TABLE_CELL);
            buf += new Date(getStartTimeInMilliseconds()).toString());
            buf += CLOSE_HTML_TABLE_CELL);
            buf += CLOSE_HTML_TABLE_ROW);

            // loop through all values...
            Long timeOfLastEntry = null;
            for (Iterator i = getAllEntries().iterator(); i.hasNext();) {
                buf += OPEN_HTML_TABLE_ROW);
                buf += OPEN_HTML_TABLE_CELL);
                Map.Entry currentEntry = (Map.Entry)i.next();
                buf += currentEntry.getKey()).append(" - ").append(currentEntry.getValue());
                buf += CLOSE_HTML_TABLE_CELL);
                buf += OPEN_HTML_TABLE_CELL);
                if (timeOfLastEntry != null) {
                    buf += ((Long)currentEntry.getKey()).longValue() - timeOfLastEntry.longValue());
                } else {
                    buf += "0");
                }
                buf += CLOSE_HTML_TABLE_CELL);
                buf += CLOSE_HTML_TABLE_ROW);

                timeOfLastEntry = (Long)currentEntry.getKey();
            }
            buf += OPEN_HTML_TABLE_ROW);
            buf += OPEN_HTML_TABLE_CELL);
            buf += "EndTime: ").append(new Date(getEndTimeInMilliseconds()).toString()).append("\n");
            buf += CLOSE_HTML_TABLE_CELL);
            buf += CLOSE_HTML_TABLE_ROW);
            buf += CLOSE_HTML_TABLE);
        }

        return buf.toString();
    }
   */
}
