/***********************************************************************
 * This sliding image class is the 2nd version of the previous version
 * which contains too many bugs and cannot be extended easily.
 * In this version, all images in the specified list are moved to the
 * display area instead of create 2 new div and swap images in and out.
 *
 * The class should work fine on all browsers.
 *
 * Current size of the image display size is hard-coded; however,
 * it should not be too difficult to modify the code in order to
 * dynamically accept a new size.
 *
 * Sample:
 * <div id='disp_div'></div>
 * <!-- images -->
 * <ul id='img_list' style="display:none;visibility:hidden">
 *  <li>
 *  <img src='images/2009_postcard_RTU_front.jpg' alt="RTU Postcard" title="RTU Patent Search" width="480" height="320">
 *  <div name="met_data" style="top:170px;left:480px;height:60px;" class="fake_link" onclick="window.location.href='sample/clearance/index.html'">
 *   <span style="z-index:2;font-size:20px">Clearance</span><br/><span style="z-index:2;font-size:20px">Sample</span>
 *  </div>
 *  </li>
 *
 *  <li>
 *  <img src='images/2011_family_tree.jpg' alt="Family Tree Postcard" title="Validity Patent Search" width="480" height="320">
 *  <div name="met_data" style="top:280px;left:490px;width:230px;height:40px;" class="fake_link" onclick="window.location.href='sample/novelty/patent_family.html'">
 *   <span style="font-size:12px;z-index:2">Patent</span><br/><span style="font-size:12px;z-index:2">Family</span><br/><span style="font-size:12px;z-index:2">Sample</span>
 *  </div>
 *  </li>
 * </ul>
 *
 * <!-- thumb images -->
 * <div id="thumb_div"></div>
 * <ul id="thumb_div_imgs" style="display:none;visibility:hidden">
 *  <li><img src="images/thumb_2009_postcard_RTU_front.jpg" onclick="slide1.startImgNumber(0)" width="80" height="60"></li>
 *  <li><img src="images/thumb_2011_family_tree.jpg" onclick="slide1.startImgNumber(1)" width="80" height="60"></li>
 * </ul>
 *
 * <script type='text/javascript'>
 *  var slide = new SlideL2RKlass('img_list', 'disp_div', 'slide', "thumb_div")
 *  slide.show()
 * </script>
 * ---------------------------------------------------------------
 * Copyright (c) Taywin Boonjindasap | Express Search, Inc.
 *
 ***********************************************************************/

var itIsLoaded = 0  // make sure that all images are loaded before display
var isIE = false
if (window.addEventListener) {  // anything but IE
  if (window.load) {
    window.__load = window.load  // hijack window.load
    window.__load()
    itIsLoaded = 1
  }
  else {
    window.addEventListener('load', function() {
      itIsLoaded = 1
    }, false);
  }
}
else {  // IE
  isIE = true
  if (window.onload) {
    window.__load = window.onload  // hijack window.onload
    window.__load()
    itIsLoaded = 1
  }
  else {
    window.attachEvent('onload', function() {
      itIsLoaded = 1
    });
  }
}  // ensure images are loaded


/*****
 * class constructor
 */
function SlideL2RKlass(imgField, dsField, vName, thumbId) {
  this.varName = vName           // variable name of the class instance
  this.displayID = dsField       // an ID of div element for display images
  this.displayElem
  this.imgDivArray = new Array() // store all images found in the list element
  this.thumb = null              // store the current display element of thumb image
  this.outLink = new Array()
  this.currImg = 0
  this.nextImg = this.currImg+1
  this.step = 8      // 8 frames between each slide when display
  this.currStep = 0  // count down of current frame step
  this.displayTime = 8000  // stay on for 8 seconds for each image
  this.constW = 640        // hard-coded for easier display
  this.constH = 480        // hard-coded for easier display
  this.frameSpd = 200/this.step
  this.dist = Math.ceil(this.constW/this.step)
  if (!this.initDisplayElement()) {
    alert("Cannot find display element for image display!")
    return
  }

  if (this.initImg(imgField, thumbId)) { // an ID of list element (ul or ol) and thumb
    // optional variable name used for this class
    this.startTimeout = 100  // delay for loading image
    this.wTimeout = null     // is used to hold window.setTimeout()
    this.metaData = null
  }
  else { alert("Invalid argument for source image div ID and/or thumb div ID") }

  this.waiting()
}


