var org = {p3k: ({url:"http://rss.weather.com/weather/rss/local/35553?cm_ven=LWO&cm_cat=rss&par=LWO_rss", xml:"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<rss version=\"2.0\">\n  <channel>\n    <title>The Weather Channel: Your Local Weather Outlook--Double Springs, AL (35553)</title>\n    <link>http://www.weather.com/weather/local/35553?cm_ven=LWO&amp;cm_cat=rss&amp;par=LWO_rss&amp;cm_pla=city_page&amp;cm_ite=cc2&amp;site=city_page</link>\n    <description><![CDATA[Local Weather Outlook for Double Springs, AL (35553). Since 1982, The Weather Channel has brought timely weather information to the world. Now via our Local Weather Outlook RSS feed we can keep you up-to-date on the latest weather affecting the cities of your choice including: current local conditions, local Doppler radar, pollen trends, regional video forecasts with expert commentary, and extended forecast details delivered right to your desktop. The Weather Channel...Bringing Weather To Life]]></description>\n    <language><![CDATA[en-us]]></language>\n    <copyright><![CDATA[Copyright \xa9 2006, The Weather Channel Interactive, Inc.]]></copyright>\n    <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n    <lastBuildDate>Tue, 9 Feb 2010 13:53:18 GMT</lastBuildDate>\n    <docs><![CDATA[http://blogs.law.harvard.edi/tech/rss]]></docs>\n    <ttl>30</ttl>\n    <image>\n      <title><![CDATA[The Weather Channel: Local Weather Outlook ]]></title>\n      <url><![CDATA[http://image.weather.com/web/common/logos/twci_logo_110x104.jpg?cm_ven=LWO&cm_pla=logo&cm_ite=homepage&site=logo&cm_cat=rss&par=LWO_rss]]></url>\n      <link><![CDATA[http://www.weather.com?cm_ven=LWO&cm_pla=logo&cm_ite=homepage&site=logo&cm_cat=rss&par=LWO_rss]]></link>\n      <description><![CDATA[Local Weather Outlook from The Weather Channel]]></description>\n    </image>\n    <item>\n      <guid isPermaLink=\"false\">0.4107164865463493</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[Current Weather Conditions In Double Springs, AL (35553)]]></title>\n      <link><![CDATA[http://www.weather.com/weather/local/35553?cm_pla=city_page&cm_ite=cc&site=city_page&cm_ven=LWO&cm_cat=rss&par=LWO_rss]]></link>\n      <description><![CDATA[<img src=\"http://image.weather.com/web/common/wxicons/31/26.gif?12122006\" alt=\"\" />Cloudy, and 41 &deg; F. For more details?]]></description>\n    </item>\n    <item>\n      <guid isPermaLink=\"false\">0.8765493329395175</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[Your Local Doppler Radar]]></title>\n      <link><![CDATA[http://www.weather.com/weather/map/35553?cm_ven=LWO&cm_pla=map&site=map&name=dopplerradar300mile_large&cm_ite=doplr_300&cm_cat=rss&par=LWO_rss]]></link>\n      <description><![CDATA[This map shows the location and intensity of precipitation in your area. The color of the precipitation corresponds to the rate at which it is falling.  This map is updated every 15 minutes.]]></description>\n    </item>\n    <item>\n      <guid isPermaLink=\"false\">2.553780439153552</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[Pollen Trend for Double Springs, AL (35553)]]></title>\n      <link><![CDATA[http://www.weather.com/outlook/health/allergies/weather/tenday/35553?cm_ven=LWO&cm_pla=city_page&cm_ite=10day_pollen&site=city_page&cm_cat=rss&par=LWO_rss]]></link>\n      <description><![CDATA[Steady. View complete PollenCast?]]></description>\n    </item>\n    <item>\n      <guid isPermaLink=\"false\">1.7820709458646555</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[Video: Your Regional Weather Forecast]]></title>\n      <link><![CDATA[http://www.weather.com/multimedia/videoplayer.html?clip=362&collection=regwxforecast&cm_ven=LWO&cm_pla=video&site=video&cm_ite=se&cm_cat=rss&par=LWO_rss]]></link>\n      <description><![CDATA[Watch what the experts at The Weather Channel\xae have to say about the weather trends in your area.]]></description>\n    </item>\n    <item>\n      <guid isPermaLink=\"false\">2.740689700273861</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[ADV: Upgrade to weather.com Gold!]]></title>\n      <link><![CDATA[http://www.weather.com/services/weathergold.html?cm_ven=LWO&cm_pla=ad&cm_ite=gold&site=adv_gold&cm_cat=rss&from=rss&refer=rss&par=LWO_rss]]></link>\n      <description><![CDATA[Get advanced storm tracking maps and weather for 10 cities in one-click, all with no ads!  Start your free trial now.]]></description>\n    </item>\n    <item>\n      <guid isPermaLink=\"false\">0.40253625665674253</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[Your Weekend Forecast For Double Springs, AL (35553)]]></title>\n      <link><![CDATA[http://www.weather.com/weather/weekend/35553?cm_ven=LWO&cm_pla=city_page&cm_ite=weekend&site=city_page&cm_cat=rss&locid=35553&par=LWO_rss]]></link>\n      <description><![CDATA[Chance of Precipitation: Fri: 30% / Sat: 10% / Sun: 10%. For complete forecast details...]]></description>\n    </item>\n    <item>\n      <guid isPermaLink=\"false\">0.22139706523629854</guid>\n      <pubDate>Tue, 9 Feb 2010 13:53:18 GMT</pubDate>\n      <title><![CDATA[Your 10-Day Forecast for Double Springs, AL (35553)]]></title>\n      <link><![CDATA[http://www.weather.com/weather/tenday/35553?cm_ven=LWO&cm_pla=city_page&cm_ite=10-day&site=city_page&cm_cat=rss&locid=35553&par=LWO_rss]]></link>\n      <description><![CDATA[Today: Mostly Clear & High 43&deg;F / Low 20&deg;F.---- Wed: Mostly Sunny & High 39&deg;F / Low 22&deg;F.---- Thu: Mostly Cloudy & High 41&deg;F / Low 27&deg;F.---- Fri & Beyond.... For more details?]]></description>\n    </item>\n  </channel>\n</rss>\n", message:undefined, modified:(new Date(1265723598469)), baseUri:"http://p3k.org/rss/", query:"frameColor=#003333&textColor=black&_=1247282025147&titleBarColor=#CBDEEF&compact=&fontFace=&align=center&showXmlButton=false&maxItems=1&boxFillColor=white&titleBarTextColor=0000C0&width=225&url=http://rss.weather.com/weather/rss/local/35553?cm_ven=LWO&cm_cat=rss&par=LWO_rss&", param:{textColor:"black", width:"225", align:"center", fontFace:"", url:"http://rss.weather.com/weather/rss/local/35553?cm_ven=LWO&cm_cat=rss&par=LWO_rss", compact:"", frameColor:"#003333", showXmlButton:"false", boxFillColor:"white", _:"1247282025147", titleBarColor:"#CBDEEF", maxItems:"1", titleBarTextColor:"0000C0"}, box:"<table class=\"rssBox\" width=\"${width}\" bgcolor=\"${frameColor}\" \n      style=\"table-layout: fixed; overflow: hidden; font-family: ${fontFace};\" \n      align=\"${align}\" cellspacing=\"1\" cellpadding=\"7\" border=\"0\">\n<tr bgcolor=\"${titleBarColor}\">\n<td>\n   ${xmlButton}\n   <strong>${title}</strong>\n   <div>\n      <small style=\"color: ${titleBarTextColor};\">${date}</small>\n   </div>\n</td>\n</tr>\n<tr bgcolor=\"${boxFillColor}\">\n<td class=\"rssBoxContent\" style=\"color: ${textColor};\">\n   ${image}\n   ${items}\n   ${input}\n   <div class=\"rssBoxPromo\" style=\"margin-top: 0px; text-align: left; \n         font: 9px verdana, sans-serif\">\n      RSS box by <a href=\"http://p3k.org/rss\">p3k.org</a>.\n   </div>\n</td>\n</tr>\n</table>\n\n", image:"<a href=\"${link}\"><img src=\"${source}\" width=\"${width}\" height=\"${height}\" \nalt=\"${title}\" title=\"${title}\" align=\"${align}\" valign=\"${valign}\" \nhspace=\"${hspace}\" vspace=\"${vspace}\" border=\"0\" /></a>\n\n", input:"<form method=\"get\" action=\"${link}\">\n${description}\n<input type=\"text\" name=\"${name}\" size=\"15\" /> <input type=\"submit\" \nvalue=\"${title}\" />\n</form>\n\n", item:"<div class=\"rssBoxItemContent\">\n${title}\n${break}\n${description}\n${buttons}\n</div><br />\n\n", date:"${year}-${month}-${day}, ${hours}:${minutes}h\n\n", link:"<a class=\"${class}\" href=\"${link}\" style=\"${style}\">${text}</a>\n", error:"<?xml version=\"1.0\"?>\n<rss version=\"error\">\n   <channel>\n      <title>RSS Box Error</title>\n      <link>${link}</link>\n      <description>This output was automatically generated to report an error \n      that occurred during a request to the JavaScript RSS Box Viewer.</description>\n      <item>\n         <title>Oops, something went wrong...</title>\n         <description>An error occurred while processing the request to the \n         JavaScript RSS Box Viewer.</description>\n      </item>\n      <item>\n         <title>An error message was returned by the server.</title>\n         <description>${message}</description>\n      </item>\n      <item>\n         <description>Most likely, this might have happened because of a \n         non-existent or invalid RSS feed URL. Please check and possibly correct \n         your input, then try again.</description>\n      </item>\n   </channel>\n</rss>\n\n"})};
function debug(str) {
   return document.write('<p><span style="background-color: yellow;">', 
         str, '</span><p>');
}

