
/*
 * Note to those who read this:  if you value good code, do NOT keep reading.
 * If you keep reading... You.  Will.  Cry.  Period.  If you were to not cry,
 * you quite possibly live in a blissful land, unaware of the importance of 
 * comments, structure, logic, or sanity.  Further, you will only learn what 
 * NOT to do, regarding javascript.
 * 
 * In the future, I will attempt to redeem myself to the coding gods.  Only time
 * will tell if such attempt is futile.
 * 
 * Regarding copyright, please do not copy, alter, redistribute, reuse this
 * code.  In other words, this code needs revised by its owner before its 
 * healthy enough to survive life in the wild.
 */

var COMIC_SLIDE_STEP = 5;
var COMIC_SLIDE_SPEED = 5;

// var davidata; // this variable needs to be set prior to now
var numComics;
var debug;
var animationPocket = new Pocket();
var farPrevComic;
var prevComic;
var nowComic;
var nextComic;
var farNextComic;
var requestingPrevComic = false;
var requestingNextComic = false;
var comicHeader;
var comicHeaderAnimOut;
var comicHeaderAnimIn;
var targetComicData;
// var initComicId; // this variable needs to be set eventually, prior to window.onload fire

window.onload = function() {
    numComics = Object.size( davidata );
    
    farPrevComic = new ComicElement( "farPrevComic" );
    farPrevComic.init( initComicId - 2 );
    prevComic = new ComicElement( "prevComic" );
    prevComic.init( initComicId - 1 );
    nowComic = new ComicElement( "nowComic" );
    nowComic.init( initComicId );
    nextComic = new ComicElement( "nextComic" );
    nextComic.init( initComicId + 1 );
    farNextComic = new ComicElement( "farNextComic" );
    farNextComic.init( initComicId + 2 );
    
    prevComic.elemComicWrapper.style.overflow = "hidden";
    prevComic.elemComicWrapper.style.height = ( document.getElementById( "comicTrailer" ).offsetHeight + nowComic.elem.offsetHeight ) + "px";
    nextComic.elemComicWrapper.style.overflow = "hidden";
    nextComic.elemComicWrapper.style.height = ( document.getElementById( "comicTrailer" ).offsetHeight + nowComic.elem.offsetHeight ) + "px";
    
    comicHeaderContainer = document.getElementById( "comicHeader" );
    comicHeader = comicHeaderContainer.getElementsByTagName( "h2" )[0];
    comicHeaderAnimOut = new ValueAnimation( comicHeader );
    comicHeaderAnimIn = new ValueAnimation( comicHeader );
    
    comicHeaderAnimOut.initialVal = 1;
    comicHeaderAnimOut.targetVal = 0;
    comicHeaderAnimOut.cssProperty = "opacity";
    comicHeaderAnimOut.cssValueSuffix = "";
    comicHeaderAnimOut.stepVal = .02;
    comicHeaderAnimOut.animSpeed = 5;
    
    comicHeaderAnimIn.initialVal = 0;
    comicHeaderAnimIn.targetVal = 1;
    comicHeaderAnimIn.cssProperty = "opacity";
    comicHeaderAnimIn.cssValueSuffix = "";
    comicHeaderAnimIn.stepVal = .02;
    comicHeaderAnimIn.animSpeed = 5;
    
    document.getElementById( "nl_prev" ).onclick = prevComic.onClickHandler;
    document.getElementById( "cnl_prev" ).onclick = prevComic.onClickHandler;
    document.getElementById( "nl_next" ).onclick = nextComic.onClickHandler;
    document.getElementById( "cnl_next" ).onclick = nextComic.onClickHandler;
}

function ComicData( comicId ) {
    var self = this;
    
    this.id = comicId;
    
    this.setId = function( comicId ) {
        self.id = comicId;
    }
    
    this.isValid = function() {
        return ( self.id >= 1 && self.id <= numComics );
    }
    
    this.getId = function() {
        return self.id;
    }
    this.getName = function() {
        return davidata[ self.id ][ "name" ];
    }
    this.getAlt = function() {
        return davidata[ self.id ][ "alt" ];
    }
    this.getTitle = function() {
        return davidata[ self.id ][ "alt" ];
    }
    this.getPlanet = function() {
        return davidata[ self.id ][ "planet" ];
    }
}

