function assignUniqueId(e) {
    if (!e.getAttribute("id"))
        e.setAttribute("id", "uniqueid_" + arguments.callee.nextId++);
    return e.getAttribute("id");
}
assignUniqueId.nextId= 0;

function Feeder(config) {
    this.config= Object.extend(config, Feeder.DEFAULTS);
    Event.onDOMReady(this.init.bind(this));
    this.categories= {};
}

Feeder.DEFAULTS = {
    allLabel: "All",
    entryTemplate: '<h4><a href="#{link}">#{title}</a></h4><p>#{excerpt}</p>',
    categoryTemplate: "<a>#{label}</a>",
    frameDelay: 25,
    slideDuration: 500
};

Feeder.prototype.getCategoryNames= function() {
    var cats= [];
    var c;
    
    for (c in this.categories)
        cats.push(c);
    return cats.sort();
}

Feeder.prototype.easeInOutSine = function(t, b, c, d) {
	return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
};

Feeder.prototype._addEntryToCategory= function(entry, category) {
    if (!this.categories[category])
        this.categories[category]= [];
    this.categories[category].push(entry);
}

Feeder.prototype.getElement= function() {
    return $(this.config.elementId);
}

Feeder.prototype.getItemList= function() {
    return $(this.config.itemListId);
}

Feeder.prototype.getCategoryList= function() {
    return $(this.config.categoryListId);
}

Feeder.prototype.init= function() {
    var e= this.getElement();
    if (!e)
        return;

    //  measure the item widths
    var lists= e.getElementsByTagName("ul");
    var categoryList= lists[0];
    var itemList= lists[1];
    
    this.config.categoryListId= assignUniqueId(categoryList);
    this.config.itemListId= assignUniqueId(itemList);
    
    var li= itemList.getElementsByTagName("li")[0];
    if (!li)
        return;
    this.viewWidth= parseInt(Element.getStyle(e, "width"));
    this.cellWidth= parseInt(Element.getStyle(li, "width"), 10) +
                    parseInt(Element.getStyle(li, "margin-left"), 10) +
                    parseInt(Element.getStyle(li, "margin-right"), 10) +
                    parseInt(Element.getStyle(li, "border-left-width"), 10) +
                    parseInt(Element.getStyle(li, "border-right-width"), 10) +
                    parseInt(Element.getStyle(li, "padding-left"), 10) +
                    parseInt(Element.getStyle(li, "padding-right"), 10);

    //  retrieve the feed data
    new Ajax.Request( this.config.feedUrl,
                      { method: "get",
                        onSuccess: this.feedLoaded.bind(this),
                        onFailure: this.feedMissing.bind(this)
                      } );
}

Feeder.prototype.makeListForCategory= function(categoryName) {
    var newList= document.createElement("ul");
    var entries= this.categories[categoryName];
    if (!entries)
        return;
        
    var t= new Template(this.config.entryTemplate);
    var last= entries.length-1;
    
    function makeItem(entry, i) {
        var li= document.createElement("li");
        var classes= ['postSummary', 'post-' + entry.id];
        if (i%2)
            classes.push('odd');
        if (0===i)
            classes.push('first');
        else if (last==i)
            classes.push('last');
        li.className= classes.join(' ');
        li.innerHTML= t.evaluate(entry);
        newList.appendChild(li);
    }
    
    var list= this.getItemList();
    if (!list)
        return;
    newList.className= list.className;
    newList.style.left=0;
    newList.style.top=0;
    newList.id= list.id;
    this.contentWidth= (entries.length*this.cellWidth);
    newList.style.width= this.contentWidth + "px";
    entries.each(makeItem);
    list.parentNode.replaceChild(newList, list);
}

Feeder.prototype.categoryClicked= function(event) {
    var categoryList= this.getCategoryList();
    var target= $(event.target);
    var cat= target.innerHTML;
    this.makeListForCategory(cat);
    var active= categoryList.getElementsByClassName("active")[0];
    if (active)
        active.removeClassName("active");
    $(target.parentNode).addClassName("active");
}