/************************
 *  Accessor Functions
 ************************/

SlideL2RKlass.prototype.initDisplayElement = function() {
  var el = document.getElementById(this.displayID)
  if (el) {
    var dispEl = document.createElement("div")
    dispEl.id = "myslide_ds_area_"+this.displayID
    dispEl.style.width = "50px"   // arbitrary size for now
    dispEl.style.height = "50px"  // arbitrary size for now
    dispEl.style.position = "relative"
    dispEl.style.top = "0px"
    dispEl.style.left = "0px"
    dispEl.style.overflow = "hidden"
    el.appendChild(dispEl)
    // add thumb nail display
    this.displayElem = document.getElementById(dispEl.id)
    return true
  }
  else { return false }
}  // initDisplayElement()


/*****
 * Initial the class when all variables are ready. The initiation is ready
 * when an object of sourceField class variable exists.
 */
SlideL2RKlass.prototype.initImg = function(imgID, thumbID) {
  if (this.imgDivArray.length>0) { return }  // no change if images already exist
  var elimg = document.getElementById(imgID)
  this.thumb = document.getElementById(thumbID)
  if (elimg && this.thumb) {
    elimg.style.display = "none"      // attempt to hide
    elimg.style.visibility = "hidden" // attempt to hide (may not work in IE)
    elimg.style.listStyle = "none"    // remove source list bullet
    var items = elimg.getElementsByTagName("li")
    var imgs, metas, meta
    var top = 0, left = 0
    for (var i=0; i<items.length; i++) {  // go through each item list
      imgs = items[i].getElementsByTagName("img")
      metas = items[i].getElementsByTagName("div")
      meta = null
      for (var j=0; j<metas.length; j++) {  // allow only 1 meta link per image
        if (metas[j].getAttribute("name")=="met_data") {
          meta = metas[j]
          break
        }
      }
      // add images found as array into class's image array
      for (var j=imgs.length-1; j>=0; j--) {
        var newChild = imgs[j].cloneNode(false)
        if (!newChild.id) { newChild.id = "img_of_"+this.varName+"_"+((i*10)+j) }
        newChild.width = this.constW
        newChild.height = this.constH
        var imgDiv = document.createElement("div")
        imgDiv.id = "slide_img_"+this.varName+"_no_"+((i*10)+j)
        imgDiv.style.position = "absolute"
        imgDiv.style.zIndex = 0
        imgDiv.style.top = top + (isIE ? "" : "px")
        imgDiv.style.left = left + (isIE ? "" : "px")
        imgDiv.style.border = "0px solid transparent"
        imgDiv.appendChild(newChild)  // add the copied
        this.displayElem.appendChild(imgDiv)
        imgs[j].parentNode.removeChild(imgs[j])  // remove original
        this.imgDivArray.push(document.getElementById(imgDiv.id))
        this.outLink.push(meta)
        left += this.constW
      }
    }  // for each i in items

    // init thumb with arbitrary size (may wait for loading later)
    this.thumb.style.position = "relative"
    this.thumb.style.textAlign = "center"
    this.thumb.style.top = "0px"
    this.thumb.style.height = "10px"
  }
  else { return false }

  return true
}  // initImg()


/*****
 * Create thumb display inside thumb.
 */
SlideL2RKlass.prototype.initThumbImg = function() {
  if (this.thumb) {  // there is an area to display thumb assigned
    var tImgList = document.getElementById(this.thumb.id.replace(this.displayID, "")+"_imgs")
    var thms, thm
    var cumw=0, fixW=0, fixH=0, pos
    var imgLen = this.imgDivArray.length
    if (tImgList) {  // has thumb images
      tImgList.style.display = "none"       // attempt to hide
      tImgList.style.visibility = "hidden"  // attempt to hide (may not work on IE)
      thms = tImgList.getElementsByTagName("img")
      cumw = 0
      for (var i=0; i<thms.length; i++) {
        thm = thms[i].cloneNode(false)
        if (thm.height>fixH) { fixH=thm.height }
        if (thm.width>fixW) { fixw=thm.width }
        thm.id="thumb_"+this.varName+"_"+i
        thm.style.position="absolute"
        thm.style.left = cumw + ((isIE)? "" : "px")
        thm.style.cursor = ((isIE)? "hand" : "pointer")
        thm.style.zIndex = 2
        if (i==this.currImg) { thm.style.border = "2px solid red" }
        else { thm.style.border = "2px solid transparent" }
        this.thumb.appendChild(thm)
        cumw += thm.width+4
      }
      this.thumb.style.left = Math.floor((this.constW-cumw+4)/2) + ((isIE)? "" : "px")
      this.thumb.style.height = fixH+10 + ((isIE)? "" : "px")
      this.thumb.style.width = (cumw+10) + ((isIE)? "" : "px")
    }
  }
}  // initThumbImg()


