/*
Licensed Materials - Property of IBM

5724S31

Copyright IBM Corp.  2007    All Rights Reserved.

US Government Users Restricted Rights - Use, duplication or
disclosure restricted by GSA ADP Schedule Contract with IBM
Corp.
*/

// Constants
var IMAGES_DIR           = 'images/';
var TEMPLATE_DIR         = 'templates/';
var EXPANDED             = 1;
var COLLAPSED            = 2;
var EXPAND_LIMIT         = 10;
var COLLAPSE_IMAGE       = 'collapse.gif';
var POST_TEMPLATE_DIV    = 'post_template_div';
var POST_TEMPLATE_NAME   = 'PostTemplate.jsp';
var LOAD_THREAD_EVENT    = 'loadthread';
var LOAD_POST_EVENT      = 'loadpost';
var DEFAULT_LAYOUT       = 'FLAT';
var DEFAULT_ROOT         = 'item';
var TEMPLATE_MIXED       = 'MixedTemplate.jsp';
var TEMPLATE_TEXTONLY    = 'TextTemplate.jsp';
var TEMPLATE_PODCAST     = 'PodcastTemplate.jsp';

var ATOM                 = 'ATOM';
var RSS                  = 'RSS';
var RDF                  = 'RDF';
var PODCAST              = 'PODCAST';

var ATOM_03_NS           = 'http://purl.org/atom/ns#';
var ATOM_10_NS           = 'http://www.w3.org/2005/atom';
var RDF_RSS_10_NS        = 'http://purl.org/rss/1.0/'
var PODCAST_NS           = 'http://www.itunes.com/dtds/podcast-1.0.dtd';

var FIELD_MAPPING        = 1;
var ATTRIBUTE_MAPPING    = 2;
var PROPERTY_MAPPING     = 3;
var DELETED_ENTRY        = "[[D]]"
//var PORTLET_NAMESPACE    = '';

// dojo requirements
//dojo.require("dojo.i18n.common");
dojo.require("dojo.lang.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.html.display");
dojo.require("dojo.date.serialize");

// Objects

