var sFXProg = "fxHeader.js";
var sFXVers = "20120111";
/*
 *  Adapted from fxHeader_0.6.js by original author Jaimon Mathew www.jaimon.co.uk
 *  Please see http://jaimonmathew.wordpress.com/2010/03/19/making-scrollable-tables-with-fixed-headers-updated-2/
 *
 *  Assumptions: 1) table will have at least 1 frozen row header column and 1 column header row
 *               2) frozen column header row(s) are defined in thead tag
 *               3) will attempt to maximize grid in viewable screen space
 */
//Version history:
//----------------
//20120111: modify so only save col widths to cookie if user manually changed col widths
//20111116: change 'Loading' box to say 'Formatting...' when running formatting code
//20110718: fix bug re bottom of grid being cut off; tune down 1 column width calc when drilling
//20110715: adjust autosizing and implement new algorithm for overriding manual col sizes when drilling up/down
//20110707: tweak to make auto-sizing a little more granular
//20110701: significant performance tweaks
//20110626: added three performance tweaks and fix for drilldown sizing issue when not actually drilling down
//20110625: Increase width of draggable by 50%; modify saveColWidths to set css vals in addition to hash vals;
//          minor tweaks to improve getAdjustedCellHeight
//20110624: Tweak to fix drilldown tbl width
//20110623: Major upgrade involving feature addition of auto- and user- sizing of column widths
//20110513: Moved getVPSize to rpFunctions since now used outside just this context
//20110510: Change fxheaderResize to better address stream of resize events
//20110509: Mods to improve precision of use of nowrap, handle refresh event less frequently, and scrollbar use when
//          addition of one scrollbar affects the necessity of the other
//20110505: Significant update in an effort to fix issues with column alignment, zoom inconsistencies, and table drop
//20110328: Temporarily removed "loading"; addressed IE incompatibility issues
//20110323: Added "loading" before and after in case of slow refreshes
//20110318: Fix so frozen panes are outlined to right and bottom with fixed border; externalized determination of
//          viewport size so it can be used in multiple places; implement ability to resize and have grid dynamically 
//          change size
(function() {
   var tbls=$A();                                          //handles > 1 scroll table on the page
   var scrollbarWidth = 0;                                 //since this is expensive to calculate, calc once and store at top lvl
   var tblResizeTimer = null;                              //used to manage many refresh requests at a time

//-----------------------------------------------------------

   this.scrollHeader = function(evt) {
   // Purpose:   Manages the scroll event by scrolling row and column header divs along with the data
   // Arguments: evt: the event captured

      var t = Event.findElement(evt);                      //bubble up through dom objects to find element where event occured 
      var tid = t.identify().replace(':scroller','');      //strip off :scroller from table id
      hideMenu();                                          //if any popup menus open, close them to keep alignment correct
      adjustScrollTblHeaders(tid);                         //adjust the table up/down and left/right based on tbl scroll event
   };//scrollHeader

//-----------------------------------------------------------

   function addScrollerDivs(tid, noOfCols) {
   // Purpose:   Initial setup of superimposed scrolling row and column header elements
   // Arguments: tid: id attribute of table upon which to act
   //            noOfCols: the number of columns frozen in the column header

      if($(tid+':scroller')) { return; }                   //if setup already done, don't bother doing it again

      var tParent = $(tid).up();                           //grab table's parent element
      var tSibling = $(tid).next();                        //grab orig table's next sibling element

      //create a div and insert orig table into it
      var sd = new Element('div', {'id': tid+':scroller'}).setStyle({'height':'auto', 'width':'auto'});
      sd.insert({'bottom': $(tid)});

      //create a div that represents viewable frozen column header row area
      var sd2 = new Element('div', {'id': tid+':scroller:fx:OuterDiv'})
                    .setStyle({'position':'relative', 'width':'auto', 'overflow':'hidden', 
                               'overflowX':'hidden', 'padding':'0px', 'margin':'0px'});
        
      //create a div that represents full frozen column header row area - viewable and non-viewable - and add to viewable frozen column header row area
      sd2.insert({'bottom': new Element('div', {'id': tid + ':scroller:fx'})
                                .setStyle({'textAlign':'left', 'position':'relative', 'padding':'0px', 
                                           'marginLeft':'0px', 'width':'auto'}) });
      
      var fc = null;
      if (noOfCols > 0) {                                  //if there are one or more frozen row header columns...
         //create a div that represents the full frozen row header column area
         fc = new Element('div', {'id': tid+':scroller:fxcol'}).setStyle({'width':'0px', 'height':'auto', 'display':'block', 
                                                                          'float':'left', 'overflow':'hidden' });

         //create a div for each of the frozen row header column areas - col header (top corner) and bottom - and insert into full frozen row header column area
         fc.insert({'bottom': new Element('div', {'id': tid+':scroller:fxCH'}).setStyle({'width':'auto', 'overflow':'hidden'}) });
         fc.insert({'bottom': new Element('div', {'id': tid+':scroller:fxCB'}).setStyle({'width':'auto', 'overflow':'hidden'}) });
      } //if one or more frozen rown header columns

      //put it all together
      if(tSibling) {                                       //if orig table's next sibling exists
         if(fc) tSibling.insert({'before': fc});           //if frozen row columns, insert before next sibling
         tSibling.insert({'before': sd2});                 //insert frozen col header before next sibling
         tSibling.insert({'before': sd});                  //insert orig table div before next sibling
      } else {                                             //if orig table has no next sibling
         if(fc) tParent.insert({'bottom': fc});            //if frozen row columns, insert in parent after orig table
         tParent.insert({'bottom': sd2});                  //insert frozen col header in parent after orig table
         tParent.insert({'bottom': sd});                   //insert orig table div in parent after orig table
      }
      Event.observe($(tid+':scroller'), 'scroll', scrollHeader); //register scroll event on orig table div
   }//addScrollerDivs

//-----------------------------------------------------------

   this.fxheader = function() {
   // Purpose:   Setup and resize refresh of superimposed scrolling row and column header elements
      $('loading').update('Formatting...');

      var activeTab = $('report_content').getElementsByClassName('activeTab')[0]; //only one tab active at a time, if at all
      if ($('grid') == undefined || ($('grid') && activeTab.id == 'grid')) { //only proceed if grid actually viewable
         var vpSize = getVPSize();                         //get viewport dimensions in case of resize
         for(var i = 0; i < tbls.length; i++) {            //for each of potentially more than one table on the page
            var tbl = getOrigTblInfo(tbls[i], vpSize);     //grab table from array of page tables; get orig tbl info
            var tOrigId = tbl.get('tid');                  //get id of original table for sake of brevity throughout method

            //clean up children for full frozen col header row area, frozen col header and col bottom headers
            [':scroller:fx', ':scroller:fxCH', ':scroller:fxCB'].each(function(eName) {
               $(tOrigId+eName).childElements().each(function(childNode) {  //for all children of aforementioned nodes
                  childNode.remove();                      //remove all children
               });
            });

            tbl = adjustCols(tbl);                         //adjust col widths to retain consistency
            tbls[i] = tbl;                                 //save changes back to array

            //determine the width of screen to work with and offsets for scrollbars if necessary
            var wOffset = (tbl.get('origHeight') > vpSize.get('vpHeight')) ? scrollbarWidth : 0;  //determine width offset for vertical slider
            var hOffset = (tbl.get('origWidth') > vpSize.get('vpWidth')) ? scrollbarWidth : 0;  //determine height offset for horizontal slider
            var w = (vpSize.get('vpWidth') - wOffset > tbl.get('origWidth')) ? tbl.get('origWidth') : (vpSize.get('vpWidth') - wOffset);          //grab configured width of usable screen and offset; will expand to fill full width
            var h = (vpSize.get('vpHeight') - hOffset > tbl.get('origHeight')) ? tbl.get('origHeight') : (vpSize.get('vpHeight') - hOffset);         //get height of usable screen and offset

            //address potential for adding a scroll bar affecting the height or width being displayed
            if (wOffset == 0 && hOffset > 0 && 
                (tbl.get('origHeight')>h && (tbl.get('origHeight')-h) <= scrollbarWidth)) {
               wOffset = scrollbarWidth;
               w -= wOffset;
            }
            if (hOffset == 0 && wOffset > 0 && 
                (tbl.get('origWidth')>w && (tbl.get('origWidth')-w) <= scrollbarWidth)) {
               hOffset = scrollbarWidth;
               h -= hOffset;
            }
            
            //populate frozen col header rows element and add to scroller
            var extDragSpace = vpSize.get('vpWidth')-tbl.get('origWidth'); //calc space available for rightmost col drag to expand
            if (extDragSpace < 0) { extDragSpace = wOffset; } //if not enough space, reset to scrollbar width, if any
            var colHeaderRows = $(tOrigId).clone(true).writeAttribute('id', tOrigId+'__cN');  //copy original table resulting in a table shell definition
            colHeaderRows.setStyle({'marginTop': '0px', 'marginLeft': '0px'})  //set width to that of original table
            $(tOrigId+':scroller:fx').insert({'bottom': colHeaderRows});  //add table shell (containing full frozen col header rows) to scroller

            //populate frozen top left corner and add to scroller (assumption that there is at least one frozen row header col)
            var topLeftCorner = colHeaderRows.clone(true).writeAttribute('id', tOrigId+'_CFH');  //create a copy of col header rows shell to manage row header cols
            $(tOrigId+':scroller:fxCH').insert({'bottom': topLeftCorner});  //insert frozen col header clone to scroller div - NOT SURE ABOUT THIS ONE

            //populate frozen row header cols and add to scroller (assumption that there is at least one frozen row hearder col)
            var rowHeaderCols = $(tOrigId).clone(true).writeAttribute('id', tOrigId+'_CFB');  //create a full clone of orig table
            rowHeaderCols.setStyle({'marginLeft': '0px'});    //set clone left margin to 0
            $(tOrigId+':scroller:fxCB').insert({'bottom': rowHeaderCols});  //add full table clone to scroller:fxCB

            addDraggableExtensionElements(tbl, extDragSpace); //add right-most col resizing extension

            //determine width of row header cols in orig table and shift left/or set width accordingly
            var colWidth = getFrozenRowHeaderColWidth(tbl); //calc total width of all frozen row header cols
            $(tOrigId+':scroller:fx').setStyle({'marginLeft': (0-colWidth-2)+'px'});  //shift marginleft of full frozen col header row area
            $(tOrigId+':scroller:fxcol').setStyle({'width': (colWidth+2)+'px'});  //set width of row header col scroller

            //determine height of col header rows and shift up or set height accordingly
            var tHeight = ($(tOrigId).select('thead')[0]).getHeight();  //save the cumulative row height of frozen col header rows
            $(tOrigId).setStyle({'marginTop': (0-tHeight-2)+'px', 'marginLeft': (0-colWidth-2)+'px'});  //shift margintop of orig table to 0-total height of all frozen col headers rows
            $(tOrigId+':scroller:fxCH').setStyle({'height': (tHeight+2)+'px'});  //set height of top corner - frozen row/col header - to total height of all frozen col header rows in orig table
            $(tOrigId+':scroller:fxCB').setStyle({'height': (((h-tHeight)<0)?0:(h-tHeight))+'px'});  //set height of bottom part of frozen row header col - to total allowable screen height - total height for all frozen col header rows
        
            //final adjustments to scroller containers to apply scroll bars and space appropriately
            w -= colWidth;                                    //adjust width to full usable screen width - total frozen row header col width
            $(tOrigId+':scroller').setStyle({'width': (w+wOffset)+'px', 'height': (((h+hOffset-tHeight-2)<0)?0:(h+hOffset-tHeight-2))+'px',
                                             'overflowX':(hOffset>0)?'scroll':'hidden', 'overflowY':(wOffset>0)?'scroll':'hidden'});
            $(tOrigId+':scroller:fx:OuterDiv').setStyle({'width': (w+extDragSpace)+'px', 'height': (tHeight+2)+'px'});  //assign width and height to viewable col header scroller

            registerDraggables(tbl);                       //register col header width draggable capability
            adjustScrollTblHeaders(tOrigId);               //re-check scroll alignment between col/row headers and data grid
            if (existColWidthOverrides(tbl)) { setRptCookies(tbl); } //save user-modified col changes to restore when col sort or drill
         } //for each of potentially more than one table on the page
         restoreScrollTableEvents();                       //reapply saved events registrations to new cloned elements
      }//if table displayed
   } //fxheader

//-----------------------------------------------------------

   this.fxheaderInit = function(_tid, _noOfCols) {
   // Purpose:   Handle general config on a per-table basis
   // Arguments: _tid: id of table to configure
   //            _noOfCols: number of row header cols to freeze
    
      //determine number of column header rows to freeze
      var _noOfRows = 1;                                   //default to 1 frozen col header row
      var cornerCell = $(_tid).select('thead > tr > td:nth(0)');
      if (cornerCell.first().empty()) {
         _noOfRows += 1;
      }

      scrollbarWidth = (scrollbarWidth > 0) ? scrollbarWidth : getScrollbarWidth();  //get and store scrollbarWidth for reference
      addScrollerDivs(_tid, _noOfCols);                    //set up table with appropriate scroller divs

      //store config in array of tables for later reference
      tbls[tbls.size()] = $H({tid: _tid, noOfRows: _noOfRows, noOfCols: _noOfCols, origWidth: 0, origHeight: 0});

      saveScrollTableEvents();                             //save event registrations for existing table elements
   }; //fxheaderInit
   
//-----------------------------------------------------------

   this.fxheaderClean = function() {
   // Purpose:   Clean out table array; should be done for each new page
      tbls.clear();
   }; //fxheaderClean

//-----------------------------------------------------------

   function adjustCols(t) {
   // Purpose:   Apply any col width chages that may have been made due to dragging col header widths, etc
   // Arguments: t: hash table of table characteristics

      var w, adjList, adjDiv, adjA;
      var cellHeight = getAdjustedCellHeight(t);           //height of most granular row of frozen col header row cells
      adjList = $(t.get('tid')).select('thead > tr:nth(' + (t.get('noOfRows')-1) + ') > td'); // cells in most granular row of frozen col header row
      adjList.each(function(cell) {                        //for each cell in frozen col header row
         //adjust draggable 'adjust' div id and parent's height
         adjDiv = cell.select('div[id*=adjust]')[0];       //there will only be 1 adjustable div per cell
         adjDiv.parentNode.setStyle({ 'height':cellHeight + 'px' }); //set containing div's height

         //adjust clickable sort text 'center' positioning due to 'position:absolute' requirement
         w = t.get('colWidths').get(cell.cellIndex);       //retrieve previously saved default size
         adjA = cell.select('[id*=sort]')[0];              //there MAY only be 1 click to sort link
         if (adjA != undefined) {                          //sort link doesn't always exist
            if (adjA.getStyle('text-align') == 'center') { //adjust to be centered in position absolute
               adjA.setStyle({ 'position':'absolute','bottom':'0','left':'50%','display':'block',
                               'width':w+'px','margin':'0px -'+(w/2)+'px' });
            } else {
               adjA.setStyle({ 'position':'absolute','bottom':'0' }); //adjust to bottom
            } //if supposed to be centered
         } //if link exists

         //adjust last column draggable extension look and position
         if (cell.cellIndex < (adjList.size()-1)) {        //if not last column, set draggable handles
            adjDiv.setStyle({ 'width':'3px','cursor':'col-resize','height':cellHeight + 'px' }); //set look of draggable div
         }
      }); //each cell
      
      //adjust and save table height based on potential column width changes
      var h = t.unset('origHeight');
      h = $(t.get('tid')).getHeight();
      t.set('origHeight',h);
      return t;
   } //adjustCols

//-----------------------------------------------------------

   function saveColWidths(t) {
   // Purpose:   Iterate through the columns in a table and save the column widths
   //            Only save most granular level of col header rows
   //            Set tbl cell dimensions along the way
   // Arguments: t  - a hash table of table configurations
   // Returns:   Array (each frozen row of col headers is an array element) of hash tables indexed on col index
      var id = t.get('tid');                               //id of the table
      var w;
      var tot = 0;
      var colWidthsRow = $H();                             //hash to return
      var tdList = $(id).select('thead > tr:nth('+(t.get('noOfRows')-1)+') > td'); //get cells in most granular frozen col header row
      tdList.each(function(cell) {                         //for each cell in most granular frozen col header row
         w = cell.getWidth();
         colWidthsRow.set(cell.cellIndex, w); //save width keyed by cell index
         tot += (w+6);                                     //add to account for padding and border widths
         cell.setStyle({'width': w + 'px'});               //adjust col width
      }); //each cell in most granula frozen col header row
      $(id).setStyle({'width': tot + 'px'});               //adjust tbl size for each col before col width chg
      return colWidthsRow;                                 //return hash of frozen col header row cells
   }//saveColWidths

//-----------------------------------------------------------

   function getScrollbarWidth() { 
   // Purpose:   Calculate the width of a browser scroll bar
   //            Note that this doesn't currently work in all browsers and relies on a default value in those 
   //            cases since, as it turns out, the default was not error prone in those browsers anyway
   // Returns:   the scrollbar width
      var oDiv = new Element('div', {'id':'odiv'}).setStyle({'width':'50px', 'height':'50px', 
                                                             'overflow':'hidden', 'position':'absolute', 
                                                             'top':'-200px', 'left':'-200px'});
      oDiv.insert({'bottom': new Element('div', {'id':'idiv'}).setStyle({'height':'100px'}) });
      $('page').insert({'bottom': oDiv});
      var w1 = $('idiv').getWidth();
      $('odiv').setStyle({'overflow':'scroll'});
      var w2 = $('idiv').getWidth();
      $('odiv').remove();
      return ((w1-w2) <= 0) ? 18 : (w1-w2);
   }//getScrollbarWidth
   
//-----------------------------------------------------------

   function getOrigTblInfo(tbl, vpSize) { 
   // Purpose:   Check the original tbl size info and set or restore if previously cookied
   // Arguments: tbl - the characteristics of the specific table
   //            vpSize - viewport size object of dimensions
   // Returns:   new hash table with original and/or new tbl size info set
      var colWidths = tbl.get('colWidths');                //get col width values from table object
      var minColWidths = null;                             //hash of min col width sizes
      var colWidthOverrides = null;                        //hash of indicators indicating per col manual width overrides
      var chkDrilldownAdjustment = false;                  //set if potential adjustment due to drilldown
      var currHeight = $(tbl.get('tid')).select('tr').size(); //get number of rows in table

      //determine col widths, accounting for previously-config'd sizes, min sizes, and cookie'd sizes
      if (colWidths == undefined) {
         //get previously stored info, if any
         makeCookies();                                    //create cookie element for this report
         minColWidths      = $H(Cookie.getData('minColWidths'));
         colWidthOverrides = $H(Cookie.getData('colWidthOverrides'));
         colWidths         = $H(Cookie.getData('colWidths'));
         var prevHeight    = parseInt(Cookie.getData('tblHeight'));

         if (minColWidths == undefined || minColWidths.keys().length == 0 ||
           currHeight != prevHeight) {                      //if no col width data previously saved OR drill up/down
            $(tbl.get('tid')).writeAttribute('width','1%'); //reset table to smallest size to get min col widths
            minColWidths = saveColWidths(tbl);             //save min col widths
         }
         if (minColWidths == undefined || minColWidths.keys().length == 0) { //if no col width data previously saved
            colWidthOverrides = $H();                      //default overrides to none/empty
         } else {
            if (currHeight != prevHeight) { chkDrilldownAdjustment = true; } //if not same, did drill up/down
         }
         //adjust col widths if still at min width and some space to play with, given overrides, etc
         colWidths = adjustMinColWidths(minColWidths, colWidths, colWidthOverrides, chkDrilldownAdjustment, vpSize); 
       }

      //iterate through col widths to cumulate total width of all cols
      var totWidth = 0;
      colWidths.each(function(pair) {
         totWidth += (pair.value+6);                       //add 6 to account for cell padding and borders
      });

      //rebuild table info object to be returned
      $(tbl.get('tid')).writeAttribute('width','');        //wipe out previously set min width HTML value
      $(tbl.get('tid')).setStyle({'width':totWidth + 'px'}); //set CSS width value

      var newTbl = $H({'tid': tbl.get('tid'), 
                       'noOfRows': tbl.get('noOfRows'), 
                       'noOfCols': tbl.get('noOfCols'), 
                       'origWidth': totWidth, 
                       'origHeight': $(tbl.get('tid')).getHeight(),
                       'colWidths': colWidths,
                       'colWidthOverrides': (colWidthOverrides == null)?tbl.get('colWidthOverrides'):colWidthOverrides,
                       'minColWidths': (minColWidths == null)?tbl.get('minColWidths'):minColWidths
                     });
      Cookie.setData('tblHeight', currHeight);        //save for comparison after drilldown/up
      return newTbl;                                       //return new hash of table info
   }//getOrigTblInfo

//-----------------------------------------------------------

   function adjustScrollTblHeaders(tbl) { 
   // Purpose:   Move the row header cols and col header rows in conjunction with data grid scrolling
   // Arguments: tbl - the id of the table

      var offsetAmt = $(tbl+':scroller').cumulativeScrollOffset();
      //move col header rows to the left/right based on scroll offset amount
      $(tbl+':scroller:fx').setStyle({'left': (0-offsetAmt[0])+'px'});  

      //move row header cols up/down based on scroll offset and frozen col header row(s) height
      var newMarginTop = 0 - offsetAmt[1] + parseInt($(tbl).getStyle('marginTop'));
      $(tbl+'_CFB').setStyle({'marginTop': newMarginTop + 'px'}); 
   }//adjustScrollTblHeaders
   
//-----------------------------------------------------------

   function getFrozenRowHeaderColWidth(t) {
   // Purpose:   Determine the cumulative width of the frozen row header cols
   // Arguments: t  - a hash table of current table attributes
   // Returns:   Width in pixels of all frozen row header cols
      var colWidths = t.get('colWidths');                  //get col widths object from table object
      var cumColWidth = 0;
      for (var j = 0; j < t.get('noOfCols'); j++) {        //for each row header col
         cumColWidth += (colWidths.get(j)+6);
      }
      return cumColWidth;                                  //return total of frozen row header col widths
   }//getFrozenRowHeaderColWidth

//-----------------------------------------------------------

   this.fxheaderResize = function() { 
   // Purpose:  Catch and regulate calls to resize.  If processing currently happening, ignore the event;
   //           Otherwise, wait a second and process
      if (tblResizeTimer != null) {
         clearTimeout(tblResizeTimer);
         tblResizeTimer = null;
      }
      displayLoadingMgr(true,true);
      tblResizeTimer = setTimeout('fxheader()', 300);
      displayLoadingMgr(false, true);
   }//fxheaderResize
   
//-----------------------------------------------------------

   function registerDraggables(t) {
   // Purpose:  for each cell in most granular frozen col header row, register div as a draggable object for col resizing
   // Arguments: t  - a hash table of current table attributes
      var newId = "";                                      //unique id for div
      var counter;                                         //used to determine if last col
      var dragHandle;                                      //visual item associated with drag
      var tOrigId = t.get('tid');                          //get id of original table for sake of brevity throughout method
      [tOrigId+'_CFH', tOrigId+'__cN'].each(function(name) { //for each table that contains user-accessible frozen col header row
         counter = 0;
         var adjList = $(name).select('div[id*=adjust]'); //get 'adjust' divs in each cell in table
         adjList.each(function(e) {                        //for each 'adjust' div
            counter += 1;                                  //count col
            newId = name + '_' + e.id.substr(e.id.length-8); //create unique id
            e.id = newId;                                  //rename div element
            if (counter == adjList.size()) {               //is this the last col?
               newId = 'extHandle';                        //if last col, process extension div instead of div in last col
            }

            Event.observe(newId, 'mouseout', function() {  //creates red ghosting line when dragging
               this.setStyle({ 'background':'red','opacity':'0.1','filter':'alpha(opacity=1)','width':'3px' });
            });
            dragHandle = newId;

            //register div as draggable object; when click to drag starts, save location info to calculate when drag ends
            new Draggable(newId, { constraint: 'horizontal', ghosting: true, handle: dragHandle,
                                onStart : function(draggable, event){ 
                                   var cw = t.unset('colWidths');
                                   var tgtIndx = (draggable.element.id.substr(draggable.element.id.length-2)-1);
                                   if (draggable.element.id == 'extHandle') { //if dragging div in extension element
                                      tgtIndx = cw.keys().size()-1; //pretend that we're actually working with last col in tbl
                                   } 
                                   var o = Event.pointerX(event);   //record point that drag started
                                   var tmp = cw.unset(tgtIndx);     //get col widths object
                                   tmp = tmp - o;                   //subtract starting point from col width
                                   cw.set(tgtIndx,tmp);             //save it back to col widths object
                                   t.set('colWidths', cw);          //save it back to tbl object
                                },
                                onEnd : function(draggable, event){ 
                                   var cw = t.unset('colWidths');   //get col widths object
                                   var tgtIndx = (draggable.element.id.substr(draggable.element.id.length-2)-1);
                                   if (draggable.element.id == 'extHandle') { //if dragging div in extension element
                                      tgtIndx = cw.keys().size()-1; //pretend that we're actually working with the last col in tbl
                                   }
                                   var minColWidth = t.get('minColWidths').get(tgtIndx); //get min col width object
                                   var o = Event.pointerX(event);   //record point that drag stopped
                                   var tmp = cw.unset(tgtIndx);     //get col widths object
                                   tmp = tmp + o;                   //add ending point to col width (net result: diff between start and end added/subtracted to/from col width)
                                   if (tmp < minColWidth) { tmp = minColWidth; } //make sure we did not exceed col width minimum
                                   cw.set(tgtIndx,tmp);             //save it back to col widths object
                                   t.set('colWidths', cw);          //save it back to tbl object
                                   var overrides = t.unset('colWidthOverrides'); //get overrides hash
                                   overrides.set(tgtIndx,1);        //note that this col was manually overriden
                                   t.set('colWidthOverrides', overrides); //save it back to tbl object
                                   fxheaderResize();                //refresh grid
                                }
            }); //register draggable object
         }); //for each adjust div
      });//for each tbl
   }//registerDraggables

//-----------------------------------------------------------

   function makeCookies() {
   // Purpose:  parse the techDetail element and determine the report that this tbl pertains to for use as a cookie name;
   //           then initialize the cookie (creates cookie or reads existing cookie info)
      var techDetail = $('techDetail').innerHTML;          //get techDetail info
      var startPoint = techDetail.indexOf('Proc=')+5;      //find starting point of report name
      var endPoint = techDetail.indexOf(';', startPoint);  //find ending point of report name
      var rptName = techDetail.substr(startPoint, endPoint-startPoint); //parse out report name
      rptName += "-";
      startPoint = techDetail.indexOf('Ver=')+4;           //find starting point of version
      endPoint = techDetail.indexOf(';', startPoint);      //find ending point of version
      rptName += techDetail.substr(startPoint, endPoint-startPoint); //parse out version and append
      Cookie.init({ name: rptName });                      //create/find cookie
   }//makeCookies

//-----------------------------------------------------------

   function setRptCookies(t) {
   // Purpose:  given table object, get col width info and save to cookie
   // Arguments: t  - a hash table of current table attributes
      makeCookies();                                       //create new cookie or get old one
      Cookie.setData('colWidths', t.get('colWidths'));     //save col width info to cookie
      Cookie.setData('minColWidths', t.get('minColWidths'));
      Cookie.setData('colWidthOverrides', t.get('colWidthOverrides'));
   }//setRptCookies

//-----------------------------------------------------------

   function adjustMinColWidths(minCols, cols, overrides, chkDrillAdj, vpSize) {
   // Purpose:  if min col widths leave extra room to the right of the table without scrolling, see if it can be auto-expanded
   // Arguments: minCols - minimum col widths object
   //            cols - the current col widths object
   //            overrides - a hash of indicators indicating which cols have been manually overriden by the user
   //            chkDrillAdj - a boolean indicating whether adjustments should adhere to drill rules
   //            vpSize - the viewport object of dimensions
   // Returns: a new col width object with expanded col widths, if possible
      var basePxChg = 10;                                  //number of pixels that a col could be incremented at a time
      var vpWidth = vpSize.get('vpWidth');                 //viewport width, beyond which we do not want to expand

      //sum up total width of all cols, including manual overrides
      var tot = 0;                                         //total width of all columns
      minCols.each(function(pair) {                        //save changes, given multiplier (though could be 0)
         if (overrides.get(pair.key) != undefined) {
            if (parseInt(pair.key) == 0 && chkDrillAdj) {  //override width manual adjustment when drilling up/down
               tot += (pair.value+6);
            } else {
               tot += (cols.get(pair.key)+6);
            }
         } else {                                          //autosize
            tot += (pair.value+6);
         }
      }); //for each col

      //figure out how many columns we can autosize, given overrides and drill potential
      var numColsToAutosize = minCols.size() - overrides.size();
      if (chkDrillAdj && overrides.get(0) != undefined) {
         numColsToAutosize += 1;
      }         

      //iterate through possible multipliers to see how much padding we can add
      var padIndex = 0;                                    //default to 0 as a multiplier
      [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20].each(function(expandIndex) { //for each multiplier
         //if existing col width + scrollbar width + number of cols*multiplier*padding increment doesn't exceed viewport width
         if (tot + scrollbarWidth + (numColsToAutosize*expandIndex*basePxChg) < vpWidth) {
            padIndex = expandIndex;                        //save that multiplier
         }
      }); //for each multiplier
      
      //create new col width object, save changes and return
      expandCols = $H();                                   //create new col width object
      minCols.each(function(pair) {                        //save changes, given multiplier (though could be 0)
         if (overrides.get(pair.key) != undefined) {
            if (parseInt(pair.key) == 0 && chkDrillAdj) {  //override width manual adjustment when drilling up/down
               expandCols.set(pair.key, pair.value+(padIndex*basePxChg));    //save padded base index value
            } else {
               expandCols.set(pair.key, cols.get(pair.key)); //save base index value for all columns
            }
         } else {                                          //autosize
            expandCols.set(pair.key, pair.value+(padIndex*basePxChg));    //save base index value for all columns
         }
      }); //for each col
      return expandCols;                                   //return new col widht object
   }//adjustMinColWidths

//-----------------------------------------------------------

   function getAdjustedCellHeight(t) {
   // Purpose:  because of the position:absolute configuration we need look at all cells in the most granular
   //           row of the frozen col header rows after setting the width appropriately in order to determine 
   //           the appropriate height of the overall row
   // Arguments: t  - a hash table of current table attributes
   // Returns: the height, in pixels, of the cell height of the the most granular row of the frozen col header rows
      var w;                                               //width retrieved from tbl object
      var tOrigId = t.get('tid');                          //get id of original table for sake of brevity throughout method
      var tot = 0;
      var adjList = $(tOrigId).select('thead > tr:nth(' + (t.get('noOfRows')-1) + ') > td');
      adjList.each(function(cell) {                        //for each cell, adjust td cell width
         w = t.get('colWidths').get(cell.cellIndex); //retrieve previously saved default size
         tot += (w+6);                                     //add to account for padding and border widths
         cell.setStyle({'width': w + 'px'});               //adjust col width
      });
      $(tOrigId).setStyle({'width': tot + 'px'});          //adjust tbl size for each col before col width chg
      return adjList[0].getHeight()-2;          //get height of td cell
   }//getAdjustedCellHeight

//-----------------------------------------------------------

   function addDraggableExtensionElements(t, extDragSpace) {
   // Purpose:  add extension and exthandle elements to dom
   // Arguments: t  - a hash table of current table attributes
   //            extDragSpace - length in pixels of draggable space between edge of tbl and edge of viewport
      var prntElement = $(t.get('tid')).select('thead > tr:nth(' + (t.get('noOfRows')-1) + ')')[0];
      var prntDims = prntElement.getDimensions();
      $(t.get('tid')+':scroller:fx').insert({'bottom': new Element('div', {'id':'extension'})
                    .setStyle({'position':'absolute',zIndex:3,'width': extDragSpace+'px', 
                               'left'  :prntDims.width-2 + 'px',
                               'top'   :prntElement.offsetTop + 'px',
                               'height':prntDims.height + 'px' }) });
      $('extension').insert({'bottom': new Element('div', {'id':'extHandle'})
                    .setStyle({ 'position':'absolute',zIndex:4, 'width':'3px', 'cursor':'col-resize',
                                'height': prntDims.height + 'px' }) }); //set look of draggable div
   }//addDraggableExtensionElements

//-----------------------------------------------------------

   function existColWidthOverrides(t) {
   // Purpose: check to see if any column widths have been manually overridden by the user
   // Arguments: t  - a hash table of current table attributes
      var overridesExist = false;
      var overrides = t.get('colWidthOverrides');
      
      overrides.each(function(pair) {                      // iterate hash to chk for overrides
         if (pair.value == 1) { overridesExist = true; }   // if any values set, override exists
      });
      
      return overridesExist;
   }//existColWidthOverrides

})();