/*****
 * Wait for itIsLoaded. If itIsLoaded is true (positive), set the display
 * and run slide; otherwise, keep waiting.
 */
SlideL2RKlass.prototype.waiting = function() {
  if (itIsLoaded==0) {
    window.setTimeout(this.varName+".waiting()", this.startTimeout)
  }
  else if (this.imgDivArray.length==0) {
    alert("No image found to be displayed!")
  }
  else {
    this.initThumbImg()
    this.setDisplayCurrImg()
  }
}  // waiting()


/*****
 * Return a string describing this class object.
 * Override default toString() function
 *
 * @return  a string describing the class object
 */
SlideL2RKlass.prototype.toString = function() {
  var out = "SlideL2RKlass Object\n"
  out += "\n Image Display: "+this.qArray[0]
  out += " -> current: "+this.imgDivArray[this.qArray[0]].childNodes[0].src+"\n"
  out += " Frames (each step): "+this.step+"\n"
  out += " Display Length (each image): "+this.displayTime/1000+" sec(s)"+"\n"

  return out
}  // toString()


/*****************************
 *  Display Related Functions
 *****************************/

/*****
 * Set up the display.
 */
SlideL2RKlass.prototype.setDisplayCurrImg = function() {
  // set display screen the first time
  if (this.displayElem) {
    this.displayElem.style.width = this.constW+((isIE)? "" : "px")
    this.displayElem.style.height = this.constH+((isIE)? "" : "px")
  }
}  // setDisplayCurrImg()


/*****
 * Set up the display.
 */
SlideL2RKlass.prototype.show = function(mul) {
  if (this.imgDivArray.length==0 || itIsLoaded==0) {  // keep waiting
    window.setTimeout(this.varName+".show("+mul+")", this.startTimeout)
  }
  else if (this.imgDivArray.length==1) { }  // do nothing for 1 image only
  else {
    mul = (isNaN(mul) || mul<0) ? 1 : mul
    this.currStep = this.step
    this.displayMetaLink(true)
    this.wTimeout = window.setTimeout(this.varName+".slidingImg("+mul+",0)", this.displayTime*mul)
  }
}  // show()


/*****
 * Set up the display.
 */
SlideL2RKlass.prototype.slidingImg = function(len, skip) {
  this.currStep -= 1
  len = (isNaN(len) || len<=0) ? 1 : len
  if (this.currStep>0) {  // keep sliding
    this.displayMetaLink(false)
    var left1 = parseInt(this.imgDivArray[this.currImg].style.left, 10)-this.dist
    var left2 = parseInt(this.imgDivArray[this.nextImg].style.left, 10)-this.dist
    this.imgDivArray[this.currImg].style.left = left1 + (isIE ? "" : "px")
    this.imgDivArray[this.nextImg].style.left = left2 + (isIE ? "" : "px")

    this.wTimeout = window.setTimeout(this.varName+".slidingImg("+len+","+skip+")", this.framdSpd*len)
  }
  else {  // the next image is now fully display, wait until next display
    this.stopSliding()
    this.imgDivArray[this.nextImg].style.left = 0 + (isIE ? "" : "px")
    this.currImg = this.nextImg
    this.nextImg = (this.nextImg+1) % this.imgDivArray.length // move to the next on the right
    this.displayMetaLink(true)
    this.moveThumb()
    this.currStep = this.step  // reset step

    // adjust all other images' left position
    var currNum = this.nextImg
    var left = this.constW
    while (currNum!=this.currImg) {
      this.imgDivArray[currNum].style.left = left + (isIE ? "" : "px")
      currNum = (currNum+1) % this.imgDivArray.length
      left += this.constW
    }

    if (!isNaN(skip) && skip>0) {  // skipping
      skip -= 1
      this.wTimeout = window.setTimeout(this.varName+".slidingImg("+len+","+skip+")", 32)
    }
    else {
      this.wTimeout = window.setTimeout(this.varName+".slidingImg(1,"+skip+")", this.displayTime*len)
    }
    // move the thumb highlight
  }
}  // slidingImg()