// Thread Object
dojo.declare("Thread", null, {
    initializer: function(config) {
		dojo.debug("Thread: Initializer called with: " + dojo.debugShallow(config));

		// Add defaults to the configuration object
		config.contextURL 	    = config.contextURL ? config.contextURL 			 : '';
        config.layout 		    = config.layout ? config.layout 					 : DEFAULT_LAYOUT;

        // Configuration thread object
        this.portletNS = config.portletNS;
        this.contextURL = config.contextURL ? config.contextURL : ' ';
        this.feedURL = config.feedURL;
        this.targetURL = config.targetURL;
        this.authorVisible = config.authorVisible;
        this.dateVisible = config.dateVisible;
        this.interval = config.interval;
        this.containerId = config.portletNS + config.containerId;
        this.layout = config.layout;
		this.textOnly = config.textOnly;
		this.credentials = config.credentials;

        // For pagination
        this.previousInterval = this.interval; // needed to track interval changes
        this.from = 0;
        this.till = this.from + this.interval;
        this.pagination = "init";

        this.id = RoninUtils.generateThreadUID(25);
        this.postTemplateDivName = ""; //POST_TEMPLATE_DIV + "_" + config.postTemplate; //TODO: These ids need work. The idea is not to load same template many times.

        this.config      = config;

        // Offscreen rendering
        this.threadState = EXPANDED;
        this.threadRoot   = null;

        // Array of posts
        this.postArray = new Array();
        this.nextUniquePostId = 0;
        this.postIdLookup = new Array();

        // Field mapping for posts
        this.fieldRoot    = DEFAULT_ROOT;
        this.fieldMapping = null;

        // Load status
        this.dataLoaded           = false;
        this.postTemplateLoaded   = false;

        // Event handlers
        this.events = new Array();
        this.addEvent(LOAD_THREAD_EVENT);
        this.addEvent(LOAD_POST_EVENT);

        // Tie object to DOM
        this.container = document.getElementById(this.containerId);
        if (this.container) {
            this.container.threadObj = this;
        }

    },

    // Register an event.
    addEvent : function(eventName) {
    	dojo.debug("addEvent: " + eventName);

        this.events[eventName.toLowerCase()] = new Array();
    },

    // Register an event handler.
    addListener : function(eventName, callbackFunc) {
    	dojo.debug("addListener: " + eventName, callbackFunc);

        var name = eventName.toLowerCase();
        var eventListeners = this.events[name];
        if (eventListeners != null) {
            eventListeners.push(callbackFunc);
        }
    },

    // Unegister an event handler.
    removeListener : function(eventName, callbackFunc) {
    	dojo.debug("removeListener: " + eventName, callbackFunc);

        var name = eventName.toLowerCase();
        var eventListeners = this.events[name];
        if (eventListeners != null) {
            for (var ii =0; ii < eventListeners.length; ii++) {
                var listener = eventListeners[ii];
                if (listener == callbackFunc) {
                    eventListeners.splice(ii, 1);
                }
            }
        }
    },

    // Trigger an event.
    triggerEvent : function(eventName, modelObj, element) {
    	dojo.debug("triggerEvent: " + eventName, dojo.debugShallow(modelObj), dojo.debugShallow(element));

        var name = eventName.toLowerCase();
        var eventListeners = this.events[name];
        if (eventListeners != null) {
            for (var ii =0; ii < eventListeners.length; ii++) {
                var listener = eventListeners[ii];
                listener(name, modelObj, element);
            }
        }
    },

    // Clear the current thread.
    clearThread : function() {
    	dojo.debug("clearThread. ");

        this.container.innerHTML= "";
    },

    // Load Thread data.
    loadThread : function() {
    	dojo.debug("loadThread. ");

		if (!this.isDataLoaded())
		{
			var normUrl = RoninUtils.rewriteURL(this.targetURL, this.config.contextURL + this.config.proxyPrefixURL, this.config.credentials);

			dojo.debug("loadThread: Issuing AJAX request " + normUrl);

			var callbackFunction = dojo.lang.hitch(this, this.parseThreadXMLResponse);
			var handleError = dojo.lang.hitch(this, "handleError");

			if ( dojo.render.html.ie )
			{
				dojo.io.bind({	url: normUrl,
	    					load: function(type, data, evt){ var doc = dojo.dom.createDocumentFromText( data ); callbackFunction(doc); },
	    					error: function(type, errObj){ handleError(type, errObj); },
	    					mimetype: "text/plain"}); // IE fix
			}
			else
			{
				dojo.io.bind({	url: normUrl,
	    					load: function(type, data, evt){ callbackFunction(data); },
	    					error: function(type, errObj){ handleError(type, errObj); },
	    					mimetype: "text/xml"});
			}
		}
    },

    // Parse Thread XML data and display the thread.
    parseThreadXMLResponse : function(originalRequest) {
    	dojo.debug("parseThreadXMLResponse ", dojo.debugShallow(originalRequest));

		// save the retrieved content
		this.xmlData = originalRequest;

		this.getFeedType();

		// Set entry root
		if (this.feedType.getType() == ATOM)
		{
			this.fieldRoot = "entry";
		}
		if (this.feedType.getType() == RSS)
		{
			this.fieldRoot = "item";
		}
		if (this.feedType.getType() == PODCAST)
		{
			this.fieldRoot = "item";
		}

		// Manual namespacing if using IE
		// We should not do that for Podcasts title/enclosure and pubdate
		if ( (dojo.render.html.ie) && (this.feedType.getBaseNS() != "") && (this.feedType.getType() != PODCAST) )
		{
			this.fieldRoot = this.feedType.getBaseNS() + ":" + this.fieldRoot;
		}

		this.loadTemplate();

        // Parse thread
  		this.parseThreadXML();

        // Do notload the data twice
        this.dataLoaded = true;

        // Update the next id counter given out to new posts
        nextUniquePostId = this.postArray.length;

        // Display the thread
        this.displayThread();
    },

    // Parse Thread XML data.
    parseThreadXML : function() {
    	dojo.debug("parseThreadXML ", dojo.debugShallow());

        var postNum;

		dom = this.xmlData;

        // Support for relative URLs
        var baseRequest = this.feedURL;

        // Loop through entries
        var entries = dom.getElementsByTagName(this.fieldRoot);
        for (var ii=0; ii < entries.length; ii++) {

            // Initialize Id
            postNum = this.uniqueId();

            // Load post
            this.postArray[postNum] = new Post(this, postNum, entries[ii], baseRequest);
        }
    },

    // To reverse pagination
    paginationDirection: function(direction)
    {
        this.pagination = direction;
    },

    // To manipulate the pagination interval
    paginationInterval: function(interval)
    {
        this.previousInterval = this.interval;
        this.interval = interval;
    },

    getNumberOfPosts: function()
    {
        return this.postArray.length;
    },

    getNumberOfPreviousPosts: function()
    {
        return this.from;
    },

    getNumberOfNextPosts: function()
    {
        var x = this.getNumberOfPosts() - this.till;
        return this.getNumberOfPosts() - this.till;
    },

    paginationState: function()
    {
  		var numberOfPosts = this.getNumberOfPosts();
		var numberOfPreviousPosts = this.getNumberOfPreviousPosts();
		var numberOfNextPosts = this.getNumberOfNextPosts();

        // Disable
		if (numberOfNextPosts == 0)
		{
            var element = document.getElementById(this.portletNS + "paginateNext");
            var element_inactive = document.getElementById(this.portletNS + "paginateNext_inactive");
            dojo.html.setDisplay(element, false);
            dojo.html.setDisplay(element_inactive, true);
		}

		if (numberOfPreviousPosts == 0)
		{
            var element = document.getElementById(this.portletNS + "paginatePrevious");
            var element_inactive = document.getElementById(this.portletNS + "paginatePrevious_inactive");
            dojo.html.setDisplay(element, false);
            dojo.html.setDisplay(element_inactive, true);
		}

        // Enable
		if (numberOfNextPosts > 0)
		{
            var element = document.getElementById(this.portletNS + "paginateNext");
            var element_inactive = document.getElementById(this.portletNS + "paginateNext_inactive");
            dojo.html.setDisplay(element, true);
            dojo.html.setDisplay(element_inactive, false);
		}

		if (numberOfPreviousPosts > 0)
		{
            var element = document.getElementById(this.portletNS + "paginatePrevious");
            var element_inactive = document.getElementById(this.portletNS + "paginatePrevious_inactive");
            dojo.html.setDisplay(element, true);
            dojo.html.setDisplay(element_inactive, false);
		}
    },

    // Display the thread
    displayThread : function() {
    	dojo.debug("displayThread. ");

        if (this.isDataLoaded()) {
            var ul_el = document.createElement('ul');
            this.threadRoot  = ul_el;

            if (this.postArray.length > EXPAND_LIMIT) {
                this.threadState = COLLAPSED;
            }

            // For pagination
            if (this.pagination == "forward")
            {
                this.previousTill = this.till;
                this.from = this.from + this.interval;
                this.till = this.till + this.interval;
                if ( this.till > this.postArray.length)
                {
                    this.till = this.postArray.length;
                    this.from = this.previousTill; // display rest
                }
            }

            if (this.pagination == "backward")
            {
               this.descrepancy = this.interval - ( this.till - this.from ); // if we changed the interval because we reached the end

               this.from = this.from - this.interval
               this.till = this.till - this.interval + this.descrepancy;

               if ( this.from < 0)
                {
                    this.from = 0;
                    this.till = this.from + this.interval; // display rest
                }
            }

            if (this.pagination == "update")
            {
                this.intervalDifference = this.interval - this.previousInterval;

                if (this.intervalDifference > 0)
                {
                    this.till = this.till + this.intervalDifference;
                    if ( this.till > this.postArray.length)
                    {
                        this.till = this.postArray.length;
                        this.interval = this.till - this.from; // adapt to max. possible interval size
                    }
                }

                if (this.intervalDifference < 0)
                {
                    this.till = this.till + this.intervalDifference; // yes, the "+" is correct here
                }
            }

            if (this.pagination == "init")
            {
                if ( this.till > this.postArray.length)
                {
                    this.till = this.postArray.length;
                }
            }

            for (var ii=this.from; ii<this.till; ii++) {
                var post = this.postArray[ii];
                post.insertPost(this.threadRoot);
                if (this.threadState == EXPANDED) {
                    post.expandPost();
                }
            }

            // Event called when thread loaded.
            this.triggerEvent(LOAD_THREAD_EVENT, this, this.threadRoot);

            // Add thread to the DOM
            this.clearThread();
            this.container.appendChild(this.threadRoot);

            this.paginationState();
        }
    },

    // Load templates
    loadTemplate : function() {
    	dojo.debug("loadTemplate");

		var templateName = "";

		if (this.feedType.getType() == PODCAST)
		{
			templateName = TEMPLATE_PODCAST;
		}
		else
		{
			templateName = this.feedType.getType().toUpperCase();
			templateName += this.textOnly?TEMPLATE_TEXTONLY:TEMPLATE_MIXED;
		}

        // Construct Template URL
        var templateUrl = this.contextURL + TEMPLATE_DIR + templateName;

		this.postTemplateDivName=POST_TEMPLATE_DIV + "_" + templateName;

		var templateDiv = document.getElementById(this.postTemplateDivName);

		if (templateDiv != null) {
			dojo.debug("no need for reloading template " + this.templateName);
	        this.fieldMapping = this.findFieldMapping(templateDiv);
			return;
		}

        // Download template from server
    	dojo.debug("loadTemplate: Issuing AJAX request: " + templateUrl);

		var callbackfcn = dojo.lang.hitch(this, "insertPostTemplate");
        var handleError = dojo.lang.hitch(this, "handleError");
    	dojo.io.bind({	url: templateUrl,
						sync: true,
    					load: function(type, data, evt){ callbackfcn(data); },
    					error: function(type, errObj){ handleError(type, errObj); },
    					mimetype: "text/plain"});
    },

    // Create the template div in the DOM tree to be peer to the thread container
    addTemplateToDOM : function(templateId) {
    	dojo.debug("addTemplateToDOM: " + templateId);

    	var container = document.getElementById(this.containerId);
       	var new_template_div = document.createElement("div");
       	new_template_div.id = templateId;

		// AN: deleted
       	//new_template_div.className = "hide";

        container.parentNode.appendChild(new_template_div);
       	return new_template_div;
    },

    // Insert the Post template into the DOM
    insertPostTemplate : function(originalRequest) {
    	dojo.debug("insertPostTemplate: " + originalRequest); // shallow screws up debug console

    	var templateDiv = document.getElementById(this.postTemplateDivName);
    	if (templateDiv == null) {
    	    templateDiv = this.addTemplateToDOM(this.postTemplateDivName);
        }

        // AN: deleted .responseText
        templateDiv.innerHTML = originalRequest;

    	this.postTemplateLoaded = true;
        // Map the template fields to the feed fields
        this.fieldMapping = this.findFieldMapping(templateDiv);
        //this.fieldRoot    = this.findRootMapping(this.fieldMapping);

        // Continue loading the thread
        //this.loadThread();
    },

    // Map the template fields to the feed fields
    findFieldMapping : function(parentNode) {
    	dojo.debug("findFieldMapping: " + dojo.debugShallow(parentNode));

        var binding = null;
        var retval = new Array();
        var childTags = parentNode.getElementsByTagName('*');
        var jj=0;
        for (var ii=0; ii<childTags.length; ii++) {
            var child = childTags[ii];

            // Bind fields
            binding = child.getAttribute("bindField");
            if (binding != null) {
                templateId = child.getAttribute("id");
                if (templateId != null) {
                    //alert ("Field found, id: "+templateId+" binding: "+binding);
                    retval[jj] = new FeedMapping(FIELD_MAPPING, templateId, binding, "");
                    jj++;
                }
            }

            // Bind attributes
            binding = child.getAttribute("bindAttribute");
            if (binding != null) {
                templateId = child.getAttribute("id");
                var idx = binding.indexOf(':')
                if (templateId != null && idx != -1) {
                    var attrName = binding.substring(0, idx);
                    binding = binding.substring(idx+1);
                    //alert ("Attribute found, id: "+templateId+" Attribute Name: "+attrName+" binding: "+binding);
                    retval[jj] = new FeedMapping(ATTRIBUTE_MAPPING, templateId, binding, attrName);
                    jj++;
                }
            }

            // Bind properties
            binding = child.getAttribute("bindProperty");
            if (binding != null) {
                binding = binding.toLowerCase();
                templateId = child.getAttribute("id");
                if (templateId != null) {
                    //alert ("Property found, id: "+templateId+" binding: "+binding);
                    retval[jj] = new FeedMapping(PROPERTY_MAPPING, templateId, binding, "");
                    jj++;
                }
            }
        }
        return retval;
    },

    // Find the root of all entries.
    findRootMapping : function(fieldMap) {
    	dojo.debug("findRootMapping: " + dojo.debugShallow(fieldMap));

        var retval = DEFAULT_ROOT;
        if (fieldMap != null && fieldMap.length > 0) {
            var fieldEntry = fieldMap[0];
            var fieldNames = fieldEntry.path.split("/");
            retval = fieldNames[0];
            if (fieldNames[0].length == 0) {
                retval = fieldNames[1];
            }
        }
        return retval;
    },

    // Return the Container.
    getContainer : function() {
    	dojo.debug("getContainer: " + dojo.debugShallow(this.container));
        return this.container;
    },

    // Return the Post Array
    getPostArray : function() {
    	dojo.debug("getPostArray: " + dojo.debugShallow(this.postArray));
        return this.postArray;
    },

    // Return the Post Count
    getPostCount : function() {
    	dojo.debug("getPostCount. ");

        retval = 0;
        if (this.postArray != null) {
            retval = this.postArray.length;
        }
        return retval;
    },

    // Return the Thread state.
    getThreadState : function() {
    	dojo.debug("getThreadState: " + this.threadState);
        return this.threadState;
    },

    // Return the Post by index
    getPost : function(index) {
    	dojo.debug("getPost: " + index);

        var retval = null
        if (index >= 0 && index < this.postArray.length) {
            retval = this.postArray[index];
        }
        return retval;
    },

    // Return true if data already loaded,
    isDataLoaded : function() {
    	dojo.debug("isDataLoaded: " + this.dataLoaded);
        return this.dataLoaded;
    },

    // Return true if Post Template already loaded,
    isPostTemplateLoaded : function() {
    	dojo.debug("isPostTemplateLoaded: " + this.postTemplateLoaded);
        return this.postTemplateLoaded;
    },

    // Return true if Reply Template already loaded,
    isReplyTemplateLoaded : function() {
    	dojo.debug("isReplyTemplateLoaded: " + this.replyTemplateLoaded);
        return this.replyTemplateLoaded;
    },

    // Set the Post by index
    setPost : function(index, post) {
    	dojo.debug("setPost: " + index, dojo.debugShallow(post));

        if (index >= 0 && index < this.postArray.length) {
            this.postArray[index] = post;
        }
    },

    // Expand all Posts.
    expandAllPosts : function () {
    	dojo.debug("expandAllPosts. ");

        for (var ii=0; ii<this.postArray.length; ii++) {
            var post = this.postArray[ii];
            post.expandPost()
        }
        this.threadState = EXPANDED;
    },

    // Collapse all Posts.
    collapseAllPosts : function () {
    	dojo.debug("collapseAllPosts. ");

        for (var ii=0; ii<this.postArray.length; ii++) {
            var post = this.postArray[ii];
            post.collapsePost()
        }
        this.threadState = COLLAPSED;
    },

    // Return the next unique Id for numbering posts.
    uniqueId : function () {
    	dojo.debug("uniqueId (current): " + this.nextUniquePostId);
        return this.nextUniquePostId++;
    },

  // AN: Additional functions
  getFeedType : function() {
    dojo.debug("getFeedType. ");

	var doc = this.xmlData;
	var type = null;
	var version = null;
	var baseNS = null;

	// Is it RSS or Podcast?
	// Manual namespacing for IE
	if ( dojo.render.html.ie )
	{
		// Is it a Podcast?
		var podcastNode = dojo.dom.getFirstChildElement(doc);
		var podcastNodeAttributes = podcastNode.attributes;
		if (podcastNodeAttributes != null)
		{
  			var attributeLength = podcastNodeAttributes.length;

      		for (var i=0; i<attributeLength; i++)
      		{
        		if (podcastNodeAttributes[i].value.toLowerCase() == PODCAST_NS)
        		{
          			// cut of xmlns:
          			baseNS = podcastNodeAttributes[i].name.substring(6, podcastNodeAttributes[i].name.length);

          			type = PODCAST;
					version = podcastNode.getAttribute("version");
				}
      		}
		}

		// Is it RSS (no namespacing assumed)?
		if (type == null)
		{
			var rssNode = doc.getElementsByTagName("rss")[0];
			if (rssNode != null)
			{
			   version = rssNode.getAttribute("version");
			   type = RSS;
			}
		}
	}
	else
	{
		var rssNode = doc.getElementsByTagName("rss")[0];
		if (rssNode != null)
		{
		   // Is it a Podcast?
		   var podcastNode = rssNode.getAttribute("xmlns:itunes");
		   if (podcastNode != null)
		   {
				type = PODCAST;
				version = rssNode.getAttribute("version");
		   }
		   else
		   {
			   // Is it RSS?
			   version = rssNode.getAttribute("version");
			   type = RSS;
		   }
		}
	}

	if (type == null)
	{
		// Is it RDF (RSS 1.0)?
		if ( dojo.render.html.ie )
		{
			var rdfNode = dojo.dom.getFirstChildElement(doc);

			// Determine baseNS in case of RDF (RSS 1.0)
			var rdfNodeAttributes = rdfNode.attributes;
			if (rdfNodeAttributes != null)
			{
	  			var attributeLength = rdfNodeAttributes.length;

	      		for (var i=0; i<attributeLength; i++)
	      		{
	        		if (rdfNodeAttributes[i].value.toLowerCase() == RDF_RSS_10_NS)
	        		{
	          			// cut of xmlns:
	          			baseNS = rdfNodeAttributes[i].name.substring(6, rdfNodeAttributes[i].name.length);

	          			type = RSS;
						version = "1.0";
					}
	      		}
			}

		}
		else
		{
			var rdfNode = doc.getElementsByTagName("RDF")[0];
			if (rdfNode != null)
			{
				type = RSS; // almost same syntax
				version = "1.0";
			}
		}
	}

	if (type == null)
	{
		// Is it ATOM?
		// Manual namespacing for IE
		if ( dojo.render.html.ie )
		{
			var atomNode = dojo.dom.getFirstChildElement(doc);

			// Determine baseNS in case of ATOM 0.3 or 1.0
			var atomNodeAttributes = atomNode.attributes;
			if (atomNodeAttributes != null)
			{
	  			var attributeLength = atomNodeAttributes.length;

	      		for (var i=0; i<attributeLength; i++)
	      		{
	        		if ( (atomNodeAttributes[i].value.toLowerCase() == ATOM_03_NS) || (atomNodeAttributes[i].value.toLowerCase() == ATOM_10_NS))
	        		{
	          			// cut of xmlns:
	          			baseNS = atomNodeAttributes[i].name.substring(6, atomNodeAttributes[i].name.length);

	          			type = ATOM;
						version = atomNode.getAttribute("version");
					}
	      		}
			}

		}
		else
		{
			var atomNode = doc.getElementsByTagName("feed")[0];
			if (atomNode != null)
			{
				type = ATOM;
				version = atomNode.getAttribute("version");
			}
		}
	}

	if (baseNS == null)
		baseNS = "";

  	this.feedType = new FeedType(type, version, baseNS);
  },

  handleError : function(type, errObj)
  {
	var element = document.getElementById(this.portletNS + "errorConsole");
	element.innerHTML = "Error: " + dojo.errorToString(errObj) + "<BR>";
  }

}); // end of class