/*
 * type  a string whose value is the class name for the particular type
 */
function ComicElement( type ) {
    var self = this;
    this.elem = document.getElementsByClassName( type )[0];
    this.elemComicWrapper = this.elem.getElementsByTagName( "div" )[0];
    // eImg is a ref to the first image held in element e
    this.elemImg = this.elemComicWrapper.getElementsByTagName( "img" )[0];
    this.animSlideX = new ValueAnimation( this.elem );
    this.animSlideX.init();
    this.comicData;
    
    this.init = function( comicId ) {
        self.setComicData( new ComicData( comicId ) );
        
        // set up handlers
        self.elem.onclick = this.onClickHandler;
        self.animSlideX.onCompleteHandler = self.onAnimCompleteHandler;
    }
    this.onClickHandler = function( e ) {
        if ( requestingPrevComic == true || requestingNextComic == true ) {
            return;
        }
        
        if ( ! (
                ( self == prevComic && prevComic.comicData.isValid() == true ) ||
                ( self == nextComic && nextComic.comicData.isValid() == true )
            ) ) {
            return;
        }
        
        if ( self == nextComic ) {
            requestingNextComic = true;
            
            farNextComic.elem.style.display = "block";
            farNextComic.elem.style.position = "absolute";
            if ( farNextComic.elemImg != null ) {
                farNextComic.elemImg.style.position = "relative";
                farNextComic.elemImg.style.left = "-50%";
            }
            
            prevComic.animSlideX.initialVal = -10;
            prevComic.animSlideX.targetVal = -90;
            prevComic.animSlideX.cssProperty = "left";
            prevComic.animSlideX.cssValueSuffix = "%";
            prevComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            prevComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            nowComic.animSlideX.initialVal = 50;
            nowComic.animSlideX.targetVal = -10;
            nowComic.animSlideX.cssProperty = "left";
            nowComic.animSlideX.cssValueSuffix = "%";
            nowComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            nowComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            nextComic.animSlideX.initialVal = 120;
            nextComic.animSlideX.targetVal = 50;
            nextComic.animSlideX.cssProperty = "left";
            nextComic.animSlideX.cssValueSuffix = "%";
            nextComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            nextComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            farNextComic.animSlideX.initialVal = 190;
            farNextComic.animSlideX.targetVal = 110;
            farNextComic.animSlideX.cssProperty = "left";
            farNextComic.animSlideX.cssValueSuffix = "%";
            farNextComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            farNextComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            prevComic.animSlideX.startAnimationHandler();
            nowComic.animSlideX.startAnimationHandler();
            nextComic.animSlideX.startAnimationHandler();
            farNextComic.animSlideX.startAnimationHandler();
            
            nowComic.elem.style.zIndex = "10";
            nextComic.elem.style.zIndex = "20";
            
            if ( document.getElementById( "comics" ).offsetHeight < parseInt( nextComic.elemImg.height, 10 ) ) {
                document.getElementById( "comics" ).style.height = parseInt( nextComic.elemImg.height, 10 ) + "px";
            }
            
            targetComicData = nextComic.comicData;
        } else if ( self == prevComic ) {
            requestingPrevComic = true;
            
            farPrevComic.elem.style.display = "block";
            farPrevComic.elem.style.position = "absolute";
            if ( farPrevComic.elemImg != null ) {
                farPrevComic.elemImg.style.position = "relative";
                farPrevComic.elemImg.style.left = "-50%";
            }
            
            nextComic.animSlideX.initialVal = 110;
            nextComic.animSlideX.targetVal = 190;
            nextComic.animSlideX.cssProperty = "left";
            nextComic.animSlideX.cssValueSuffix = "%";
            nextComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            nextComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            nowComic.animSlideX.initialVal = 50;
            nowComic.animSlideX.targetVal = 110;
            nowComic.animSlideX.cssProperty = "left";
            nowComic.animSlideX.cssValueSuffix = "%";
            nowComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            nowComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            prevComic.animSlideX.initialVal = -10;
            prevComic.animSlideX.targetVal = 50;
            prevComic.animSlideX.cssProperty = "left";
            prevComic.animSlideX.cssValueSuffix = "%";
            prevComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            prevComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            farPrevComic.animSlideX.initialVal = 140;
            farPrevComic.animSlideX.targetVal = 80;
            farPrevComic.animSlideX.cssProperty = "right";
            farPrevComic.animSlideX.cssValueSuffix = "%";
            farPrevComic.animSlideX.stepVal = COMIC_SLIDE_STEP;
            farPrevComic.animSlideX.animSpeed = COMIC_SLIDE_SPEED;
            
            farPrevComic.animSlideX.startAnimationHandler();
            prevComic.animSlideX.startAnimationHandler();
            nowComic.animSlideX.startAnimationHandler();
            nextComic.animSlideX.startAnimationHandler();
            
            nowComic.elem.style.zIndex = "10";
            prevComic.elem.style.zIndex = "20";
            
            if ( document.getElementById( "comics" ).offsetHeight < parseInt( prevComic.elemImg.height, 10 ) ) {
                document.getElementById( "comics" ).style.height = parseInt( prevComic.elemImg.height, 10 ) + "px";
            }
            
            targetComicData = prevComic.comicData;
        }
        
        prevComic.elemComicWrapper.style.overflow = "visible";
        nextComic.elemComicWrapper.style.overflow = "visible";
        
        comicHeaderAnimOut.onCompleteHandler = self.comicHeaderAnimationHandler;
        comicHeaderAnimOut.startAnimationHandler();
    }
    this.onAnimCompleteHandler = function() {
        if ( self.allComicsAreStationary() == false ) {
            return;
        }
        
        if ( requestingNextComic == true ) {
            //dispose of old farPrevComic data
            farPrevComic.setComicData( prevComic.comicData );
            
            prevComic.elem.style.left = "-10%";
            prevComic.setComicData( nowComic.comicData );
            
            nowComic.elem.style.left = "50%";
            nowComic.setComicData( nextComic.comicData );
            
            nextComic.elem.style.left = "110%";
            nextComic.setComicData( farNextComic.comicData );
            
            farNextComic.elem.style.left = "190%";
            // load new farNextComic data
            farNextComic.setComicData( new ComicData( nextComic.comicData.getId() + 1 ) );
            
            nextComic.elem.style.zIndex = "10";
            nowComic.elem.style.zIndex = "20";
            
            requestingNextComic = false;
        } else {// ( requestingPrevComic == true )
            // dispose of old farNextComic data
            farNextComic.setComicData( nextComic.comicData );
            
            nextComic.elem.style.left = "110%";
            nextComic.setComicData( nowComic.comicData );
            
            nowComic.elem.style.left = "50%";
            nowComic.setComicData( prevComic.comicData );
            
            prevComic.elem.style.left = "-10%";
            prevComic.setComicData( farPrevComic.comicData );
            
            farPrevComic.elem.style.right = "110%";
            // load new farPrevComic data
            farPrevComic.setComicData( new ComicData( prevComic.comicData.getId() - 1 ) );
            
            prevComic.elem.style.zIndex = "10";
            nowComic.elem.style.zIndex = "20";
            
            requestingPrevComic = false;
        }
        
        prevComic.elemComicWrapper.style.overflow = "hidden";
        prevComic.elemComicWrapper.style.height = ( document.getElementById( "comicTrailer" ).offsetHeight + nowComic.elem.offsetHeight ) + "px";
        
        document.getElementById( "comics" ).style.height = "";
        
        nextComic.elemComicWrapper.style.overflow = "hidden";
        nextComic.elemComicWrapper.style.height = ( document.getElementById( "comicTrailer" ).offsetHeight + nowComic.elem.offsetHeight ) + "px";
    }
    this.allComicsAreStationary = function() {
        return ! ( farPrevComic.animSlideX.isAnimating ||
                   prevComic.animSlideX.isAnimating ||
                   nowComic.animSlideX.isAnimating ||
                   nextComic.animSlideX.isAnimating ||
                   farNextComic.animSlideX.isAnimating
                   );
    }
    this.updateElemContent = function() {
        if ( self.comicData.isValid() == true ) {
            self.elemComicWrapper.innerHTML = "<img src=\"http://img.daviday.com/comics/" + self.comicData.getId() + ".png\" alt=\"" + self.comicData.getAlt() + "\" title=\"" + self.comicData.getTitle() + "\" />";//<div class=\"comicWrapperFooter\"></div>";
            self.elemImg = self.elemComicWrapper.getElementsByTagName( "img" )[0];
        } else { // not a real comic
            // clear content
            self.elemComicWrapper.innerHTML = "";
            self.elemImg = null;
        }
    }
    this.setComicData = function ( cd ) {
        self.comicData = cd;
        self.updateElemContent();
    }
    this.comicHeaderAnimationHandler = function() {
        comicHeader.innerHTML = targetComicData.getName();
        
        comicHeaderAnimIn.startAnimationHandler();
    }
}