Feeder.prototype.makeCategoryList= function() {
    var newList= document.createElement("ul");
    var list= this.getCategoryList();
    var self= this;
    var t= new Template(this.config.categoryTemplate);
    
    var categories= this.getCategoryNames();
    if (!categories)
        return;
        
    var last= categories.length-1;

    function makeCategory(category, i) {
        var li= document.createElement("li");
        var classes= ['category', 'category-' + category.replace(/\s+/g,'-')];
        if (self.config.allLabel==category) {
            classes.push('all');
            classes.push('active');
        }
        if (0===i)
            classes.push('first');
        else if (last==i)
            classes.push('last');
        li.className= classes.join(" ");
        li.innerHTML= t.evaluate({label:category});
        newList.appendChild(li);
    }
    
    categories.each(makeCategory);
    newList.onclick= this.categoryClicked.bindAsEventListener(this);
    newList.className= list.className;
    newList.id= list.id;
    list.parentNode.replaceChild(newList, list);
}

Feeder.prototype.feedLoaded= function(request) {
    this.feed= eval("("+request.responseText+")");
    var entries= this.feed.entries;
    var self= this;
    
    function processEntry(entry) {
        function processCategory(category) {
            self._addEntryToCategory(entry, category);
        }
        self._addEntryToCategory(entry, self.config.allLabel);
        entry.categories.each(processCategory);
    }
    
    entries.each(processEntry);
    
    this.makeCategoryList();
    //  Add clipping div
    var clip= document.createElement("div");
    clip.className="clipper";
    var list= this.getItemList();
    list.parentNode.replaceChild(clip, list);
    clip.appendChild(list);
    this.makeListForCategory("All");
    var e= this.getElement();

    var prev= document.createElement("a");
    this.config.prevId = assignUniqueId(prev);
    prev.className= "prev";
    e.appendChild(prev);
    Event.observe(prev, "click", this.previousClicked.bindAsEventListener(this));
    
    var next= document.createElement("a");
    this.config.nextId = assignUniqueId(next);
    next.className= "next";
    e.appendChild(next);
    Event.observe(next, "click", this.nextClicked.bindAsEventListener(this));
}

Feeder.prototype.feedMissing= function(request) {
    console.log( "feed missing" );
}

Feeder.prototype.animate= function() {
    var list= this.getItemList();
    if (!list)
        return;
    this._animationTimer= 0;
    
    this.now+= this.config.frameDelay;
    var newPos= this.easeInOutSine(this.now, this.start, this.stop-this.start, this.duration);
    list.style.left= -newPos + "px";

    if (this.now>=this.duration)
        return;
    this._animationTimer= setTimeout(this._animator, this.config.frameDelay);
}

Feeder.prototype.beginAnimation = function(start, stop, duration) {
    this.now= 0;
    this.duration= duration;
    this.start= start;
    this.stop= stop;
    this._animator= this.animate.bind(this);
    this._animationTimer= setTimeout(this._animator, this.config.frameDelay);
}

Feeder.prototype.stopAnimation = function() {
    this._animator= null;
    clearTimeout(this._animationTimer);
    this._animationTimer= null;
}

Feeder.prototype.previousClicked = function(event) {
    var list= this.getItemList();
    if (!list || this._animationTimer)
        return;
    var pos= -parseInt(Element.getStyle(list, "left"));
    var finalPos= Math.max(0, pos - this.viewWidth + this.cellWidth);
    this.beginAnimation(pos, finalPos, this.config.slideDuration);
}

Feeder.prototype.nextClicked = function(event) {
    var list= this.getItemList();
    if (!list || this._animationTimer)
        return;
    var pos= -parseInt(Element.getStyle(list, "left"));
    var finalPos= Math.min(this.contentWidth - this.viewWidth,
                           pos + this.viewWidth - this.cellWidth);
    this.beginAnimation(pos, finalPos, this.config.slideDuration);
}