dojo.declare("FeedType", null, {
	initializer: function(type, version, baseNS) {
	  dojo.debug("FeedType: Initializer called with: " + type, version, baseNS);

	  this.type = type;
	  this.version = version;
  	  this.baseNS = baseNS;
	},

	getType : function()
	{
	  return this.type;
	},

	getVersion : function()
	{
	  return this.version;
	},

	getBaseNS : function()
	{
	  return this.baseNS;
	}
});

// Post Object
dojo.declare("Post", null, {
    initializer: function(thread, postNum, entry, baseRequest) {
		dojo.debug("Post: Initializer called with: " + dojo.debugShallow(thread), postNum, entry, baseRequest);

        this.thread = thread;
        this.postNum = postNum;
        this.postId = thread.id+'_post_'+postNum;
        this.guid = null;
        this.parentId = null;
        this.subject = null;
        this.author = null;
        this.author_mail = null;
        this.creator = null;
        this.creator_mail = null;
        this.published = null;
        this.published_updated = null;
        this.published_modified = null;
        this.date = null;
        this.duration = null;
        this.updated = null;
        this.summary = null;
        this.subtitle = null;
        this.bodyUrl = null;
        this.body = null;
        this.body_summary = null;
        this.extData = null;
        this.expanded = false;
        this.container = null;
        this.owner = false;
        this.edit = null;
        this.editEnabled = false;
        this.edited = false;
        this.del = null;
        this.deleteEnabled = false;
        this.deleted = false;

        var xlateId     = null;
        var permissions = "";

        var feedType = this.thread.feedType;

        // Loop through the field table
        for (var ii=1; ii<this.thread.fieldMapping.length; ii++)
        {
            var fieldEntry = this.thread.fieldMapping[ii];
            var fieldValue = findFeedFieldValue(entry, fieldEntry.path, baseRequest, feedType);

            switch (fieldEntry.elemId) {
                case 'post_subject':
                    this.subject = fieldValue;
                    break;

                case 'post_creatpr':
                    this.creator = fieldValue;
                    break;

                case 'post_creator_mail':
                    this.creator_mail = fieldValue;
                    break;

                case 'post_author':
                    this.author = fieldValue;
                    break;

                case 'post_author_mail':
                    this.author_mail = fieldValue;
                    break;

                case 'post_published':
                    this.published = this.convertDate(fieldValue);
                    break;

                case 'post_published_updated':
                    this.published_updated = this.convertDate(fieldValue);
                    break;

                case 'post_published_modified':
                    this.published_modified = this.convertDate(fieldValue);
                    break;

                case 'post_date':
                    this.date = this.convertDate(fieldValue);
                    break;

                case 'post_duration':
                    this.duration = fieldValue;
                    break;

                case 'post_summary':
                    this.summary = fieldValue;
                    break;

                case 'post_subtitle':
                    this.subtitle = fieldValue;
                    break;

                case 'post_body_url':
                    this.bodyUrl = fieldValue;
                    break;

                case 'post_body_text':
                    this.body = fieldValue;
                    break;

                case 'post_body_text_summary':
                    this.body_summary = fieldValue;
                    break;

                default:
                    if (this.extData == null) {
                        this.extData = new Array();
                    }
                    this.extData[this.extData.length]=new ExtendedData(fieldEntry.type, fieldEntry.elemId, fieldEntry.attrName, fieldValue);
                    break;
            }
        }

        // Get guid and save it in lookup table
        this.guid = findFeedFieldValue(entry, "entry/id", "", feedType);
        if (this.guid != null) {
            var idx = this.guid.lastIndexOf(':');
            if (idx > -1) {
                this.guid = this.guid.substring(idx+1);
            }
        }
        if (this.layout == 'INDENTED')
        {
            if (this.guid != null && this.guid.length != 0) {
                this.thread.postIdLookup[this.guid] = Id;
            }

            var feedParentId =  getElementsByTagNameNS( entry,'http://purl.org/syndication/thread/1.0','thr','in-reply-to');
            if (feedParentId != null && feedParentId.length != 0) {
                this.parentId = feedParentId[0].getAttribute('idref');
                xlateId = this.thread.postIdLookup[parentId];
                if (xlateId != "undefined") {
                    this.parentId = xlateId;
                }
            }
        }

        // Set the deleted flag
        if (this.body != null && this.body.indexOf(DELETED_ENTRY)==0) {
            this.setDeleted(true);
            var idx = DELETED_ENTRY.length;
            this.body = this.body.substring(idx);
            this.summary = this.summary.substring(idx);
        }
        else {
            // Set the permissions on the entry
            permissions = findFeedFieldValue(entry, "entry/td:permissions", "", feedType);
            if (permissions.length ==0) {
                permissions = findFeedFieldValue(entry, "entry/permissions", "", feedType);
            }
            this.setPermissions(permissions);

            // Set the edited flag
            this.updated = findFeedFieldValue(entry, "entry/updated", "", feedType);
            var publ = findFeedFieldValue(entry, "entry/published", "", feedType);
            if (this.updated.length >0 && publ.length >0 ) {
                this.setEdited(this.updated != publ);
            }
        }
    },

    // Enable / Disable Edit and Delete.
    setPermissions : function(permissions) {
    	dojo.debug("setPermissions: " + dojo.debugShallow(permissions));

        if (permissions != null) {
            if (permissions.indexOf('edit') != -1) {
                this.editEnabled = true;
            }
            if (permissions.indexOf('delete_soft') != -1) {
                this.deleteEnabled = true;
            }
        }
    },

    // Get Owner flag.
    getOwner : function() {
    	dojo.debug("getOwner: " + this.owner);
        return this.owner;
    },

    // Set Owner flag.
    setOwner : function(owner) {
    	dojo.debug("setOwner: " + owner);
        this.owner = owner;
    },

    // Get Edited flag.
    getEdited : function() {
    	dojo.debug("getEdited: " + this.edited);
        return this.edited;
    },

    // Set Edited flag.
    setEdited : function(edited) {
    	dojo.debug("setEdited: " + edited);
        this.edited = edited;
    },

    // Display edited section.
    displayEditHistory : function() {
    	dojo.debug("displayEditHistory. ");

        if (this.container != null) {
            var editHist = getElementById(this.container, 'post_edit_history_'+this.postId);

            // OR: only continue if element exists
            if (editHist == null)
              return;

            if (this.edited == true) {
                // AN: change to dojo stlye
                dojo.html.style.show(editHist);
            }
            else {
                // AN: change to dojo stlye
                dojo.html.hide(editHist);
            }
        }
    },

    // Get Deleted flag.
    getDeleted : function() {
    	dojo.debug("getDeleted: " + this.deleted);
        return this.deleted;
    },

    // Set Deleted flag.
    setDeleted : function(deleted) {
    	dojo.debug("setDeleted: " + deleted);
        this.deleted = deleted;
    },

    // Display deleted section.
    displayDeleteHistory : function() {
    	dojo.debug("displayDeleteHistory. ");

        if (this.container != null) {
            var deleteHist = getElementById(this.container, 'post_delete_history_'+this.postId);

            // OR: only continue if element exists
            if (deleteHist == null)
              return;

            if (this.deleted == true) {
                // AN: change to dojo stlye
                dojo.html.style.show(deleteHist);
            }
            else {
                // AN: change to dojo stlye
                dojo.html.hide(deleteHist);
            }
        }
    },

    // Insert Post in DOM.
    insertPost : function(threadRoot) {
    	dojo.debug("insertPost: " + dojo.debugShallow(threadRoot));

        if (this.thread.layout == 'INDENTED') {
            this.insertPostIndented(threadRoot);
        }
        else if (this.thread.layout == 'FLAT') {
            this.insertPostFlat(threadRoot);
        }

        // Handle updates
        this.displayDeleteHistory();
        this.displayEditHistory();
    },

    // Insert Post in hierarchy.
    insertPostIndented : function(listContainer) {
    	dojo.debug("insertPostIndented: " + dojo.debugShallow(listContainer));

        // If the parent exists, insert the post as a child of it in the tree
        if ((this.parentId != null) && (getElementById(listContainer,this.parentId) != null)) {
            var parentPostDiv = getElementById(listContainer, this.parentId);
            // Does the parent already have children?
            if (parentPostDiv.parentNode.childNodes.length > 1) {
                var childListUL = parentPostDiv.parentNode.childNodes[1];
                this.insertPostFlat(childListUL);
            }
            else {
                var ul_el = document.createElement("ul");
                this.insertPostFlat(ul_el);
                parentPostDiv.parentNode.appendChild(ul_el);
            }
        }
        else { //if the parent does not exist, first create a list in the postListDiv if it doesn't exist (it should)
            if (listContainer == null) {
                listContainer = document.createElement("ul");
                document.getElementById(this.thread.container).appendChild(listContainer);
            }
            this.insertPostFlat(listContainer);
        }
    },

    // Determine insertion point.
    findInsertPositionByPublished : function(siblings) {
    	dojo.debug("findInsertPositionByPublished: " + dojo.debugShallow(siblings));

        var beforePost = null;
        if (siblings.length == 0)
            return null;
        var i = siblings.length-1;
        while ((i >= 0) && (getPostNodePublished(siblings[i].childNodes[0]).valueOf() > (new Date(Date.parse(this.published))).valueOf())) {
            beforePost = siblings[i];
            i--;
        }
        return beforePost;
    },

    // Insert Post in flat list.
    insertPostFlat : function(listContainer) {
    	dojo.debug("insertPostFlat: " + dojo.debugShallow(listContainer));

        var siblings = listContainer.childNodes;
        var li_el = document.createElement("li");
        if (this.thread.layout == 'FLAT') {
            li_el.className = "li_flat";
        }
        else {
            li_el.className = "li_indented";
        }
        var postDiv = this.clonePostTemplate();
        if (postDiv != null) {
            postDiv.postObj = this;
            this.container = postDiv;
            li_el.appendChild(postDiv);

            if (siblings.length == 0)
                listContainer.appendChild(li_el);
            else
            {
            	// AN: We don't want to do any sorting here
            	var beforePostLI = null;
                // var beforePostLI = this.findInsertPositionByPublished(siblings);

                //insert the postDiv. if no before position exists, append to end of the list
                if (beforePostLI == null)
                    listContainer.appendChild(li_el);
                else
                    listContainer.insertBefore(li_el, beforePostLI);
            }
            // Event called when Post loaded.
            this.thread.triggerEvent(LOAD_POST_EVENT, postDiv.postObj, postDiv);
        }
    },

    // Clone the Post template.
    clonePostTemplate : function() {
    	dojo.debug("clonePostTemplate. ");

    	// AN: Fix namespacing
        //var template = document.getElementById('post_template');

		var templateDiv = document.getElementById(this.thread.postTemplateDivName);
    	if (templateDiv == null) {
    	    templateDiv = this.addTemplateToDOM(this.thread.postTemplateDivName);
        }

        var newPostDiv = templateDiv.cloneNode(true);
        var file = null;
        var idx = -1;

        // Set container ids.
        newPostDiv.id = this.postId;
        var head = getElementById(newPostDiv,"post_header");
        if (head != null) {
            head.id = head.id + "_" + this.postId;
        }
        var act = getElementById(newPostDiv,"post_actions");
        if (act != null) {
            act.id = act.id + "_" +this.postId;
        }
        var body = getElementById(newPostDiv,"post_body");
        if (body != null) {
            body.id = body.id + "_" +this.postId;
        }
        // Fill in field data.
        var subj = getElementById(newPostDiv, "post_subject");
        if (subj != null) {
            subj.innerHTML = this.subject;
            subj.id = subj.id + "_" +this.postId;
        }
        var auth = getElementById(newPostDiv, "post_author");
        if (auth != null) {
            auth.innerHTML = this.author;
            auth.id = auth.id + "_" +this.postId;

            if (this.thread.authorVisible != "true")
            {
                dojo.html.hide(auth);
            }
            else
            {
            	if (auth.innerHTML != "")
            	{
                	//auth.innerHTML = auth.innerHTML + "<br>";
                }
            }
        }
        var auth_mail = getElementById(newPostDiv, "post_author_mail");
        if (auth_mail != null) {
            auth_mail.innerHTML = this.author_mail;
            auth_mail.id = auth.id + "_" +this.postId;

            if (this.thread.authorVisible != "true")
            {
                dojo.html.hide(auth_mail);
            }
            else
            {
            	if (auth_mail.innerHTML != "")
            	{
                	//auth_mail.innerHTML = auth_mail.innerHTML + "<br>";
                }
            }
        }
        var creator = getElementById(newPostDiv, "post_creator");
        if (creator != null) {
            creator.innerHTML = this.creator;
            creator.id = creator.id + "_" +this.postId;

            if (this.thread.authorVisible != "true")
            {
                dojo.html.hide(creator);
            }
            else
            {
            	if (creator.innerHTML != "")
            	{
                	//creator.innerHTML = creator.innerHTML + "<br>";
                }
            }
        }
        var creator_mail = getElementById(newPostDiv, "post_creator_mail");
        if (creator_mail != null) {
            creator_mail.innerHTML = this.creator_mail;
            creator_mail.id = creator.id + "_" +this.postId;

            if (this.thread.authorVisible != "true")
            {
                dojo.html.hide(creator_mail);
            }
            else
            {
            	if (creator_mail.innerHTML != "")
            	{
                	//creator_mail.innerHTML = creator_mail.innerHTML + "<br>";
               }
            }
        }
        var publ = getElementById(newPostDiv, "post_published");
        if (publ != null) {
            publ.innerHTML = this.published;
            publ.id = publ.id + "_" +this.postId;

            if (this.thread.dateVisible != "true")
            {
                dojo.html.hide(publ);
            }
            else
            {
            	if (publ.innerHTML != "")
            	{
                	//publ.innerHTML = publ.innerHTML + "<br>";
               }
            }
        }
        var publ_modified = getElementById(newPostDiv, "post_published_modified");
        if (publ_modified != null) {
            publ_modified.innerHTML = this.published_modified;
            publ_modified.id = publ_modified.id + "_" +this.postId;

            if (this.thread.dateVisible != "true")
            {
                dojo.html.hide(publ_modified);
            }
            else
            {
            	if (publ_modified.innerHTML != "")
            	{
                  //publ_modified.innerHTML = publ_modified.innerHTML + "<br>";
               }
            }
        }
        var publ_updated = getElementById(newPostDiv, "post_published_updated");
        if (publ_updated != null) {
            publ_updated.innerHTML = this.published_updated;
            publ_updated.id = publ_updated.id + "_" +this.postId;

            if (this.thread.dateVisible != "true")
            {
                dojo.html.hide(publ_updated);
            }
            else
            {
            	if (publ_updated.innerHTML != "")
            	{
                	//publ_updated.innerHTML = publ_updated.innerHTML + "<br>";
               }
            }
        }
        var dat = getElementById(newPostDiv, "post_date");
        if (dat != null) {
            dat.innerHTML = this.date;
            dat.id = dat.id + "_" +this.postId;

            if (this.thread.dateVisible != "true")
            {
                dojo.html.hide(dat);
            }
            else
            {
            	if (dat.innerHTML != "")
            	{
                	//dat.innerHTML = dat.innerHTML + "<br>";
               }
            }
        }
        var dur = getElementById(newPostDiv, "post_duration");
        if (dur != null) {
            dur.innerHTML = this.duration;
            dur.id = dur.id + "_" +this.postId;

           	if (dur.innerHTML != "")
           	{
               //dur.innerHTML = dur.innerHTML + "<br>";
            }
        }
        var summ = getElementById(newPostDiv, "post_summary");
        if (summ != null) {
            summ.innerHTML = this.summary;
            summ.id = summ.id + "_" +this.postId;
        }
        var subt = getElementById(newPostDiv, "post_subtitle");
        if (subt != null) {
            subt.innerHTML = this.subtitle;
            subt.id = subt.id + "_" +this.postId;

           	if (subt.innerHTML != "")
           	{
               //subt.innerHTML = subt.innerHTML + "<br>";
            }
        }
        var bodyTxtSummary = getElementById(newPostDiv, "post_body_text_summary");
        if (bodyTxtSummary != null) {
            bodyTxtSummary.innerHTML = this.body_summary;
            bodyTxtSummary.id = bodyTxtSummary.id + "_" +this.postId;

           	if (bodyTxtSummary.innerHTML != "")
           	{
               //bodyTxtSummary.innerHTML = bodyTxtSummary.innerHTML + "<br>";
            }
        }
        var bodyTxt = getElementById(newPostDiv, "post_body_text");
        if (bodyTxt != null) {
            bodyTxt.innerHTML = this.body;
            bodyTxt.id = bodyTxt.id + "_" +this.postId;

           	if (bodyTxt.innerHTML != "")
           	{
               //bodyTxt.innerHTML = bodyTxt.innerHTML + "<br>";
            }
        }
        var bodyUrl = getElementById(newPostDiv, "post_body_url");
        if (bodyUrl != null) {
            bodyUrl.id = bodyUrl.id + "_" +this.postId;
        }
        var editHist = getElementById(newPostDiv, "post_edit_history");
        if (editHist != null) {
            editHist.id = editHist.id + "_" +this.postId;
        }
        var deleteHist = getElementById(newPostDiv, "post_delete_history");
        if (deleteHist != null) {
            deleteHist.id = deleteHist.id + "_" +this.postId;
        }

        // Fill in extended data.
        this.handleExtData(newPostDiv);

        // Add the listeners and new ids.
        var toggle = getElementById(newPostDiv, "post_toggle");
        if (toggle) {
        	// AN: change to dojo eventing
            dojo.event.connect(this.toggle, "onclick", this.togglePostBody);

            toggle.id = toggle.id + "_" +this.postId;
            toggle.src = this.thread.contextURL+IMAGES_DIR+EXPAND_IMAGE;
        }
        else if (head != null) {
        	// AN: change to dojo eventing
            dojo.event.connect(this.head, "onclick", this.togglePostBody);
        }

        var reply = getElementById(newPostDiv, "post_reply");
        if (reply) {
            reply.id = reply.id + "_" + this.postId;
            if (this.isReplyEnabled()) {
            	// AN: change to dojo eventing
                dojo.event.connect(reply, "onclick", this.replyPost);

                // AN: change to dojo stlye
                dojo.html.style.show(reply);
            }
            else {
                // AN: change to dojo stlye
                dojo.html.hide(reply);
            }
        }

        var edit = getElementById(newPostDiv, "post_edit");
        if (edit) {
            edit.id = edit.id + "_" +this.postId;
            if (this.isEditEnabled()) {
            	// AN: change to dojo eventing
                dojo.event.connect(edit, "onclick", this.editPost);

                // AN: change to dojo stlye
                dojo.html.style.show(edit);
            }
            else {
                // AN: change to dojo stlye
                dojo.html.hide(edit);
            }
        }

        var del = getElementById(newPostDiv, "post_delete");
        if (del) {
            del.id = del.id + "_" +this.postId;
            if (this.isDeleteEnabled()) {
            	// AN: change to dojo eventing
                dojo.event.connect(del, "onclick", this.deletePost);

                // AN: change to dojo stlye
                dojo.html.style.show(del);
            }
            else {
                // AN: change to dojo stlye
                dojo.html.hide(del);
            }
        }

        // Set style based on ownership
        if (this.getOwner() == true) {
            var number = getElementById(newPostDiv, "post_number_"+this.postId);
            if (number) {
                number.parentNode.className = "post_number_owner";
            }
        }
        return newPostDiv;
    },

    // Handle extended data (if any).
    handleExtData : function(postDiv) {
    	dojo.debug("handleExtData: " + dojo.debugShallow(postDiv));

        if (this.extData != null) {
            for (var ii =0; ii < this.extData.length; ii++) {
                var updated = false;
                var field = this.extData[ii];
                var elem = getElementById(postDiv, field.elemId);
                if (elem == null) {
                    elem = getElementById(postDiv, field.elemId+'_'+this.postId);
                    updated = true;
                }
                if (elem != null) {
                    if (field.type == FIELD_MAPPING ) {
                        elem.innerHTML = field.value;
                    }
                    else if (field.type == ATTRIBUTE_MAPPING) {
                        elem.setAttribute(field.attrName, field.value);
                    }
                    else if (field.type == PROPERTY_MAPPING) {
                        elem.innerHTML = this.postId;      //1+(this.postNum-0);
                    }
                    if (!updated) {
                        elem.id = elem.id+'_'+this.postId;
                    }
                }
            }
        }
    },

    // Toggle the body display
    togglePostBody : function () {
    	dojo.debug("togglePostBody.");

        // Collapse body
        if (this.expanded) {
            this.collapsePost();
        }
        // Expand body
        else {
            this.expandPost();
        }
        return;
    },

    // Expand the body.
    expandPost : function () {
    	dojo.debug("expandPost.");

        var summEl = getElementById(this.thread.threadRoot,'post_summary_'+this.postId);
        var bodyEl = getElementById(this.thread.threadRoot,'post_body_'+this.postId);

        //NEEDSWORK...
        if ((this.body == null || this.body.length ==0) && !this.deleted) {
            this.body = " ";
        }

        if ((this.body == null || this.body.length ==0) && !this.deleted) {
            this.loadPostBody();
        }
        else {
            if (bodyEl != null)
            {
                bodyEl.className ="post_body_show";
            }
        }
        if (summEl != null) {
            // AN: change to dojo stlye
            dojo.html.hide(summEl);
        }
        this.expanded = true;
    },

    // Load the Post body.
    loadPostBody : function() {
    	dojo.debug("loadPostBody.");

        var fullUrl = this.bodyUrl;
        var idIdx = this.bodyUrl.indexOf('byId');
        if (idIdx > -1 && idIdx < 2) {
            fullUrl = this.thread.contextURL+this.bodyUrl;
        }

       	dojo.debug("loadPostBody: Issuing AJAX request: " + fullUrl);

        var callbackFunction = dojo.lang.hitch(this, this.parseBodyXMLResponse);
        var handleError = dojo.lang.hitch(this, "handleError");
      	dojo.io.bind({	url: fullUrl,
       					load: function(type, data, evt){ callbackFunction(data); },
       					error: function(type, errObj){ handleError(type, errObj); },
       					mimetype: "text/plain"});
    },

    // Collapse the body.
    collapsePost : function() {
    	dojo.debug("collapsePost.");

        var summEl = getElementById(this.thread.threadRoot,'post_summary_'+this.postId);
        var bodyEl = getElementById(this.thread.threadRoot,'post_body_'+this.postId);
        if (bodyEl != null) {
            bodyEl.className = "post_body_hide";
        }
        if (summEl != null) {
            // AN: change to dojo stlye
            dojo.html.style.show(summEl);
        }
        this.expanded = false;
    },

    // Parse Post XML data and display the Post.
    parseBodyXMLResponse : function(originalRequest) {
    	dojo.debug("parseBodyXMLResponse: " + dojo.debugShallow(originalRequest));

        // AN: deleted .responseXML
        this.parseBodyXML(originalRequest.documentElement);
        var postDiv = document.getElementById(this.postId);
        getElementById(postDiv,'post_body_text_'+this.postId).innerHTML = this.body;
        getElementById(postDiv,'post_toggle_'+this.postId).src = this.thread.contextURL+IMAGES_DIR+COLLAPSE_IMAGE;
        getElementById(postDiv,'post_body_'+this.postId).className ="post_body_show";
    },

    // Parse Post body XML data.
    parseBodyXML : function(dom) {
    	dojo.debug("parseBodyXML: " + dojo.debugShallow(dom));

        var el_arr = dom.getElementsByTagName('entry');
        var body = el_arr[0].getElementsByTagName('body')[0].childNodes[0].nodeValue;
        this.body = body;
    },

    // Return the Container.
    getContainer : function() {
    	dojo.debug("getContainer: " + dojo.debugShallow(this.container));
        return this.container;
    },

    // Compare Posts by published.
    compareByTs : function(a, b) {
    	dojo.debug("compareByTs: " + a, b);
        return (new Date(Date.parse(a.published))).valueOf() - (new Date(Date.parse(b.published))).valueOf();
    },

	handleError : function(type, errObj)
	{
    	var element = document.getElementById(this.thread.portletNS + "errorConsole");
    	element.innerHTML = "Error: " + dojo.errorToString(errObj) + "<BR>";
  	},

  	convertDate : function(date)
  	{
  		var localeDate = null;

  		// this handles IETF RFC822 dates
  		var currentDate = new Date(date);
  		if (currentDate != null)
  		{
    		localeDate = currentDate.toLocaleString();
	  		if ( (localeDate != "Invalid Date") && (localeDate != "NaN") )
	  		{
	  			return localeDate;
	  		}
  		}

		// this handles RFC3339 dates
		currentDate = dojo.date.fromRfc3339(date);
		if (currentDate != null)
		{
	  		localeDate = currentDate.toLocaleString();
			return localeDate;
		}

		// if the date was given as neither IETF RFC822 nor as RFC3339 compliant date we do not convert anything
		// this can e.g. happen with RSS 0.91 feeds adhering to the Netscape spec
		return date;
  	}

}); // end of class