function ValueAnimation( element ) {
    var self = this;
    
    this.animPocketPos = animationPocket.addItem( self );
    this.elem = element;
    this.isAnimating = false;
    this.cssProperty = "opacity";
    this.cssValuePrefix = "";
    this.cssValueSuffix = "";
    this.initialVal = 0;
    this.currentVal = 0;
    this.targetVal = 1;
    this.stepVal = 1;
    this.animSpeed = 20;
    this.onCompleteHandler = null;
    
    this.init = function() {
        
    }
    
    this.updateElement = function() {
        self.elem.style[self.cssProperty] = self.cssValuePrefix + self.currentVal + self.cssValueSuffix;
    }
    
    this.startAnimationHandler = function() {
        if ( this.isAnimating == true || self.initialVal == self.targetVal )
        // already animating or there is no animation to occur, so prevent further execution
        {
            return;
        }
        
        self.isAnimating = true;
        self.currentVal = self.initialVal;
        self.updateElement();
        setTimeout( "animationPocket.itemAt("+self.animPocketPos+").stepAnimationHandler();", self.animSpeed );
    }
    this.stepAnimationHandler = function() {
        if ( self.currentVal == self.targetVal ) {
            self.endAnimationHandler();
        } else {
            if ( self.initialVal < self.targetVal )
            // increasing
            {
                self.currentVal += self.stepVal;
                if ( self.currentVal > self.targetVal ) {
                    self.currentVal = self.targetVal;
                }
            } else
            // decreasing
            {
                self.currentVal -= self.stepVal;
                if ( self.currentVal < self.targetVal ) {
                    self.currentVal = self.targetVal;
                }
            }
            self.updateElement();
            setTimeout( "animationPocket.itemAt("+self.animPocketPos+").stepAnimationHandler();", self.animSpeed );
        }
    }
    this.endAnimationHandler = function() {
        self.isAnimating = false;
        if ( self.onCompleteHandler != null ) {
            self.onCompleteHandler();
        }
    }
}

function Pocket() {
    var self = this;
    
    this.contents = new Array();
    
    // eventually, this should take advantage of lint status
    // in order to recycle old pocket positions
    // @return  int  position in pocket
    this.addItem = function( item ) {
        self.contents[self.contents.length] = new PocketItem( item );
        return self.contents.length - 1;
    }
    this.itemAt = function( pos ) {
        return self.contents[ pos ].getValue();
    }
}

function PocketItem( itemValue ) {
    var self = this;
    this.lintStatus = false;
    this.value = itemValue;
    
    this.lintify = function() {
        self.lintStatus = true;
        self.value = null;
    }
    this.isLint = function() {
        return self.lintStatus;
    }
    this.getValue = function() {
        return self.value;
    }
}

/*
 * http://stackoverflow.com/questions/5223/length-of-javascript-associative-array
 */
Object.size = function( obj ) {
    var objSize = 0;
    var key;
    
    for ( key in obj ) {
        if ( obj.hasOwnProperty( key ) ) {
            objSize++;
        }
    }
    
    return objSize;
}

