/* Copyright 2008 - Idee Inc. All rights reserved. */
var tineyeFlows = Array();

// The conf object can contain:
function TineyeFlow(conf) {
    this.theDiv = jQuery("#"+conf.divId);
    this.divId = conf.divId;
    this.numShown = conf.numShown===undefined?15:conf.numShown;
    this.imgPrefix = conf.imgPrefix;
    this.format = conf.imgFormat;
    var thisPersistent = this;
    
    this.maxImgWidth = conf.maxImgWidth===undefined?180:conf.maxImgWidth;
    this.imgAR = conf.imgAR===undefined?0.7:conf.imgAR;
    this.tailBend = conf.tailBend===undefined?2:conf.tailBend;
    this.tailExtend = conf.tailExtend===undefined?0.5:conf.tailExtend;
    this.controlsPrefix = conf.controlsPrefix===undefined?"":conf.controlsPrefix;
    this.speed = conf.speed===undefined?0.001:conf.speed;
    this.playing = conf.autoplay===undefined?false:conf.autoplay;
    this.aboutstring = conf.aboutstring;
    this.embedsmalltitle = conf.embedsmalltitle;
    this.embedlargetitle = conf.embedlargetitle;
    this.embedsmallstring = conf.embedsmallstring;
    this.embedlargestring = conf.embedlargestring;
    this.creditstring = conf.creditstring;
    this.yOffset = conf.yOffset;
    this.showDiggLink = conf.showDiggLink===undefined?false:conf.showDiggLink;
    tineyeFlows[conf.divId] = this;
    jQuery.getJSON(conf.infoSrc, function(json) {
            thisPersistent.info = json.array;
            thisPersistent.init();
        });
}
TineyeFlow.prototype = {
    t:0,
    prevT:null,
    tTarget:0,
    seeking: false,
    seekPrecision: 0.05, // How close to tTarget before you're basically there
    looping: true,
    stopLooping: false,
    numShown: 15,
    maxImgWidth: 180,

    init: function() {
        this.originX = this.theDiv.width()/2;
        this.originY = this.theDiv.height()-this.yOffset;
        this.originZ = this.numShown;
        
        this.numResults = this.info.length;    
        this.images = Array();
        this.imgBoxes=Array();

        this.theDiv.children(".result").remove();
        
        this.prevDate = (new Date()).getTime(); 
        // Keeps "this" local to callbacks.
        var obj = this;

        jQuery(document).keydown(function(event) {
            switch (event.keyCode) {
                case 32:
                    obj.toggleAnimation();
                    break;
                case 37:
                    obj.prev();
                    break;
                case 39:
                    obj.next();
                    break;
            }
        });
          
     

        this.theDiv.
            append(jQuery("<div class='flowbydomain'>")).
            append(jQuery("<div class='flowbypoint'>").html("<input type='text' class='flowbycurrimg' value='1' size='4'/> of "+this.numResults));
        this.theDiv.find(".flowbycurrimg").change(function() {
                var t = parseInt(this.value,10)-1;
                if (t>=0 && t <= obj.numResults-1) {
                    obj.t = t;
                } else {
                    this.value=Math.floor(t)+1;
                }
            });
        
        // Put in controls
        this.theDiv.append(jQuery("<div class='flowbycontrols'>"));
        this.theDiv.children(".flowbycontrols").
            append(jQuery("<img src='"+this.controlsPrefix+"nav-start-off.png' class='start' title='start'>")).
            append(jQuery("<img src='"+this.controlsPrefix+"nav-prev-off.png' class='prev' title='previous'>"));
        if (this.playing) {
            this.theDiv.children(".flowbycontrols").
                append(jQuery("<img src='"+this.controlsPrefix+"nav-pause-off.png' class='playpause' title='play/pause'>"));
        } else {
            this.theDiv.children(".flowbycontrols").
                append(jQuery("<img src='"+this.controlsPrefix+"nav-play-off.png' class='playpause' title='play/pause'>"));
        }
        this.theDiv.children(".flowbycontrols").
            append(jQuery("<img src='"+this.controlsPrefix+"nav-next-off.png' class='next' title='next'>")).
            append(jQuery("<img src='"+this.controlsPrefix+"nav-end-off.png' class='end' title='end'>"));

        var bottomBar = jQuery("<div class='flowbybottombar'>");
        
        bottomBar.append(
                    jQuery("<a href='#'>About</a>").click(
                        function() {
                            jQuery('.flowbymoreinfo').slideToggle('normal');
                            jQuery('.flowbyembed').slideUp('normal');
                            return false;
                        })).
                append(
                    jQuery("<a href='#'>Embed</a>").click(
                        function() {
                            jQuery('.flowbyembed').slideToggle('normal');
                            jQuery('.flowbymoreinfo').slideUp('normal');
                            return false;
                        }));
        if (this.showDiggLink) {
            bottomBar.append(
                    jQuery("<a href='http://digg.com/tech_news/Amazing_Image_Identification_Demonstration' target='_blank'>Digg it!</a>")
                    );
        }
        bottomBar.append(jQuery("<span class='flowbycredit'></span>").html(this.creditstring));
        this.theDiv.append(bottomBar);
        
        // Scoping
        var embedstring = this.embedstring;
        this.theDiv.
            append(jQuery("<div class='flowbymoreinfo'></div>").append(jQuery("<div class='flowbyindiv'></div>").html(
                "<h2><img src='/images/logo.gif' style='width:33px;'/>About</h2>" +
                this.aboutstring).
                append(jQuery("<div class='flowbyclose'/>").click(
                      function() {
                        jQuery(".flowbymoreinfo").slideUp('normal');  
                      })
                    )).
                append(jQuery("<div class='flowbyarrow' />"))
            ).
            append(jQuery("<div class='flowbyembed'></div>").append(jQuery("<div class='flowbyindiv'></div>").
                        append(jQuery("<h2></h2>").html(this.embedlargetitle)).
                        append(jQuery("<input type='text' />").attr("value",this.embedlargestring)).
                        append(jQuery("<h2></h2>").html(this.embedsmalltitle)).
                        append(jQuery("<input type='text' />").attr("value",this.embedsmallstring)).
                        append(jQuery("<div class='flowbyclose' src='closebutton.png'></div>").click(
                              function() {
                                jQuery(".flowbyembed").slideUp('normal');  
                              })
                        )).
                        append(jQuery("<div class='flowbyarrow'></div>"))
                );
        cPref = this.controlsPrefix;
        this.theDiv.find(".start").
            hover(
                function() {
                    this.src=cPref+"nav-start-on.png";
                },
                function() {
                    this.src=cPref+"nav-start-off.png";
                }
            ).
            click(
                function() {
                    obj.t=0;
                    obj.seeking=false;
                }
            );
        this.theDiv.find(".prev").
            hover(
                function() {
                    this.src=cPref+"nav-prev-on.png";
                },
                function() {
                    this.src=cPref+"nav-prev-off.png";
                }
            ).
            click(
                function() {
                    obj.prev();
                }
            );
        this.theDiv.find(".next").hover(
                function() {
                    this.src=cPref+"nav-next-on.png";
                },
                function() {
                    this.src=cPref+"nav-next-off.png";
                }
            ).
            click(
                function() {
                    obj.next();
                }
            );
        this.theDiv.find(".end").hover(
                function() {
                    this.src=cPref+"nav-end-on.png";
                },
                function() {
                    this.src=cPref+"nav-end-off.png";
                }
            ).
            click(
                function() {
                    obj.t = obj.numResults-1;
                    obj.seeking=false;
                }
            );
        // The play/pause control now 
        this.theDiv.find(".playpause").
            hover(
                function() {
                    if(this.src.indexOf("pause") < 0) {
                        this.src=cPref+"nav-play-on.png";
                    } else {
                        this.src=cPref+"nav-pause-on.png";
                    }
                },
                function() {
                    if(this.src.indexOf("pause") < 0) {
                        this.src=cPref+"nav-play-off.png";
                    } else {
                        this.src=cPref+"nav-pause-off.png";
                    }
                }
            ).
            click(
                function() {
                    obj.toggleAnimation();
                }
            );
        
        // Set up images
        for (var i = 0; i < this.numResults; i++) {
            this.images[i] = {loaded: false, loading: false};
        }

        for (i = 0; i < this.numShown+2; i++) {
            this.imgBoxes.push(new FlowImg(i,this));
        }
        
        for (i in this.imgBoxes) {
            var img = this.imgBoxes[i];
            img.update(0);
        }
        setInterval("tineyeFlows['"+this.divId+"'].loop()",20);
    },

    loop: function() {
        var currDate = (new Date()).getTime();
        var dDate= currDate-this.prevDate;
        this.prevDate = currDate;
              
        if (this.prevT != this.t) {
            this.prevT = this.t;
            for (var i in this.imgBoxes) {
                this.imgBoxes[i].update(this.t);
            }
            this.theDiv.find(".flowbycurrimg").attr("value", Math.floor(this.t)+1);
            if (this.info!==undefined) {
                var thisInfo = this.info[Math.floor(this.t)];
                if (thisInfo !== undefined) {
                    this.theDiv.find(".flowbydomain").html("<a target='_blank' href='"+thisInfo.href+"'>"+thisInfo.short+"</a>");
                } else {
                    this.theDiv.find(".flowbydomain").html("No domain");
                }
            }
        }
        this.preloadRange(Math.floor(this.t),Math.floor(this.t) + this.numShown+6);
        if (this.seeking) {
            this.t += (this.tTarget-this.t)/5;
            if (this.t >= this.numResults-1) {
                this.t = this.numResults-1;
                this.seeking=false; 
            } else if(this.t<0){
                this.t=0;
                this.seeking=false;
            }
            if (Math.abs(this.tTarget-this.t)<this.seekPrecision) {
                this.t = this.tTarget;
                this.seeking=false;
            }
        }
        if (this.playing && !this.seeking) {
            this.t=this.t+dDate*this.speed;
            if (this.t>=this.numResults-1) {
                this.t=this.numResults-1;
                this.stopAnimation();
            }
        }
    },

    getLoc: function(index, t) {
        var x = (t-this.numResults*0.5)/this.numResults*this.tailBend*(index-t-1)*(index-t-1);
        var y = -(this.theDiv.height()+20)*this.tailExtend*(index-t-1)/(this.numShown-1);
        var z = -(index-t);
        var w = this.maxImgWidth-Math.floor(this.maxImgWidth/(this.numShown-0.9))*(index-t-1);
        var o = 1;
        if (z>-1) {
            w=this.maxImgWidth;
            x=0;
            y=0;
        }
        if (z>0) {
            o = 1-z;
        }
        if (z<-this.numShown) {
            o=0;
        }
        if (o>1) {
            o=1;
        } else if (o<0) {
            o=0;
        }
        var h = w/this.imgAR;
        return {
            x: x,
            y: y,
            z: z,
            w: w,
            h: h,
            opacity: o
        };
    },
    loadNextInRange: function(start, num) {
        for (var i = start; i < start+num; i++) {
            if (!this.images[i].loading && !this.images[i].loaded) {
                this.preload(i);
            }
        }
    },

    loadNext: function(index) {
        do {
            if (!this.images[index].loading && !this.images[index].loaded) {
                this.preload(index);
                break;
            }
            index = (index+1)%this.numResults;        
        } while (this.index != Math.floor(this.t));
    },

    preloadRange: function(start, stop) {
        if (start>stop) {
            var temp = start;
            start = stop;
            stop = temp;
        }
        for (var i = Math.floor(start); i <= stop && i < this.numResults; i++) {
            if (!this.images[i].loading &&!this.images[i].loaded) {
                this.preload(i);
            }
        }
    },

    preload: function(index) {
        this.images[index].loading=true;
        var i = new Image();
        i.src = this.imgPrefix + this.info[index].key + "." + this.format;

        // For the closure
        var images = this.images;
        i.onload = function() {
            images[index].loaded=true;
        };
        images[index].imgObj = i;
    },

    loadedFrom: function(start, stop) {
        if (start>stop) {
            var temp = start;
            start = stop;
            stop = temp;
        }
        for (var i = start; i <= stop; i++) {
            if(!this.images[i].loaded) { 
                return false;
            }
        }
        return true;
    },
    stopAnimation: function() {
        this.playing=false;
        this.tTarget = Math.round(this.t);
        this.seeking=true;
        this.theDiv.find(".playpause").attr("src",this.controlsPrefix+"nav-play-off.png");
    },
    startAnimation: function() {
        this.playing=true;
        this.theDiv.find(".playpause").attr("src",this.controlsPrefix+"nav-pause-off.png");
    },
    toggleAnimation: function() {
        if (this.playing) {
            this.stopAnimation();
        } else {
            if (this.t >= this.images.length-1) {
                this.t=0;
            }
            this.startAnimation();
        }
    },
    prev: function() {
        this.stopAnimation();
        this.tTarget = Math.floor(this.t-0.1);
        this.seeking=true;
    },
    next: function() {
        this.stopAnimation();
        this.tTarget = Math.ceil(this.t+0.1);
        this.seeking = true;
    }
};
var FlowImg = function(index, parent) {
    this.index = index;
    this.parent = parent;

    this.prevImgIndex = null;
    this.prevDOMNode = null;
};
FlowImg.prototype = {
    update: function(t) {
        // The index of the image that this ImgBox should be.
        var imgIndex = this.index + (this.parent.numShown+2)*Math.floor((t-this.index+this.parent.numShown+1)/(this.parent.numShown+2));
        var node;
        if (this.prevImgIndex != imgIndex) {
           node = jQuery("<img class='result' id='img" + this.index + "' />");
           node.hover(function() { jQuery(this).css({border:"2px solid #FFFF00", margin: "-2px 0 0 -2px"}); },
                      function() { jQuery(this).css({border: "none", margin: 0}); });
           if (this.prevDOMNode !== null) {
               this.prevDOMNode.remove();
           }
           this.prevDOMNode = node;
        } else {
            node = this.prevDOMNode;
        }
        if (imgIndex > this.parent.numResults-1) {
            node.css("display","none");
            this.prevImgIndex = imgIndex;
            return;
        }
        var loc = this.parent.getLoc(imgIndex, t);

        if(this.prevImgIndex != imgIndex) {
            node.attr("src",this.parent.imgPrefix + this.parent.info[imgIndex].key + "." + this.parent.format);
        }
        if (loc.opacity>0) {
            node.css({
                left:this.parent.originX + loc.x-loc.w/2, 
                top:this.parent.originY + loc.y-loc.w/this.parent.imgAR/2,
                zIndex:this.parent.originZ + Math.floor(loc.z),
                width: loc.w+"px",
                height: loc.h+"px",
                display:"block",
                opacity: loc.opacity
            });
            this.parent.images[imgIndex].loading = true;
        } else {
            node.css("display","none");
        }
        if (this.prevImgIndex != imgIndex) {
            this.parent.theDiv.append(node);
        }

        node.click(function(e) {
                    var parent = tineyeFlows[jQuery(this).parent().attr("id")];
                    var id =  jQuery(this).attr("id");
                    var num = parseInt(id.substring(3,id.length),10);
                    var imgIndex = num + (parent.numShown+2)*Math.floor((t-num+parent.numShown)/(parent.numShown+2));
                    parent.tTarget = imgIndex;
                    parent.preloadRange(parent.tTarget,parent.tTarget+parent.numShown);
                    parent.seeking = true;
                }).
            load(function() {
                    var parent = tineyeFlows[jQuery(this).parent().attr("id")];
                    var id =  jQuery(this).attr("id");
                    var num = parseInt(id.substring(3,id.length),10);
                    var imgIndex = num + (parent.numShown+2)*Math.floor((t-num+parent.numShown)/(parent.numShown+2));
                    if (imgIndex<0) {
                        return;
                    }
                    parent.images[imgIndex].loaded=true;
                });

        this.prevImgIndex = imgIndex;
    }
};