// Feed Mapping Object
dojo.declare("FeedMapping", null, {
    initializer: function(type, elemId, path, attrName) {
		dojo.debug("FeedMapping: Initializer called with: " + type, elemId, path, attrName);

        this.type = type;
        this.elemId = elemId;
        this.path = path;
        this.attrName = attrName;
    }
}); // end of class

// Extended Data
dojo.declare("ExtendedData", null, {
    initializer: function(type, elemId, attrName, value) {
		dojo.debug("ExtendedData: Initializer called with: " + type, elemId, attrName, value);

        this.type = type;
        this.elemId = elemId;
        this.attrName = attrName;
        this.value = value;
    }
}); // end of class

// AN: Additional functions
// Cross-browser event registration for IE5+, NS6 and Mozilla.
function addEvent(elm, evType, fn, useCapture) {
    var retval;

    if (elm.addEventListener) {
        elm.addEventListener(evType, fn, useCapture);
        retval = true;
    }
    else if (elm.attachEvent) {
        retval = elm.attachEvent('on' + evType, fn);
    }
    else {
        elm['on' + evType] = fn;
        retval = true;
    }
    return retval;
}

// Cross-browser event deregistration for IE5+, NS6 and Mozilla.
function removeEvent(elm, evType, fn, useCapture) {
    var retval;

    if (elm.removeEventListener) {
        elm.removeEventListener(evType, fn, useCapture);
        retval = true;
    }
    else if (elm.detachEvent) {
        retval = elm.detachEvent('on' + evType, fn);
    }
    else {
        elm['on' + evType] = null;
        retval = true;
    }
    return retval;
}