/*****
 * Reset slide show to a selected image number. The number of image is using
 * 0-index as in array indexing.
 *
 * @param  pos  an integer of selecting image
 */
SlideL2RKlass.prototype.startImgNumber = function(pos) {
  // ignore invalid image number
  if (isNaN(pos) || (pos<0) || (pos>=this.imgDivArray.length)) { return }
  this.stopSliding()  // stop animation first
  if ((this.currStep%this.step)!=0) {  // being called while displaying animation
    this.imgDivArray[this.nextImg].style.left = 0 + (isIE ? "" : "px")
    this.currImg = this.nextImg
    this.nextImg = (this.nextImg+1) % this.imgDivArray.length // move to the next on the right
    this.displayMetaLink(true)
    this.moveThumb()
    this.currStep = this.step
  }

  // compute the distant to be skipping
  var skipping = pos>=this.currImg ? (pos-this.currImg-1) : (pos+(this.imgDivArray.length-this.currImg)-1)
  this.displayMetaLink(false)
  if (skipping<0) {
    this.displayMetaLink(true)
    this.wTimeout = window.setTimeout(this.varName+".slidingImg(1,0)", this.displayTime*2)
  }
  else { this.slidingImg(2, skipping) }
}  // startImgNumber(int)


/*****
 * Either start or stop sliding by checking if the class object has a thred
 * of setTimeout.
 */
SlideL2RKlass.prototype.startStopSlide = function() {
  if (this.wTimeout) {
    this.stopSliding()
  }
  else {
    this.setDisplayCurrImg()
    this.moveThumb()
    this.show()
  }
}  // startStopSlide()


/*****
 * Display selected thumb. Assume that slide always move from right to left.
 * (The current image position keeps going up and is reset once it hit the
 * total number of images.)
 */
SlideL2RKlass.prototype.moveThumb = function() {
  if (this.thumb) {  // need to set display of thumb
    var el
    for (var i=0; i<this.imgDivArray.length; i++) {
      el = document.getElementById("thumb_"+this.varName+"_"+i)
      if (this.currImg==i) { el.style.borderColor = "red" }
      else { el.style.borderColor = "transparent" }
    }
  }
}  // moveThumb()


/*****
 * Display selected thumb. Assume that slide always move from right to left.
 * (The current image position keeps going up and is reset once it hit the
 * total number of images.)
 *
 * @param  mode  boolean indicates whether or not the meta data will be
 *               displayed
 */
SlideL2RKlass.prototype.displayMetaLink = function(mode) {
  if (mode && mode.toString()=="true") {  // show
    var el = this.imgDivArray[this.currImg]
    if (this.outLink[this.currImg]) {
      el.appendChild(this.outLink[this.currImg].cloneNode(true))
      this.metaData = el.childNodes[el.childNodes.length-1]
    }
  }
  else {  // hide
    if (this.metaData && this.metaData.parentNode) {
      this.metaData.parentNode.removeChild(this.metaData)
    }
  }
}  // displayMetaLink(boolean/string)


/*****
 * Return an integer of index position of numElement inside qArray.
 * Return -1 if not found or invalid argument number.
 * This function is used to avoid problem that IE does not implement
 * array's indexOf() function.
 *
 * @param  numElement  an integer which is supposed to be an element number
 * @return  an integer of index position
 */
SlideL2RKlass.prototype.qArrayIndexOf = function(numElement) {
  if (!isNaN(numElement) || numElement<0) {
    for (var i=this.qArray.length-1; i>=0; i--) {
      if (numElement==this.qArray[i]) { return i }
    }
  }

  return -1
}  // qArrayIndexOf()


/*****
 * Stop sliding by checking if the class object has a thread of setTimeout.
 */
SlideL2RKlass.prototype.stopSliding = function() {
  if (this.wTimeout) {
    window.clearTimeout(this.wTimeout)
    this.wTimeout = null
  }
}  // stopSliding()