org.p3k.RssBox = function() {
   var ref;
   var ISOPATTERN = /([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9:]+).*$/;
   
   var data = org.p3k;
   data.defaults = {
      url: "http://blog.p3k.org/rss",
      maxItems: 7,
      width: 200,
      align: "",
      frameColor: "black",
      titleBarColor: "lightblue",
      titleBarTextColor: "black",
      boxFillColor: "white",
      textColor: "black",
      showXmlButton: "",
      compact: ""
   };
   
   var baseUri = data.baseUri;
    
   var getColor = function(str) {
      if (str.length === 6 && parseInt(str, 16) && str.indexOf("#") !== 0) {
         str = "#" + str;
      }
      return str.toLowerCase();
   }

   var value;
   for (var i in data.defaults) {
      value = data.param[i];
      if (!value || value.length === 0) {
         data.param[i] = data.defaults[i];
      } else if (i.indexOf("Color") > 0) {
         data.param[i] = getColor(value);
      }
   }

   // FIXME: Ugly work-around for many boxes using too small width 
   // values because the former version did not show the exact output.
   if (data.param.javascript && data.param.width < 200) {
      data.param.width = 200;
   }
   // Remove obsolete parameters from param and query
   delete data.param.javascript;
   data.query = data.query.replace("javascript=true", "");   

   var NAMESPACES = {
      dc: "http://purl.org/dc/elements/1.1/",
      rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   };

   var getUrl = function(url) {
      url = baseUri + "proxy.r?" + encodeURIComponent(url);
   
      var HttpRequest = function() {
         return (typeof XMLHttpRequest !== "undefined") ?
            new XMLHttpRequest() : new ActiveXObject("Msxml2.XMLHTTP");
      }
   
      var request = new HttpRequest();
      request.open("GET", url, false);
      request.send(null);   
      if (!request.getResponseHeader("Date")) {
         var cached = request;
         var ifModifiedSince = cached.getResponseHeader("Last-Modified") || 
               new Date(0); // January 1, 1970
         request = new HttpRequest();
         request.open("GET", url, false);
         request.setRequestHeader("If-Modified-Since", ifModifiedSince);
         request.send("");
         if (request.status === 304) {
            request = cached; 
         }
      }
      return request;
   }
   
   var getDocument = function(source) {
      if (source) {
         if (document.implementation.createDocument) {
            var parser = new DOMParser();
            var doc = parser.parseFromString(source, "text/xml");
            return doc;
         } else if (window.ActiveXObject) {
            var doc = new ActiveXObject("Microsoft.XMLDOM");
            doc.async = "false";
            doc.loadXML(source);
            return doc;
         }
      }
      return null;
   }
   
   var getError = function() {
      var msg = null, root;
      if (!xml || data.message) {
         msg = data.message || "Unknown error.";
      } else if (xml.parseError && xml.parseError.errorCode) {
         msg = xml.parseError.reason; // IExplore
      } else if (root = xml.documentElement) {
         var errorNode;
         if (root.nodeName === "parsererror") {
            msg = xml.documentElement.textContent; // Mozilla
         } else if ((errorNode = root.childNodes[0]) && 
               errorNode.nodeName === "parsererror") {
            msg = errorNode.textContent; // Safari
         } else if (!/rss|rdf|scriptingNews/i.test(xml.documentElement.nodeName)) {
            msg = "Incompatible data format. Are you sure this is an RSS feed?";
         }
      }
      return msg;
   }
   
   var getNode = function(parent, name, namespace) {
      if (namespace) {
         if (typeof parent.getElementsByTagNameNS === "undefined") {
            var elements = parent.getElementsByTagName(namespace + ":" + name);
         } else {
            var elements = parent.getElementsByTagNameNS(NAMESPACES[namespace], name);
         }
      } else {
         var elements = parent.getElementsByTagName(name);
      }
      if (elements && elements[0]) {
         return elements[0];
      }
      return null;
   }
   
   var getText = function(node) {
      if (node && node.childNodes && node.childNodes.length > 0) {
         return node.childNodes[0].nodeValue || "";
      }
      return "";
   }
   
   var trim = function(str) {
      if (str) {
         return str.replace(/^\s*(\S*)\s*$/, "$1");
      }
      return "";
   }
   
   var padZero = function(n) {
      if (n < 10) {
         return "0" + n
      }
      return n;
   }

   var encodeXml = function(str) {
      if (!str) {
         return "";
      }
      return str.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/&/g, "&amp;");
   }
      
   var render = function(template, param) {
      if (!template || !param) {
         return template;
      }
      template = template.replace(/\$\{([^}]+)\}/g, function() {
         var key = arguments[1];
         return param[key] || "";
      });
      return template;
   }
   
   var renderDate = function(date) {
      if (date.constructor !== Date) {
         var str = String(date);
         var millis = Date.parse(str.replace(ISOPATTERN, "$1/$2/$3 $4"));
         if (millis) {
            date = new Date(millis);
         } else {
            date = new Date;
         }
      }

      return render(data.date, {
         year: date.getFullYear(),
         month: padZero(date.getMonth() + 1),
         day: padZero(date.getDate()),
         hours: padZero(date.getHours()),
         minutes: padZero(date.getMinutes()),
         seconds: padZero(date.getSeconds()),
         timeZone: "" // date.getTimezoneOffset()
      });
   }
   
   var renderButtons = function(enclosure, source) {
      var result = "";
      if (enclosure && enclosure.link) {
         result += render(data.image, {
            source: baseUri + "enclosure.gif",
            title: enclosure.type,
            link: encodeURI(enclosure.link),
            width: 13,
            height: 16
         });
      }
      if (source && source.link) {
         result += render(data.image, {
            source: baseUri + "source.gif",
            title: source.title,
            link: encodeURI(source.link),
            width: 15,
            height: 15
         });
      }
      return result;         
   }
   
   var param = data.param;
   var rss = data.rss = {items: []};
   var xml = getDocument(data.xml);

   rss.error = getError();
   if (rss.error !== null) {
      xml = getDocument(render(data.error, {
         link: baseUri + "?" + encodeXml(data.query),
         message: encodeXml(rss.error)
      }));
      param.compact = 0;
      param.showXmlButton = 1;
   }

   var root = xml.documentElement;
   var type = root.nodeName;

   if (type === "scriptingNews") {
      var channel = getNode(xml, "header");
      rss.format = "Scripting News";
      rss.version = getText(getNode(channel, "scriptingNewsVersion"));
      rss.title = getText(getNode(channel, "channelTitle"));
      rss.description = getText(getNode(channel, "channelDescription"));
      rss.link = getText(getNode(channel, "channelLink"));
      if (ref = getText(getNode(channel, "imageUrl"))) {
         ref = rss.image = {source: ref};
         ref.title = getText(getNode(channel, "imageTitle"));
         ref.link = getText(getNode(channel, "imageLink"));
         ref.width = getText(getNode(channel, "imageWidth"));
         ref.height = getText(getNode(channel, "imageHeight"));
         ref.description = getText(getNode(channel, "imageCaption"));
      }
   } else {
      var channel = getNode(xml, "channel");
      rss.format = "RSS";
      rss.version = (type === "rdf:RDF") ? "1.0" : 
            root.getAttribute("version");
      rss.title = getText(getNode(channel, "title"));
      rss.description = getText(getNode(channel, "description"));
      rss.link = getText(getNode(channel, "link"));
      var image = getNode(xml, "image");
      if (image) {
         ref = rss.image = {};
         ref.source = getText(getNode(image, "url"));
         ref.title = getText(getNode(image, "title"));
         ref.link = getText(getNode(image, "link"));
         ref.width = getText(getNode(image, "width"));
         ref.height = getText(getNode(image, "height"));
         ref.description = getText(getNode(image, "description"));
      }
   }
   
   if (type === "rdf:RDF") {
      rss.date = renderDate(getText(getNode(channel, "date", "dc")) || data.modified);
      rss.rights = getText(getNode(channel, "creator", "dc"));
      var input = getNode(root, "textinput");
      if (input && !getNode(input, "link")) {
         input = root.getElementsByTagName("textinput")[1];
      }
      if (input) {
         ref = rss.input = {};
         ref.link = getText(getNode(input, "link"));
         ref.description = getText(getNode(input, "description"));
         ref.name = getText(getNode(input, "name"));
         ref.title = getText(getNode(input, "title"));
      }
   } else {
      rss.date = renderDate(getText(getNode(channel, "lastBuildDate") || getText(getNode(channel, "pubDate"))) || data.modified);
      rss.rights = getText(getNode(channel, "copyright"));
   }
   
   var item, text, node;
   var items = xml.getElementsByTagName("item");

   for (var i=0; i<Math.min(items.length, param.maxItems); i+=1) {
      item = items[i];

      if (type === "scriptingNews") {
         ref = {title: ""};
         ref.description = getText(getNode(item, "text")).replace(/\n/g, " ");
         ref.link = getText(getNode(item, "link"));
         if (text = trim(getText(getNode(item, "linetext")).replace(/\n/g, " "))) {
            ref.description = ref.description.replace(new RegExp(text), 
                  '<a href="' + getText(getNode(item, "url")) + '">' + text + '</a>');
         }
      } else {
         ref = {
            title: getText(getNode(item, "title")),
            description: getText(getNode(item, "description")),
            link: getText(getNode(item, "link") || getNode(item, "guid"))
         };
     }

     if (node = getNode(item, "source")) {
        ref.source = {
           link: node.getAttribute("url"),
           title: getText(node)
        }
     }
     
     if (node = getNode(item, "enclosure")) {
        ref.enclosure = {
           link: node.getAttribute("url"),
           length: node.getAttribute("length"),
           type: node.getAttribute("type")
        }
     }
     
     if (node = getNode(item, "category")) {
        ref.category = {
           domain: node.getAttribute("domain") || "",
           content: getText(node)
        }
     }
     
     rss.items.push(ref);
   }
   
   var item, items = "";
   for (var i=0; i<rss.items.length; i+=1) {
      item = rss.items[i];
      items += render(data.item, {
         title: new function() {
            var title = (!param.compact ? "<strong>" : "");
            if (item.link) {
               title += render(data.link, {
                  link: encodeURI(item.link),
                  text: item.title,
                  'class': "rssBoxItemTitle"
               });
            } else {
               title += item.title;
            }
            !param.compact && (title += "</strong>");
            return new String(title); // FIXME: Funny, title alone will be rendered as [object]
         }(),
         'break': item.title && item.description ? "<br />" : "",
         description: (!param.compact || !item.title) && item.description,
         buttons: renderButtons(item.enclosure, item.source)
      });
   }
   
   var box = render(data.box, {
      title: rss.link ? render(data.link, {
         link: encodeURI(rss.link),
         text: rss.title,
         'class': "rssBoxTitle",
         style: "color: " + param.titleBarTextColor
      }) : rss.title,
      description: rss.description,
      items: items,

      xmlButton: param.showXmlButton && render(data.image, {
         link: param.url,
         source: baseUri + "rss.png",
         title: rss.format + " " + rss.version,
         width: 16,
         height: 16,
         align: "right",
         hspace: 3
      }),
      
      image: !param.compact && rss.image && render(data.image, {
         link: encodeURI(rss.image.link),
         source: rss.image.source,
         width: rss.image.width,
         height: rss.image.height,
         title: rss.image.title,
         align: "right",
         valign: "baseline",
         hspace: 5,
         vspace: 5
      }),
      
      input: !param.compact && rss.input && render(data.input, {
         link: encodeURI(rss.input.link),
         description: rss.input.description,
         name: rss.input.name,
         title: rss.input.title
      }),
      
      date: rss.date,
      width: param.width,
      frameColor: param.frameColor,
      fontFace: param.fontFace,
      align: param.align,
      titleBarColor: param.titleBarColor,
      titleBarTextColor: param.titleBarTextColor,
      boxFillColor: param.boxFillColor,
      textColor: param.textColor
   });

   if (!window.rssBoxSetup) {
      document.write(box);
   }
   
   return box;
};

org.p3k.RssBox();