// Ajax callbacks
// Find desired node in the feed entry
function findFeedFieldValue(feedEntry, fieldPath, baseRequest, feedType)
{
    var retval = "";
    var attrName = null;
    var fieldNode = feedEntry;
    var idx = fieldPath.lastIndexOf('@');
    if (idx != -1) {
        attrName = fieldPath.substring(idx+1);
        fieldPath = fieldPath.substring(0, idx);
    }
    var fieldNames = fieldPath.split("/");
    var ii=1;
    if (fieldNames[0].length == 0) {
        ii=2;
    }

	var type = feedType.getType();
	var atomLink = "entry/link";

	// Support for relative URLs
    var baseURLStack = new Array();
	if (type == ATOM)
	{
		var baseURL = null;

		// The very first element is the request itself
	    baseURLStack.push(baseRequest);

	    // The second element is the xmlns of the document's root element
	    if ( (dojo.dom.isNode(fieldNode)) && (fieldNode.nodeType != dojo.dom.DOCUMENT_NODE ) )
		{
		    var rootNode = fieldNode.parentNode;
		    if ( (dojo.dom.isNode(rootNode)) && (rootNode.nodeType != dojo.dom.DOCUMENT_NODE ) )
			{
			    baseURL = rootNode.getAttribute("xml:base");
		       	if (baseURL != null)
		       	{
		       		baseURLStack.push(baseURL);
		       	}
		    }
	    }

	    // For the third element Check the entry element itself
		baseURL = fieldNode.getAttribute("xml:base");
       	if (baseURL != null)
       	{
       		baseURLStack.push(baseURL);
       	}
	}

    for (; ii<fieldNames.length && fieldNode; ii++)
    {
        if (fieldNames[ii].length > 0)
        {

			// Manual namespacing if using IE
			if ( (dojo.render.html.ie) && (feedType.getBaseNS() != "") )
		    {
		    	if (feedType.getType() != PODCAST)
		    	{
		    		fieldNames[ii] = feedType.getBaseNS() + ":" + fieldNames[ii];
		    	}
		    	else
		    	{
					// Some itunes elements should not be prefixed manually
					if ( (fieldPath != "item/title") && (fieldPath != "item/enclosure") && (fieldPath != "item/pubDate") )
					{
						fieldNames[ii] = feedType.getBaseNS() + ":" + fieldNames[ii];
					}
		    	}
		    }

            if (fieldNode != null)
            {
	            var children = fieldNode.childNodes;
	            if (children != null)
	            {
	            	var stop = false;
	            	for (var jj=0; jj<children.length && !stop; jj++)
	            	{
	            		var current = children[jj];

						// IE fix
	            		var currentName;
	            		if (dojo.render.html.ie)
	            		{
							currentName = current.tagName;
						}
						else
						{
							currentName = current.localName;
						}

	            		if (currentName == fieldNames[ii])
	            		{
	            			// ATOM
	            			if (type == ATOM)
	            			{
	            				// In the ATOM case, also check the NS
	            				// For IE we have done the NS checks manually
		            			if ( (dojo.render.html.ie) || (current.namespaceURI.toLowerCase() == ATOM_03_NS) || (current.namespaceURI.toLowerCase() == ATOM_10_NS) )
		            			{
			            			// Default
			            			fieldNode = current;

					            	// An ATOM feed can have more than one link element assigned
					            	// We always try to fetch the default one with attribute "alternate", or null (which is then the same as "alternate")
					            	if (fieldPath == "entry/link")
					            	{
			            				if ( (dojo.dom.isNode(fieldNode)) && (fieldNode.nodeType != dojo.dom.DOCUMENT_NODE ) )
			            				{
				            				var rel = current.getAttribute("rel");
				            				if (rel == null)
				            				{
				            					stop = true;
				            				}
				            				if (rel == "alternate")
				            				{
				            					stop = true;
				            				}
			            				}
					            	}
					            }
				            }
				            else
				            {
		            			// Default
		            			fieldNode = current;
				            }
	            		}
	            	}

       				// Support for relative URLs
       				if (type == ATOM)
       				{
						var baseURL = fieldNode.getAttribute("xml:base");
			           	if (baseURL != null)
			           	{
			           		baseURLStack.push(baseURL);
			           	}
	   				}

	            }
			}
        }
    }


    if (fieldNode != null)
    {
        if (attrName != null) {
            retval = fieldNode.getAttribute(attrName);
        }
        else
        {
            if (fieldNode.childNodes[0] != null)
            {
                retval = fieldNode.childNodes[0].nodeValue;
            }
        }
    }

    // Support for relative URLs
    // Only modify entry/link tags
	if (type == ATOM)
	{
	    if (fieldPath == "entry/link")
	    {
			// Only act if relative URLs have been defined
			if (baseURLStack.length > 1)
			{
				if (retval != null)
		      	{
		        	var baseURL = baseURLStack[0];
		        	for (var kk=1; kk<baseURLStack.length; kk++)
		        	{
		          		baseURL = Util.uri.join(baseURLStack[kk], baseURL);
		        	}

		        	retval = Util.uri.join(retval, baseURL);
					return retval;
		      	}
			}
	    }

		// 182113
		if (fieldPath == "entry/title")
		{
			if (retval == null || retval == "")
			{
				retval = "Link";
			}
		}
	}

	if (type == ATOM)
	{
		// 182113
		if (fieldPath == "item/title")
		{
			if (retval == null || retval == "")
			{
				retval = "Link";
			}
		}
	}

    return (retval == null ? "" : retval);
}

