// SCRIPT MODULES LIBRARY   ECMAScript v3.0   (c) 2006 

// a Global object CSS07 is assumed declared  CSS07  may be changed to make it  unique for deployment 
try
{

// ===========================================================================
// NAMESPACE MANAGEMENT - ONLY ONE GLOBAL IDENTIFIER RESERVED ('CSS07')


// OVERVIEW: CORE LOGIC

// the Links object applies the events we want to the picture links (and removes them on destroy)
// One preview gallery corresponds to one page and one folder on disk

// Dependent on server-side image key setup in CSS07.img

// desirable enhancement #1: upgrade preview auto-scaling for viewport width.
// desirable enhancement #2: use classes not IDs to allow multiple OverView structures in one page.
// useful    enhancement #3: allow multiple instances (redevelop as a prototype 'class').
// possible  enhancement #4: auto-positioning of preview to avoid/minimise view-port clipping.

  if (!CSS07.app) { window.status = 'PRJ-LIB: CSS07.app not loaded]'; throw new Error(window.status); }

  if (!CSS07.kpl) { window.status = 'CSM-LIB: CSS07.kpl not loaded]'; throw new Error(window.status); }

  if (!CSS07.csm) { window.status = 'CSM-LIB: CSS07.csm not loaded]'; throw new Error(window.status); }

  if (!CSS07.gal) { CSS07.gal = {USAGE:'codesmiths.com.au ecmascript & event lib'}; } 

  CSS07.gal.urlPre     = 'http://';
  CSS07.gal.htReserved =  65; //px overhead for this imgSrc
  CSS07.gal.wdReserved =   4; //px
  CSS07.gal.sizeIncX   =  64;
  CSS07.gal.sizeIncY   =  40;
  CSS07.gal.min_wd     = 320;
  CSS07.gal.min_ht     = 200;
  CSS07.gal.zIndex     = 10;
  
  // experimental
  CSS07.gal.comIDext   = '_cmt';
  CSS07.gal.showMin    = 'showMin=';
  
  CSS07.gal.waitTimeMS = 100; // wait time for the image link to resolve

  CSS07.gal.captionClearance        = 4;           // CAPTION CLEARANCE: offset from thumbnail  (px)
  CSS07.gal.captionWidth            = 200;         // CAPTION WIDTH                             (px)
  CSS07.gal.captionReadSpeedCPS     = 20;          // CAPTION READ-RATE: user read speed (chars/sec)
  CSS07.gal.captionShowMinimum      = 3;           // CAPTION DISPLAY-TIME (secs) short caption

CSS07.gal.ImageKeys = function ()
      {
        this.amp = '&';
        this.qmk = '?';
        this.equ = '=';
        
        this.img  = CSS07.img.img;
        this.cap  = CSS07.img.cap;
        this.com  = CSS07.img.com;
        this.gap  = 'gap';

        this.xWin = CSS07.img.xWin;
        this.yWin = CSS07.img.yWin;
        
        this.file = CSS07.img.file;
        this.fldr = CSS07.img.fldr;
        
        this.wid  = CSS07.img.wid;
        this.hgt  = CSS07.img.hgt;
        
        this.imgExtn = CSS07.img.defExtn;

        this.imgLoadURI = CSS07.img.keyLoad;
        
        this.setSize = CSS07.gal.ImageKeys.setSizeKeys;
        
        // functions to return assembled keys
        
        this.jKey = function (keyName) {
          return this.amp + this[keyName];
        }
        this.qKey = function (keyName) {
          return this.qmk + this[keyName];
        }
        this.jKeyE = function (keyName) {
          return this.amp + this[keyName] + this.equ;
        }
        this.qKeyE = function (keyName) {
          return this.qmk + this[keyName] + this.equ;
        }
        this.keyRE = function (keyName) {
          return new RegExp(this[keyName] + this.equ);
        }
        this.fldrLoadURI= this.imgLoadURI.replace(this.file + this.equ, this.fldr + this.equ)
        
      };

CSS07.gal.ImageKeys.setSizeKeys = function(xVal, yVal)  // one or two keys
      {
        this.sufx  = '' + (xVal ? 'x' + xVal : '') + (yVal ? 'y' + yVal : '');
        this.args  = '' + (xVal ? this.jKeyE('wid') + xVal : '') + (yVal ? this.jKeyE('hgt') + yVal : '');
      };

CSS07.gal.ImageSizeKeys = function()    // over-ride always 2 keys deprecated
{
  this.setSize = function (x, y)
      {
        this.sufx  = 'x' + x + 'y' + (y || x);
        this.args  = '&' + CSS07.img.wid + '=' + x + '&' + CSS07.img.hgt + '=' + (y || x);
      };
  };

CSS07.gal.Browsers = function ()
      {
        var appVer = window.navigator.appVersion;
        var majVersion = parseInt(appVer.slice(0, appVer.indexOf('.')));
        //alert(majVersion);
        this.opera = (window.navigator.userAgent.toLowerCase().indexOf('opera') > -1 );
        this.msie  = (window.navigator.userAgent.toLowerCase().indexOf('msie')  > -1)  &&
                     (!this.opera);
      };
      
CSS07.gal.getEventTarget = function (evt)
      {
        var target = null;
        try {
          if (evt && evt.currentTarget)   { target = evt.currentTarget; }
          else if (evt && evt.srcElement) { target = evt.srcElement; } 
          else                            { target = window.event.srcElement; }          
        } catch(e) {}
        return (target);
      };
      
CSS07.gal.ImagePanel = function(x_or_img_id, y)  // Constructor  -- first arg x can be size or and img ID
      {
        if (!(this instanceof CSS07.gal.ImagePanel ))  { return null; }   // constructor was CALLed as a function

        CSS07.kpl.Encapsulator.call(this);   // 'inherit'   Encapsulator's features
        CSS07.gal.Browsers.call(this);       // 'inherit'   Browser properties

        this.imgLoadURI = CSS07.img.keyLoad;
        // LocalFolder for Src URL
        var href = window.location.href;
        var slash = '/';
        var rootSlash = href.indexOf(slash, 10);
        var locPath = href.slice(rootSlash, href.length);
        this.localFolder = locPath.slice(0, locPath.lastIndexOf(slash) +1);
        this.siteURL = href.slice(0, rootSlash);

        this.heightMax        = 'auto';      // PREVIEW MAX-HEIGHT: in px (auto = full height)
        this.heightMaxAutoAdj = 1.0;         // PREVIEW MAX-HGHT AUTOSCALE VERNIER:  (0.9=90%)
        this.heightMaxLowest  = 100;         // PREVIEW MAX-HGHT MINIMUM: lower limit     (px)
        this.heightMaxPadding = 80;          // PREVIEW MAX-HGHT PAD: clear viewport,etc. (px)
        this.clearance        = 6;           // PREVIEW CLEARANCE: offset from thumbnail  (px)
        this.showTime         = 10;          // PREVIEW DISPLAY-TIME (secs)
        this.heightMaxOverride= true;
        this.previewMoves     = true;

        
        // first arg - is it an id?
        var x;
        if (typeof(x_or_img_id) == 'string'){
          var elt = window.document.getElementById(x_or_img_id);
          if (elt) {
            this.id = x_or_img_id;
            this.elt = elt;
            x = elt.getAttribute('width')  || elt.offsetWidth;
            y = elt.getAttribute('height') || elt.offsetHeight;
            this.previewMoves = false;
          }
        }
        if (x === undefined) {
          this.id  = 'gal_preview';
          x = x_or_img_id;
        }
        this.imageName  = '';
        //this.debugImg = 0;

        CSS07.gal.ImageSizeKeys.call(this);
        this.setSize(x, y);
      };
CSS07.gal.ImagePanel.prototype.destroy  =  function ()
      {
        if (this.elt) { this.elt = null; }
        if (this.img) { this.img = null; }
      };
/* no ?
CSS07.gal.Image.prototype.setSize  =  function (x, y)
      {
        CSS07.gal.ImageSizeKeys.call(this, x, y);
      };
*/      
CSS07.gal.ImagePanel.prototype.toggleHeightMaxOverride  =  function ()
      {
        try
        {
            if(!this.enabled){return;}
            this.heightMaxOverride = !this.heightMaxOverride;
            if (this.msie)  { this.above = !this.above; }                                    // x-bwr
        }
        catch(e){
          alert('Exception in previewToggleHeightMaxOverride: ');
          this.enabled=false;
        }
      };

CSS07.gal.ImagePanel.prototype.panelShow =  function (newImgName, target, winYdim)
      {
      // here newImageName is just the fileName - they are all in a folder we know
        try
        {
          // if its the same image again - this will just make it visible & return null
          if (this.setImageName(newImgName)) {
            if (this.previewMoves) { this.positionAbove(target, winYdim); }
            //alert('previewAbove = ' + this.above);
            this.target = target;  // save for positioning
          }
        }
        catch(e){
          alert('Exception in Preview panelShow: ' + this.URL);
        }
      };

CSS07.gal.ImagePanel.prototype.startPreload  =  function (newImageName)
      {
        try
        { 
          // careful not to encode twice ...
          var ImageURL = this.imgLoadURI + this.localFolder + 
                         (newImageName.indexOf('%') < 0 ? encodeURI(newImageName) : newImageName);
          this.URL = ImageURL + this.args; 

          // undecorate any previous preload image
          if (this.onPreload) { 
            this.unbindEvent(this.img, this.onPreload, 'load');
            if(this.msie) { window.document.body.removeChild(this.img); }
            this.onPreload = null;
          }
          this.img.setAttribute('src', null);
          
          // now start afresh
          this.img = new Image();
          //  IE (7) load event only passes the event data if the img is in the DOM!!
          //  and Opera returns 0 for the image width if diplay is set to none!
          if (this.msie) {
            window.document.body.appendChild(this.img);
            this.img.style.display    = 'none';
          }
          //alert('Binding OnPreload');
          //window.status = 'Binding preview.Preload';
          this.onPreload = this.bindEvent(this.img, this.bind(this, this.Preload), 'load');
          this.img.setAttribute('src', this.URL);
          this.imageName = newImageName;
          this.superseded = false;  // IE
        }
        catch(e){
          alert('Exception in Preview startPreload: ' + this.URL);
        }
      };

CSS07.gal.ImagePanel.prototype.Preload  =  function (evt)
      {
        try
        {
            //window.status = 'preview.Preload fired : ' + this.enabled + '   ' + this.superseded;
            if (this.timerRef) { window.clearTimeout(this.timerRef); }
            this.timerRef = null;
            //alert('preview.Preload fired : ' + this.enabled);
            // We only ever have one loading! it must be on this.img -- except for race conditions? 
            if(!this.img || !this.enabled) { return; }
            
            // IE will only pass the elt in the event if it is in the DOM - then we have render issues with prLoad images!!
            var pvwImg = CSS07.gal.getEventTarget(evt); 
           
           
            // alert('previewOnPreload pvwImg ' + pvwImg.getAttribute('src'));
            if (!this.supersededURL(pvwImg)) {
                //window.status = 'calling previewSetDimensions';
                if (this.previewMoves) {
                  this.setDimensions();
                  this.setPosition(this.target);
                  this.elt.style.visibility = 'visible'; 
                }
                this.superseded = false;
                /* does not fix it
                //window.status = 'calling setAttribute ' + this.URL;
                if (this.opera) {
                  // opera quirk - won't fire load more than once
                  this.unbindEvent(this.elt, this.onloadFn, 'load');
                  this.bindEvent  (this.elt, this.onloadFn, 'load');
                }
                */
                this.elt.setAttribute('src', this.URL);
                // now its on the element maybe remove it from the preload image?
                if (this.previewMoves) {
                  this.timerRef = window.setTimeout(this.bind(this, this.hide), (this.showTime * 1000));
                }
            }
            else
            { 
                //window.status = 'preview Superseded';
                alert(window.status);
                this.superseded = true;
            }
        }
        catch(e){
        
          alert('Exception in preview.Preload: ' + this.URL);
          this.enabled=false;
        }
      };

CSS07.gal.ImagePanel.prototype.hide = function()  
      { 
        if (this.previewMoves) {
          this.elt.style.visibility = 'hidden'; 
          //if (this.debugImg >1) { this.debugImg -= 1; }
        }
      };
/*    
CSS07.gal.ImagePanel.prototype.onload = function ()
      {
        try
        {
            window.status = 'preview.load fired';
            alert('previewOnload : debugImg ' + this.debugImg + '  ' + this.superseded);
            if(!this.enabled){return;}
            if(this.debugImg > 1) {
              return;
            }
            var pvw = this.elt;
            if (!this.msie && (this.superseded || this.supersededURL(pvw)))  { return; }
            
            this.loadPreview();
            window.status = 'previewOnload complete';
        }
        catch(e){
          alert('Exception in previewOnload');
          this.enabled=false;
        }
      };


CSS07.gal.ImagePanel.prototype.load = function ()
      {
        try
        {
          this.setPosition();
          this.elt.style.visibility = 'visible'; 
          this.debugImg += 1;
          this.superseded = true;                                   
          if (this.timerRef)  { window.clearTimeout(this.timer); }
          this.timerRef = window.setTimeout(this.bind(this, this.hide), (this.showTime * 1000));
        }
        catch(e){
          alert('Exception in previewOnload');
          this.enabled=false;
        }
      };
*/


CSS07.gal.ImagePanel.prototype.setDimensions  =  function ()
      {
        try
        {

          var pvwImgWidth   = this.img.width; 
          var pvwImgHeight  = this.img.height;
          var pvwImgHghtMax = this.heightMax;
          var autoAdj       = this.heightMaxAutoAdj;
          var hghtMax, scaling;

          if (!this.heightMaxOverride)
          {
              if (pvwImgHghtMax != 'off')
              {
                  hghtMax = (pvwImgHghtMax == 'auto') ? this.heightMaxAuto() : pvwImgHghtMax;
                  if (hghtMax < pvwImgHeight)  
                  {   
                      scaling = hghtMax / pvwImgHeight;
                      pvwImgWidth  = Math.round(pvwImgWidth  * scaling); 
                      pvwImgHeight = Math.round(pvwImgHeight * scaling);  
                  }
              }
          }
          this.elt.style.width  = pvwImgWidth   + 'px'; 
          this.elt.style.height = pvwImgHeight  + 'px'; 
          //alert('previewSetDimensions : img width ' + this.elt.style.width);

        }
        catch(e){
          alert('Exception in previewSetDimensions');
          this.enabled=false;
        }
      };
 
CSS07.gal.ImagePanel.prototype.setPosition  =  function (elt)
    {
      try
      {
        var pvwClear  = this.clearance;
        
        var eltWidth  = elt.offsetWidth;
        var eltHeight = elt.offsetHeight;
        var pvwWidth  = this.elt.offsetWidth;
        var pvwHeight = this.elt.offsetHeight;
        var pvwLeft = CSS07.kpl.domLeftToBody(elt) - Math.round((pvwWidth - eltWidth) / 2);
        var pvwTop  = CSS07.kpl.domTopToBody(elt)  - pvwHeight;
        if (this.above)
        { 
            pvwTop -= pvwClear; 
        }
        else
        { 
            pvwTop += (pvwClear + (pvwHeight + eltHeight)); 
        }
        this.elt.style.top  = pvwTop  + 'px';
        this.elt.style.left = pvwLeft + 'px';
        //alert('previewSetPosition : ' + this.elt.style.left + '  ' + this.elt.style.top );
      }
      catch (e)
      {
        alert('Exception in previewSetPosition : ' + eltHeight);
      }
    };

CSS07.gal.ImagePanel.prototype.heightMaxAuto = function ()
    {
      try
      {
        var pvw = this.elt;
        var allotted, hghtMax;
        var pvwHeightMin = this.heightMaxLowest;
        allotted  = this.clearance;
        allotted += parseInt(CSS07.kpl.getStyle(pvw, 'paddingTop',        'padding-top'        ));
        allotted += parseInt(CSS07.kpl.getStyle(pvw, 'paddingBottom',     'padding-bottom'     ));
        allotted += parseInt(CSS07.kpl.getStyle(pvw, 'borderTopWidth',    'border-top-width'   ));
        allotted += parseInt(CSS07.kpl.getStyle(pvw, 'borderBottomWidth', 'border-bottom-width'));
        allotted += this.heightMaxPadding;
        hghtMax = ((this.winYdim / 2) - allotted) * this.heightMaxAutoAdj;
        return ( (hghtMax >= pvwHeightMin) ? hghtMax : pvwHeightMin );
      }
      catch (e)
      {
        alert('Exception in HeightMaxAuto : ' + pvwHeightMin);
        return 200;
      }
    };

CSS07.gal.ImagePanel.prototype.positionAbove  =  function(elt, winYdim)
    {
      try
      {
        var tmbToViewportTop = (CSS07.kpl.domTopToBody(elt) - CSS07.kpl.viewportToBodyTop()) + (elt.offsetHeight/2);
        var tmbToViewportBot = winYdim - tmbToViewportTop;
        //alert('tmbToViewportBot ' + tmbToViewportBot);
        this.above = (tmbToViewportTop > tmbToViewportBot); 
      }
      catch (e)
      {
        alert('Exception in previewPositionAbove : ');
      }
    };
    
CSS07.gal.ImagePanel.prototype.supersededURL  =  function (img)
    {
      try
      {
        if (!img) { return true; }
        var imgURL = img.getAttribute('src');

        if (imgURL.length > 0 && imgURL.slice(0,4) == 'http') {
          imgURL = imgURL.slice(this.siteURL.length, imgURL.length);
        }
        //window.status = 'compare\noldIMg : ' + this.URL + '\n newImg : ' + imgURL;
        var ret_val = (imgURL != this.URL);
        //alert(' oldIMg : ' + this.URL + '\n newImg : ' + imgURL + '\nNequal? ' + ret_val);
        return (imgURL != this.URL);
      }
      catch(e){
        alert('Exception in previewSupersededURL: ' + img);
        this.enabled=false;
      }
    };

CSS07.gal.ImagePanel.prototype.setImageName   = function (newImgName)
        {
          try
          {
            var curImageName = this.elt.getAttribute('src') || '';
            // this.newImage name can be set before load completes
            if (curImageName.indexOf(newImgName) > -1) {
               this.superseded = false;
               this.elt.style.visibility = 'visible'; 
            }
            else
            {
              if (this.imageName !== newImgName) {
                // IE leaves the img in the wrong place at times
                this.startPreload(newImgName); 
                return(true);
              } else {
                // waiting on load
                //***********************************
              }
            }
          }
          catch(e){alert('Exception in ImagePanel.setImageName'); }
        };

CSS07.gal.ImagePanel.prototype.makeElement   = function ()
// built once by constuctor
    {
      /*
        if (this.debugImg > 0) { 
          var div = window.document.getElementById(this.id);
          if (div) { alert('2 Previews'); }
          return;
        }
      */
        var elt, iso;
        if (!this.elt) {
          elt = window.document.createElement('img');
          
          elt.id         = this.id;
          iso = elt.style;
          iso.position   = 'absolute';
          iso.left       = '1px';
          iso.top        = '1px';
          iso.zIndex     = CSS07.gal.zIndex;
          iso.width      = '';                                                                    
          iso.height     = '';                                                                    
          iso.visibility = 'hidden';
          //iso.display    = 'block';
          if (true || this.msie) { window.document.body.appendChild(elt); }
          else { this.content.appendChild(elt); }
          //this.debugImg += 1;

          this.elt = elt;
        }
        this.img = new Image();    // for preload
        this.enabled = true;       
    };

// Handle the events including the basic "click" request for an image sized to the album page.
// shift click may defeat the logic as we dont have the page size of the new window unless we do a postback from it
CSS07.gal.Links = function (parentId, showPreviews, showCaptions, szThumbs, szPreviews)        // CLASS CONSTRUCTOR //
        {
          try
          {
            if (!(this instanceof CSS07.gal.Links ))  { return null; }   // constructor was CALLed as a function
            // Apply the event model
            this.content =  window.document.getElementById(parentId);

            if (!this.content) { return null; }                          // no content
                        
            CSS07.kpl.Encapsulator.call(this);   // 'inherit'   Encapsulator's features
            CSS07.gal.ImageKeys.call(this);      // 'inherit'   ImageKeys properties
            CSS07.gal.Browsers.call(this);       // 'inherit'   Browser properties

            if (showPreviews) {                        // PREVIEW IS TO BE SHOWN ?
              this.preview  = new CSS07.gal.ImagePanel(szPreviews || 300);
            }
            this.captionEnabled = showCaptions;        // CAPTION IS TO BE SHOWN ?

            this.captionId   = 'gal_caption';
            this.defComment =  'No Comment';
            this.above = false;
            
            CSS07.gal.ImageKeys.call(this);      // "inherit" ImageKeys properties
            this.thumb = new CSS07.gal.ImageSizeKeys;
            this.thumb.setSize(szThumbs || 80);        // needed to disassemble the thumb name
            
            var imgVal = '\\' + this.img + '=([^&]+)&';
            this.imgKeyRE = new RegExp(imgVal);  // match returns array length >1
            this.filePart = /[^\/\\]+$/;         // match returns array length 1

            this.debugCap = 0;
 
            // collect all the links under the parent elt
            this.eventElmts     = new Array;                        // elements with associated click events
            this.eventFuncs     = new Array;
            this.eventTypes     = new Array;                        // single or double
            this.nmbrEvents     = 0;
            
            var needMouseEvents = showPreviews || showCaptions;

            // fix the viewport dimensions on load; user can use refresh after a re-size
            this.getViewportSize();
            //alert ('window x=' + this.winXdim + ' y=' + this.winYdim);
            //this.winSizeKeys = this.keyXwin + this.winXdim + this.keyYwin + this.winYdim;
            this.winSizeKeys = this.jKeyE('xWin') + this.winXdim + this.jKeyE('yWin') + this.winYdim;
            var jj = 0;
            var thumbs = new Array();           // collect all the thumbs from under the album node
            var selector  = 'IMG';

            CSS07.csm.selectDescendants(this.content, selector, thumbs);
            //alert('Thumbs : ' + thumbs.length);
            
            //alert('First Image: ' + thumbs[0].src);
            for (var ii = 0; ii < thumbs.length; ii++){
              var imag = thumbs[ii];
              var link = imag.parentNode;
              
              if (link && link.tagName.toUpperCase() == 'A') {
                //alert('Adding Click : ' + link.href);
                // not needed if the server constructs the LinkURL and we add the Window size
                // this.addEvent(link, this.viewImage, 'click');
                var href = link.getAttribute('href');
                link.setAttribute('href',href + this.winSizeKeys);
                // preview and caption pop-ups are optional
                if (needMouseEvents) {        
                //if (needMouseEvents && !this.msie) {          // ***************DEBUG   // balance }
                   this.addEvent(imag, this.panelsShow, 'mouseover');
                   this.addEvent(imag, this.panelsHide, 'mouseout');
                }
              }
            }
            this.unload = this.bindEvent(window, this.bind(this, 'destroy'), 'unload');   // function ref (evtHdlr) stored for unbinding            

            if (needMouseEvents) {
              this.caption = this.captionMakeElement(this.captionId);
              //this.addEvent(this.caption, this.panelsHide,    'click');

              if (this.preview) { this.preview.makeElement(); }

//              this.addEvent(this.preview.elt, this.preview.onload, 'load');
//              if (this.opera){
//                this.preview.onloadFn = this.eventFuncs[this.nmbrEvents -1];
//              }

              //this.addEvent(this.preview.elt, this.panelsHide,  'click');
              this.toggleSuff = this.bind(this, this.preview.toggleHeightMaxOverride);
              this.addEvent(this.content, this.toggleSuff,'dblclick');
              
//              if ((this.heightMax != 'off') && (this.msie || this.opera))                                                                  // firefox has probs
//              { 
//                  alert(this.content.title);
//                  this.content.title = 'double-click to zoom flash-image to/fro full-size'; 
//                  alert(this.content.firstChild.tagName);
//                  this.content.firstChild.title = '';
//              }
               
              // alert('Links enabled: ' + this.enabled);
            }
            this.enabled = true;

          }
          catch(e){alert('Exception in Links constructor'); this.destroy(); }
        };

CSS07.gal.Links.prototype.destroy = function ()
        {
          try
          {
            for(var ii = 0; this.eventElmts && ii<this.eventElmts.length; ii++) {
              if (this.eventElmts[ii])
              {
                this.unbindEvent(this.eventElmts[ii], this.eventFuncs[ii], this.eventTypes[ii]);
                this.eventElmts[ii] = null;
                this.eventFuncs[ii] = null;
                this.eventTypes[ii] = null;
              }
            }
            if (this.toggleSuff) {
              this.unbindEvent(this.content, this.toggleSuff, 'dblclick');
              this.toggleSuff = null;
            }
            if (this.timerRef)  { window.clearTimeout(this.timerRef); }
            this.timerRef = null;
            this.unbindEvent(window, this.unload, 'unload');
            if (this.preview) { this.preview.destroy(); }
            this.preview = null;
            this.caption = null;

          }
          catch(e){} 
        };
 
CSS07.gal.Links.prototype.addEvent = function (elt, fn, evt)
        {
          try
          {
          /*
            if (this.nmbrEvents % 14 == 0 && this.msie) {
              alert('addEvent : ' + this.nmbrEvents + '  ' + elt.tagName + '  ' + evt);
            }
            */
            var bind_fn = this.bind(this,fn); 
            
            this.eventElmts[this.nmbrEvents] = elt;
            this.eventFuncs[this.nmbrEvents] = bind_fn;
            this.eventTypes[this.nmbrEvents] = evt;
            this.bindEvent(elt, bind_fn, evt);
            this.nmbrEvents++; 
          }
          catch(e){
            var msg = e.toString() + '\nElement: ' + elt.tagName + '\nEvent : ' + evt + '\n';
            alert('Exception adding Event ' + msg);} 
        };

CSS07.gal.Links.prototype.getViewportSize = function () 
{
  try 
  {
    this.winXdim = CSS07.csm.round_down(CSS07.kpl.viewportWidth ()-CSS07.gal.wdReserved, CSS07.gal.sizeIncX);
    this.winYdim = CSS07.csm.round_down(CSS07.kpl.viewportHeight()-CSS07.gal.htReserved, CSS07.gal.sizeIncY);
    this.winXdim = Math.max(this.winXdim, CSS07.gal.min_wd);
    this.winYdim = Math.max(this.winYdim, CSS07.gal.min_ht);
    //alert('&Xwin=' + this.winXdim + '&Ywin=' + this.winYdim);       
  } catch(ex) {}
};
// not used except for debugging, better to decorate the hrefs at load
CSS07.gal.Links.prototype.viewImage = function (evt)
{
  try
  {
    var vRef;       // virtual href of the existing link to the image page
    var me = CSS07.gal.getEventTarget(evt);
    
    // remove the protocol prefix if present
    var href = me.getAttribute('href');
    var pos = href.indexOf('//');
    vRef = (pos > -1) ? href.substring(pos+2, href.length) : href;
    pos = vRef.indexOf(this.qKeyE('img')); 
    if (pos < 0) { pos = vRef.indexOf(this.qKeyE('File')); }  // allow the ashx syntax
    if (pos < 0) { 
      // no imgKey found in the target URI so use the default img ViewerPage and key
      vRef = this.imgLoadURI + vRef;
    } 
    
    // Remove break tags in comments
    var reCap = /(<[^>]*\/>)|(%3C.*\/%3E)/i;
    //pos = vRef.indexOf(this.jKeyE('cap'));
    if (vRef.search(reCap) > -1) {
      //check the caption
      vRef = vRef.replace(reCap,'');
    }
    
    var comment;
    var imgID = me.getAttribute('id');
    // check for an element with a matching Id + comment extension
    if (imgID) {
      var comID =imgID  + CSS07.gal.comIDext;
      var comEl = window.document.getElementById(comID);
      if (comEl) { comment = comEl.innerHTML; }
    } else { comment = me.getAttribute('alt') || this.defComment; }
    var cap = '';
    pos = vRef.indexOf(this.jKeyE('cap'));
    
    // if there is no caption (in the href already) add one...
    if (pos < 0) { cap = this.jKeyE('cap') + me.getAttribute('title'); }

    var URL = this.imgLoadURI + vRef + cap + this.jKeyE('com') + comment + this.winSizeKeys;
              
    //alert (URL);
    //alert ('ref=' + vRef);
    
    return CSS07.csm.viewer_show(URL);
  }
  catch(e){} 
};

CSS07.gal.Links.prototype.panelsShow = function (evt)
// Event handler to show caption and img preview panels
    {
        try
        {
          /*
            alert('panelsShow fired ' + evt);
            var msg = 'panelsShow : ' + this.enabled + ' evt ' + evt;
            
            var p;
            msg += '\nEvent Properties\n';
            for (p in evt){
              msg += p + ' = ' + eval('evt.' + p) + '\n';
            }
            alert (msg);
          */
            if(!this.enabled){return;}
            var thumbnail = evt.target ? evt.target : evt.srcElement;  //need to get href image
            
            this.panelsHide();
            //window.status = 'panelsShow : ' + this.enabled;
            if (this.preview && this.preview.enabled)  { 
              // note no more dependence on having the root file name in the alt tag
              var newImgName;  // just the file part with no size suffix
              // what if its an aspx trailer? get the href of the link?
              var href = thumbnail.parentNode.getAttribute('href');
              if (href) { 
                  // href - extract image string 
                  var ff = href.match(this.imgKeyRE);
                  if (ff) { newImgName = ff[1].match(this.filePart)[0]; }
                  else    { newImgName =  href.match(this.filePart)[0]; }
              } else {
                // if the thumb can produce this event it has an image elt which matches this RE
                var imgName = thumbnail.getAttribute('src').match(this.filePart)[0];
                // if we use the thumb src to get the preview image name, remove the size suffix
                if (imgName.indexOf(this.thumb.sufx) > -1) {
                  imgName = imgName.replace(this.thumb.sufx, '');
                } 
                newImgName = imgName;
              }

              // pass the image name, target thumbnail and window height to the preview object to display
              this.preview.panelShow(newImgName, thumbnail, this.winYdim);
              this.above = !this.preview.above;  // caption setting is opposite preview setting
            }
            if (this.captionEnabled)  { this.captionShow(thumbnail); }
        }
        catch(e){
        
          alert('Exception in panelsShow : ' + thumbnail.src);
          this.enabled=false;
        }
        return false;
    };

CSS07.gal.Links.prototype.panelsHide  =  function ()
// Event handler to hide caption and img preview panels
    {
        try
        {
          //window.status = 'panelsHide : ' +this.enabled;
          this.captionHide();
          if (this.preview) {
            this.preview.hide();
          }
        }
        catch(e){
          alert('Exception in panelsHide: ' + this.preview.URL);
          this.enabled=false;
        }
        return false;
    };



CSS07.gal.Links.prototype.captionShow  =  function (thb)
    {
      try
      {
        if(this.debugCap > 1) {
          return;
        }
        var cpn       = this.caption;
        var cpnClear  = CSS07.gal.captionClearance; 

        var thbWidth  = thb.offsetWidth;
        var thbHeight = thb.offsetHeight; 
        var cpnText   = thb.getAttribute('alt'); 
        if (cpnText === undefined) { cpnText   = thb.textContent; }
        var readRateCPS  = CSS07.gal.captionReadSpeedCPS; 
        var minimum_secs = CSS07.gal.captionShowMinimum; 
        var display_secs;

        cpn.firstChild.firstChild.data = cpnText; 

        var cpnWidth  = cpn.offsetWidth;
        var cpnHeight = cpn.offsetHeight;
        var cpnLeft   = CSS07.kpl.domLeftToBody(thb) - Math.round((cpnWidth - thbWidth) / 2);
        var cpnTop    = CSS07.kpl.domTopToBody(thb);
        if (this.above)
        {  cpnTop -= (cpnClear + cpnHeight); }
        else
        {  cpnTop += (cpnClear + thbHeight); }
        cpn.style.top  = cpnTop  + 'px';
        cpn.style.left = cpnLeft + 'px';
        cpn.style.visibility = 'visible';
        
        display_secs = cpnText.length / readRateCPS;
        if (display_secs < minimum_secs)  { display_secs = minimum_secs; }
        if ( this.timerRefCaption) { window.clearTimeout(this.timerRefCaption); }
        if (!this.captionHideInst) { this.captionHideInst= this.bind(this, this.captionHide); }
        var p;
        var ii = 0;
        /*
        var msg= 'Caption properties\n';
        for (p in cpn) {
           ii++;
           msg += p + ' = ' + eval('cpn.' + p + (p.type == 'function' ? '()' : '')) + '\t\t';     
           if((ii%3) { == 0) msg += '\n'; }
        }
        var msg= 'Caption style properties\n';
           msg += 'top        = ' + CSS07.kpl.getStyle(cpn, 'top'    , 'top') + '\t\t';     
           msg += 'left       = ' + CSS07.kpl.getStyle(cpn, 'left'    , 'left') + '\t\n';     
           msg += 'width      = ' + CSS07.kpl.getStyle(cpn, 'width'    , 'width') + '\t\t';     
           msg += 'height     = ' + CSS07.kpl.getStyle(cpn, 'height'   , 'height') + '\t\n';     
           msg += 'display    = ' + CSS07.kpl.getStyle(cpn, 'display'  , 'display') + '\t\t';     
           msg += 'visibility = ' + CSS07.kpl.getStyle(cpn, 'visibility', 'visibility') + '\t\t';     

        if (this.msie) { alert(msg); }
        */
        // alert('Display Secs caption = ' + display_secs);
        this.timerRefCaption = window.setTimeout(this.captionHideInst, Math.round(display_secs * 1000));
        this.debugCap += 1;

      }
      catch (e) 
      {
        alert('Exception in Caption Show');
      }
    };

CSS07.gal.Links.prototype.captionHide = function()  
    { 
       this.caption.style.visibility = 'hidden'; 
       if (this.debugCap >1) { this.debugCap -= 1; }

    };
    
CSS07.gal.Links.prototype.captionMakeElement  =  function (id)
    {
      try 
      {
        var div, spn, dso;
        if (this.debugCap > 0) { 
          div = window.document.getElementById(this.captionId);
          if (div) { alert('2 Captions'); }
          return div;
        }
        div = window.document.createElement('div');
        div.id         = id;
        dso = div.style;
        dso.position   = 'absolute';
        dso.left       = '1px';
        dso.top        = '1px';
        dso.zIndex     = CSS07.gal.zIndex +1;
        dso.width      = CSS07.gal.captionWidth + 'px';                                                                   
        dso.height     = '';                                                           // !important
        dso.visibility = 'hidden';
        //dso.display    = 'block';
        
        spn = window.document.createElement('span');                                   // see css font-sizing
        spn.appendChild(window.document.createTextNode(''));
        div.appendChild(spn);
        
        if (true || this.msie) { window.document.body.appendChild(div); }  // IE quirks! not visible in a table!
        else { this.content.appendChild(div); }
        this.debugCap += 1;
        return div;
      }
      catch (e) {
        alert('Exception in Caption makeElement');
      }
    };


/*
CSS07.gal.Links.prototype.viewerShow  =  function (evt)
    {
        try
        {
            if(!this.enabled){return;}
            var link             = evt.target;
            var thumb            = link.firstChild;
            var SEARCH_FAILED    = -1;
            var FILE_EXT_JPG     = /\.jpg$/i;
            var FILE_EXT_GIF     = /\.gif$/i;
            var vwrURL           = me.VIEWER_PAGE_URL;
            
            var tmbCaption, urlQuery;
            
            var href   = link.href;
            var notJPG = (href.search(FILE_EXT_JPG) == SEARCH_FAILED);  
            var notGIF = (href.search(FILE_EXT_GIF) == SEARCH_FAILED);  
            if (notJPG && notGIF)  { return; }

            tmbCaption = window.encodeURIComponent(thumb.alt);
            urlQuery   = vwrURL + CSS07.gal.keyImg  + href         + ',' +  
                                  CSS07.gal.jKeyE('cap')  + tmbCaption   + ',' +
                                  CSS07.gal.showMin + CSS07.gal.captionShowMinimum;
            alert (urlQuery);
            window.setTimeout('window.location.href="' + urlQuery + '"', CSS07.gal.waitTimeMS);
            
            return false;                                                              // cancel link-action
        }
        catch(e){kpl_overview.enabled=false;}
    };
*/

/* Generic tools for gallery & filmstrip */
CSS07.gal.qChar   = '?';
CSS07.gal.jChar   = '&';

CSS07.gal.filKey  = 'File=';
CSS07.gal.widKey  = 'Width=';
CSS07.gal.hgtKey  = 'Height=';
CSS07.gal.loadMsg = 'Image Loading...';
CSS07.gal.helpText  = 'Click to return to previous page...';
CSS07.gal.priorPage = -1;

// TODO : generic dynamic loader based on size of the image window (for Shift-clickers - ctrl-click is OK)

CSS07.gal.makePreviewPane   = function (div_ID, img_ID, anc_ID, cap_ID, cap_tag)
  // generic popup? pane with load msg needs to be in a div and maybe have an anchor around
  // div may exist
        {
          var div, img, cap, anchor, container, popup;
          // can pass in the parent object
          if (typeof div_ID == 'string') {
            div = window.document.getElementById(div_ID);
          } else {
            div = div_ID;
          }
          if (!div) { 
            // make it and give it default postioning
            div = CSS07.csm.makeElement(null, 'div', div_ID, null, false); 
            var iso = div.style;
            iso.position   = 'absolute';
            iso.left       = '1px';
            iso.top        = '1px';
            iso.zIndex     = CSS07.gal.zIndex;
            iso.width      = '';                                                                    
            iso.height     = '';
          }
          
          if (anc_ID) { 
            container = CSS07.csm.makeElement(div, 'a', anc_ID, null, true); 
          } else { container = div; }
          
          img = CSS07.csm.makeElement(container, 'img', img_ID, null, true);
          
          // don't really need a caption on a preview, if we do it should be in the anchor? can be a loading sign
          if (cap_ID) {
            CSS07.csm.makeTextElement(container, cap_tag || 'span', cap_ID, CSS07.gal.loadMsg, true, 11);
          }

          window.document.body.appendChild(div);
          
          return div;
          
     };
     
CSS07.gal.makeLoadingSign   = function (parentElt, div_ID, cap_ID, tag, zindex)
  // text in a div under a parent element, div may exist, for in-situ preview screen
        {
          var div, cap;
        
          div = window.document.getElementById(div_ID);
          if (!div) { div = CSS07.csm.makeElement(parentElt, 'div', div_ID, null, false); }
                    
          CSS07.csm.makeTextElement(div, tag, cap_ID, CSS07.gal.loadMsg, null, zindex || 11);
          return div;
     };

CSS07.gal.previousPage = function () 
      {
        window.history.go(CSS07.gal.priorPage);
      };


CSS07.gal.gotoLink = function(evt)
       {
         var elt = CSS07.gal.getEventTarget(evt);
         if (elt) {
           window.location = elt.getAttribute('href');
         }
       }

CSS07.gal.ImageLoader = function (img_ID,      // CLASS CONSTRUCTOR  / one shot image loader with wait msg
                                  img_URI,     // rooted path to the image
                                  cap_ID,      // caption/ load message / created if not found
                                  capText)     // text for Caption once loaded
        {
          try
          {
            if (!(this instanceof CSS07.gal.ImageLoader ))             { return null; }          // constructor was CALLed as a function
            
 
            CSS07.kpl.Encapsulator.call(this);  // 'inherit'   Encapsulator's functions
            CSS07.gal.Browsers.call(this);      // 'inherit'   Browser's functions
            
            this.imgElt = window.document.getElementById(img_ID);
            
            this.imgPre = null;
            this.onPreload = null;
            this.activeHandler = (img_URI.indexOf(".ashx") > -1);
            var htArg = CSS07.csm.extractValue(img_URI, CSS07.gal.hgtKey, CSS07.gal.jChar);
            if (htArg && htArg.length > 0) {
              this.requestHeight = htArg;
              if (!this.activeHandler) { img_URI = img_URI.substr(0,img_URI.indexOf(CSS07.gal.jChar + CSS07.gal.hgtKey)); }
            }
            var wdArg = CSS07.csm.extractValue(img_URI, CSS07.gal.widKey, CSS07.gal.jChar);
            if (wdArg && wdArg.length > 0) {
              this.requestWidth = wdArg;
              if (!this.activeHandler) { img_URI = img_URI.substr(0,img_URI.indexOf(CSS07.gal.jChar + CSS07.gal.widKey)); }
            }
            // var msg ='req h= ' + this.requestHeight + '\n';
            // msg   += 'req w= ' + this.requestWidth + '\n';
            // alert(msg);
            
            this.onClick = this.bindEvent(window.document.body, CSS07.gal.previousPage, 'click');
            this.unload = this.bindEvent(window, this.bind(this, 'destroy'), 'unload');   // function ref (evtHdlr) stored for unbinding
            window.status = CSS07.gal.helpText;

            if(this.imgElt && img_URI) {
              this.onPreload = this.startPreload(img_URI, this.msie);
            }
            this.caption  = window.document.getElementById(cap_ID);
            this.loadMsg = CSS07.gal.loadMsg;
            this.comment = capText;
            if (this.caption) {
              this.caption.innerHTML = this.loadMsg;
            } else {
              this.caption = CSS07.csm.makeTextElement(this.imgElt.parentNode, 'h3', cap_ID, this.loadMsg);
            }
            if (this.caption) {  this.caption.style.visibility = 'visible'; }
            
            // Click to return 

          }
          catch(e){} 
        };
        
CSS07.gal.ImageLoader.prototype.destroy = function()
        {
          try {
            this.unbindEvent(window.document.body, this.onClick, 'click');
            this.onClick = null; 
            this.unbindEvent(window, this.unload, 'unload');
            this.unload = null
            if (this.onPreload && this.imgPre) { 
              this.unbindEvent(this.imgPre, this.onPreload, 'load') 
            };
            this.onPreload = null;
            this.caption = null;
            this.imgElt = null;
            this.imgPRe = null;
          }
          catch(e) {}
        };
        
CSS07.gal.ImageLoader.prototype.check_fit = function ()
        {
          try
          {
            var maxHgt = this.imgElt.height;
            /*
            var msg ='elt h= ' + this.imgElt.height + '\n';
             
            msg   += 'elt w= ' + this.imgElt.width + '\n';
            msg   += 'req h= ' + this.requestHeight + '\n';
            msg   += 'req w= ' + this.requestWidth + '\n';
             
            alert(msg);
            */
            
            if (this.requestHeight && this.imgElt.height > 0 + this.requestHeight) {
              maxHgt = parseInt(this.requestHeight);
            }
            if (maxHgt === 0 || this.imgPre.height < maxHgt) {
              maxHgt = this.imgPre.height;
            }
            var maxWid = this.imgElt.width;
            if (this.requestWidth && this.imgElt.width > 0 + this.requestWidth) {
              maxWid = parseInt(this.requestWidth);
            }
            if (maxWid === 0 || this.imgPre.width < maxWid) {
              maxWid = this.imgPre.height;
            }
            
            var aspect = this.imgPre.width/this.imgPre.height;
            if (((maxWid/maxHgt) - aspect) > 0.005) {
              maxWid = maxHgt*aspect;
            } else if (((maxWid/maxHgt) - aspect) < -0.005) {
              maxHgt = maxWid*aspect;
            }
            //alert('wid = ' + maxWid +', hgt =' +maxHgt);
            if (this.imgElt.width != maxWid) {
              this.imgElt.width = maxWid;
            }
            if (this.imgElt.height != maxHgt) {
              this.imgElt.height = maxHgt;
            }
          }
          
          catch(e) {}
        };
        

CSS07.gal.ImageLoader.prototype.load = function ()
        {
          try
          {
            //window.status = 'Load Fired: ' + this.requestHeight;
            if (this.imgPre) {
              // remove attributes put on by firefox
              this.imgElt.setAttribute('height', null);
              this.imgElt.setAttribute('width', null);
              this.imgElt.setAttribute('src', this.imgPre.getAttribute('src'));
              // Catch an image > requested size and re-size in browser
              this.check_fit();
              /*
              if (this.requestHeight && this.imgElt.height > 0 + this.requestHeight) {
                this.imgElt.height = this.requestHeight;
                //window.status = 'Setting Height: ' + this.requestHeight;
              } else this.imgElt.height = this.imgPre.height;
              if (this.requestWidth && this.imgElt.width > 0 + this.requestWidth) {
                this.imgElt.width = this.requestWidth;
              } else this.imgElt.width = this.imgPre.width;
              */
              this.imgElt.style.visibility = 'visible'
            }
            if (this.comment) { 
              this.caption.innerHTML = this.comment; 
            } else { this.caption.style.visibility = 'hidden'; }
            
            //if (this.onPreload) { this.unbindEvent(this.imgPre, this.onPreload, 'load') };
            this.imgPre = null;
            this.imgElt = null;
            this.onPreload = null;
          }
          catch(e){} 
        };

CSS07.gal.ImageLoader.prototype.startPreload = function (img_URI, inDom)
        {
          try
          {
            // undecorate any previous preload image
            if (this.onPreload) { 
              this.unbindEvent(img, this.onPreload, 'load');
              if(inDom) { window.document.body.removeChild(img); }
              this.onPreload = null;
            }
            if (this.imgPre) { this.imgPre.setAttribute('src', null); }

            // now start afresh
            this.imgPre = new Image();
            //  IE (7) load event only passes the event data if the img is in the DOM!!
            //  and Opera returns 0 for the image width if diplay is set to none!
            if (inDom) {
              window.document.body.appendChild(this.imgPre);
              this.imgPre.style.display = 'none';
            }
            //alert('Binding OnPreload');
            //window.status = 'Binding Preload';
            onPreload = this.bindEvent(this.imgPre, this.bind(this, this.load), 'load');
            this.imgPre.setAttribute('src', img_URI);
            
          } catch(e){
            alert (e.message);
          }
        };


}
catch(e) {}