// Get the current Thread element
function getThreadElement(e)
{
    var found = false;
    var threadDiv = getEventElement(e);

    if (threadDiv) {
        while (threadDiv != document.body && !found) {
            threadDiv = threadDiv.parentNode;
            if (threadDiv.nodeName.toLowerCase() == 'div' && threadDiv.threadObj) {
                found = true;
            }
        }
    }
    return threadDiv;
}

// Get the current post element
function getPostElement(e)
{
    var found = false;
    var postDiv = getEventElement(e);

    if (postDiv) {
        while (postDiv != document.body && !found) {
            postDiv = postDiv.parentNode;
            if (postDiv.nodeName.toLowerCase() == 'div' && postDiv.postObj) {
                found = true;
            }
        }
    }
    return postDiv;
}

// Find Target Div
function find_target(e)
{
    var target = getEventElement(e);
    if (!target)
        return null;

    while (target != document.body && target.nodeName.toLowerCase() != 'div') {
        target = target.parentNode;
    }

    if (target.nodeName.toLowerCase() != 'div')
        return null;

    return target;
}

// Get the current Thread element
function getEventElement(e)
{
    var retval = null;
    if (window.event && window.event.srcElement) {
        retval = window.event.srcElement;
    }
    else if (e && e.target) {
        retval = e.target;
    }
    return retval;
}

// Find child element by id.
function getElementById(parentNode, tagId) {
    var retval = null;
    var childTags = parentNode.getElementsByTagName("*");
    for (var ii=0; ii<childTags.length; ii++) {
        if (childTags[ii].id == tagId) {
            retval = childTags[ii];
            break;
        }
    }
    return (retval)
}

// Find child element by class name
function getElementsByClassName(parentNode, className) {
    var retval = new Array();
    var childTags = parentNode.getElementsByTagName('*');

    for (var ii=0; ii<childTags.length; ii++) {
        var child = childTags[ii];
        var classNames = child.className.split(' ');
        for (var jj = 0; jj < classNames.length; jj++) {
            if (classNames[jj] == className) {
                retval.push(child);
                break;
            }
        }
    }
    return retval;
}

// Cross browser version of getElementsByTagNameNS.
function getElementsByTagNameNS(parentNode,ns,nsCode,tagName) {
    var retval;
    if (parentNode.getElementsByTagNameNS) {
        retval = parentNode.getElementsByTagNameNS(ns, tagName);
    }
    else {
        retval = parentNode.getElementsByTagName(nsCode+":"+tagName);
    }
    return retval;
}

// Cross browser means of cancelling default event handling.
function cancelClick(e) {
    if (e && e.returnValue) {
        e.returnValue = false;
    }
    if (e && e.preventDefault) {
        e.preventDefault();
    }
}

//NEEDSWORK this goes away with getPostNodePublished
// Method for extracting a numeric id from an object id.
function extractId(objId) {
    var id = -1;
    idx = objId.lastIndexOf('_');
    if (idx > -1) {
        id = objId.substring(idx+1);
    }
    return id;
}

//NEEDSWORK rewrite this
// Get time stamp.
function getPostNodePublished(post) {
    var postDate = null;
    var time = getElementById(post,"post_published_"+extractId(post.id));
    if (time && time.childNodes[0]) {
        dateStr = time.childNodes[0].nodeValue;
        postDate = new Date(Date.parse(dateStr));
    }
    else {
        postDate = new Date();
    }
    return (postDate);
}

// Check for proper browser support
function isBrowserSupported() {
    return true;

    // AN: TODO
    retval = true;
    try {
        var trans = Ajax.getTransport();
        if (trans == null) {
            retval = false;
        }
    }
    catch (e) {
        retval = false;
    }
    return (retval);
}

// AN: TODO, internationalization
// Basic date formatter (has not been
// internationalized).
function formatDate(dateObj) {
    var ampm  = "AM";
    var month = dateObj.getMonth()+1;
    var day   = dateObj.getDate();
    var year  = dateObj.getFullYear();
    var hours = dateObj.getHours();
    var mins  = dateObj.getMinutes();
    if (hours > 12) {
        ampm = "PM";
        hours -= 12;
    }
    else if (hours ==0) {
        hours = 12;
    }
    if (hours < 10) {
        hours = "0"+hours;
    }
    if (mins < 10) {
        mins = "0"+mins;
    }
    return (month+"/"+ day+"/"+year+" "+hours+":"+mins+" "+ampm);

}