// Copyright 

/* Change History:
 30 Jun 09 GFreeman new version 4.0.0 with new naming (ssc_....) still compatible with map shell 3.4.2x
 06 Jul 09 GFreeman for Opera: remove width=100% on listAndMap table, use $().height() vs $().css("height") for mapCell
 07 Jul 09 GFreeman add vfsMeasure common info dump for parameters, replacing individual ones.
 08 Jul 09 GFreeman replace all XXX. with ssc; clean up parms to filter builder
 09 Jul 09 GFreeman add var stmts to make temp vars inside functions non-global
 10 Jul 09 GFreeman add mapgroups[2] to build when no qty spec;
 13 Jul 09 GFreeman allow click on "include sets of x..." to filp the checkbox; assure all IDs start with ssc_
 14 Jul 09 GFreeman turn off bucket hdrs if static map shown (due to swf missing or not found)
 15 Jul 09 GFreeman move colSortArrows to listCriteria, pass criteria to col hdr build funcs
 16 Jul 09 GFreeman move tglist field indexes into cp object; fix more rogue vars
 20 Jul 09 GFreeman use new cp element names, values
 21 Jul 09 GFreeman minor tweak to qty build in tgListRowDefault
 22 Jul 09 GFre man remove beginnnings of changing list from table to div scheme; add mapOptionsHeld queue
 23 Jul 09 GFreeman fix default filter builder to not include maxqty-1 in list unless there is a TG at that number; don't try to reload map after critchanged if it's not there
 24 Jul 09 GFreman fix scrolling glitch at VFS open/close (esp Chrome, Opera); add fix ofr IE6 where swf load may be delayed
 05 Aug 09 GFreeman start to add logging of timings for more detailed analysis; don't call row builder if tg doesn't qualify for display
 10 Aug 09 GFreeman make showPlus1 a part of listCriteria
 11 Aug 09 GFreeman remove redundant hdr, list build in SkelBld if no SWF map; ad jsTrace ctl
 13 Aug 09 GFreeman add mousewheelcatcher on mapcell so mapcell scroll /=> page scroll
 14 AUg 09 GFreeman add event listener to catch DOMMouseScroll for Firefox; mapCell mouseOver==> focus to map for IE so Flash can catch wheel.
 17 Aug 09 GFreeman catch mouseWheel here and send to Flash so it works in ALL browsers with no need to click flash first; no longer move focus to Flash with mouseOver on map cell; default shellURL to new std (no version # in it)
 18 Aug 09 GFreeman restore block on trying to showVFS if TG section not on map
 19 Aug 09 GFreeman update bucket header text for not on map.
 20 Aug 09 GFreeman move critGroupCts -> listCriteria.groupCts
 26 Aug 09 GFreeman add ASC/DESC dflt by field for sorts; add STAR rule; add summary call in list
 27 Aug 09 GFreeman make sure all ssc.tt's are on one line; add test for secInfo existnece to vfsEnter/Exit to stop erors on Flash side
 28 Aug 09 GFreeman remove message about interactive map not supplied.
 01 Sep 09 GFreeman in showPlus1 checkbox onchange -> onclick make changes take effect in IE right away vs after extra event (tnx to Canz for this!)
 02 Sep 09 GFreeman getSectionInfo at initializeMap to see if VFS images are available (not done!); update logic handling secInfo
 03 Sep 09 GFreeman don't try to show VFS if no image code returned by getSectionInfo; new scheme for building vfs imageURL
                    add sortRowRule function; use caller's delims in tgStringFromArray
 08 Sep 09 GFreeman escape window.location and currency symbol when passing to Flash.
 11 Sep 09 GFreeman in sort secs & rows, handle single and multiple same letters like digits (left padded)
 15 Sep 09 GFreeman timeout 3000->10000ms; declare SL, AIOL in buildAndShowList; use mapStatus=1 to indicate flash load pending (and inhibit sort showing list)
 22 Sep 09 GFreeman remove src="" from image0,1 vfs 
 29 Sep 09 GFreeman incorporate some <div>s to replace table entries to avoid CSS collisions with CPT (and maybe others)
 05 Oct 09 GFreeman begin changes for hidden-sectionsSelected list option.
 06 Oct 09 GFreeman version to others to QA/test
 08 Oct 09 GFreeman groupCts no longer adjusted by tg on map/visible or not; absorb buildAndShowListFilter inside buildAndShowList
 13 Oct 09 GFreeman add vfsImageSet as cp property and pass during initializeMap
 14 Oct 09 GFreeman add onload sync for vfs images to prevent jumping
 15 Oct 09 GFreeman move in more mods from TL test version vfs transitions wait till end (even of fade for pan) to change caption, arrows.
 15 Oct 09 GFreeman temporarily don't send vfsImageSet info at initializeMap due to bug in 2009-09-09 version of the shell
 =====================================================
*/

/* ra codes. list is successive entries in format: code + String(value) + ";"
Q #   - quantity limit set
L amt - Low price limit set
H amt - High price limit set
S #   - number of section(s) selected (0 if selected sections are cleared/reset)
D col - Descending sort on col
A col - Ascending sort on col
P 0/1 - ShowPlus1 on/off
M     - map: fI=Flash Interactive showing, 
             fS=Flash Interactive loaded OK but low section hit % so showing static in flash, 
             fE=I/O error in flash shell loading innerMap, 
             fX= unable to load flash shell (delay=1 sec.)
             nI= no interactive URL supplied, 
             nF=No Flash installed .. 
             [+ hit% + 'p'] + tgArray len + 'g' + msecs for load + 't'
V  C ( VFS view closed)
   L (pan left) 
   R (pan right)
   G (TktGp selected) 
   M (map section clicked)
*/

//=============================================================================================

(function() {
   ssc = {   
  
version : "2009-10-16 11:39 TBL",

actionHistory : "",
bubbleStop : false,
cp : { // all the paramaters that can be over-ridden in loadTGlist call from the web page.
    dynMapMinTgMapHitPct  : 75,
    jsTrace               : 0,
    listType              : 'scrolled',
    loadTime              : (new Date()).getTime(),
    mapShellURL           : "http://www.indux.com/map/MapShell_tn.swf",
    mapTrace              : 0,
    mapTgFb               : 2,
    sectionHiliteColor    : 'EEEE66',
    sectionInListColor    : '00CC33',
    sectionNoSeatsColor   : 'FFFFFF',
    sectionNotInListColor : 'AAFFAA',
    sectionSelectColor    : 'FF0000', 
    showListGroupHeaders  :  true,
    showTGsInNotSelectedSections :  true,
    showTGsNotOnMap       : "bottom", //  controls whether or not and where we display the TGs that did not match the map("hidden", "inlist", "bottom", "bottom-hidden") 
    sortArrows            : ['&#9660','&#9660','&#9650'], 
    staticMapURL          : "",
    swfMapURL             : "",
 // list of acceptable prices to use in lo and hi- price limit combo boxes
    tgListFilterPricePoints : [0,10,20,30,40,50,60,70,80,90,100,150,200,250,300,350,400,450,500,600,700,800,900,1000,1500,2000,2500,3000,4000,5000,10000,20000,50000,100000,200000,500000,1000000],
    //Default indexes of TG fields in the incoming tgList to buildTheDOM
	tgCanonSecIX : 0,
	tgUserSecIX  : 1,
	tgUserRowIX  : 2,
	tgQtyIX      : 3,
	tgPriceIX    : 4,
	tgTGcodeIX   : 5,
	tgNotesIX    : 6,
	tgTpsIX      : 7,
	tgStarIX     : 8,
	tgReccIX     : 9,
    vfsEnable : 0,
    vfsFilterAnimate : '',
    vfsImageAnimate  : '',
    vfsMsecs  : 800,
    vfsImageSet : '*'
}, // holds all parms passed into the list & map control from the web page

docStatus : 0, // 1 = loaded, 2 = loaded and DOM and TGs  built 
flashAvailable :false,

flashVars : {},
fltrHgtMemory : 0,
gpDelim : "",
hiQty   : 0, // #tkts in biggest TG
hiQtyNxt: 0, // #tkts in next biggest TG
itDelim : "",
listBucketCts : [],
listColHdr : "", // HTML for column headers 
listCriteria : {
    reqQty  : 0,  // current value of the desired qty filter; 0 = no spec
    offerPlus1 : 0, // indicates user should be offered +1 option
    showReqQtyPlus1 : 0, // controls whether we show TGs with reqQty+1 (or 4 if reqQty=1) tickets available
    minPrice: 0,  // current numerical value (w/o currency symbol) of the min price filter
    maxPrice: 0,  // current numerical value (w/o currency symbol) of the max price filter
    selectedMapSections : "",
    okPricePoints: [],
    loPricePoints: [],
    hiPricePoints: [],
    currencySymbol: "",    
    columnSortArrows : {}, // sort arrows for each column
    groupCts : [],    // array to hold count of TGs in each criteria clasification group
    hiQty : 0,
    hiQtyNxt : 0
    },

listHgtMemory : 0,
// 7/8/09 set in loadTgList mapGroupColors : ['00cc33', '00cc33', '00cc33', '00cc33', '00cc33'], // must be RRGGBB hex strings without lead-in 0x or #. will be used for colors to ID list groups and map section hilighting colors
mapColors : "",
mapGroups : [],
mapOptionsHeld : "",
mapStatus : 0, // -1 =  interactive map load failed, 0 = flash map not specified or flash not available, static map loaded, 1 = Flash map load started, 2 = Flash Map loaded w/data but showing static, 3 = map ready and interactive map displayed, 4=interactive displayed, data load started
notSelBktHdrTxt : "",
notOnMapBktHdrTxt : "",


activeBktHdr : -1, // remember last bucket header shown at top of list
secInfo      : {}, // object to store info on a section returned by the map
selectedBktHdrTxt : "",
scrollMemory : 0,
sortCtl      : {}, // key : ascending/descending control for last sort
sortAD       : 0, // sort direction for current sort. has to be visible to all sort functions
sortKeys     : ['SEC', 'ROW', 'SECROW', 'QTY', 'PRICE', 'STAR', 'RECC'],
sortDflts    : [0,     0,     0,        0,     0,       1,       1], // 0=  ASC, 1= DESC
tgArray      : [],
tgMapHitPct  : -1,
vfsActiveImage :0, // flip 0/1 to select which VFS image we're dealing with

vfsURLpatterns : { 'SeatData' : 'http://vfs.seatics.com/SD/<cf>/800x600/<ic>.jpg',
                   'Fanvenues' : 'http://widget.fanvenues.com/img?id=<cf>_<ic>_S'},	    


// decide the categorization of ech TG

assignTgsToGroups: function  () {
    ssc.tt ("AsgnTgGps-Start");
    ssc.listCriteria.groupCts = [0,0,0]; // clear old values
    var gpX,
        tg,
        i;
	for (i=0; i < ssc.tgArray.length; i++) { 
		tg = ssc.tgArray[i];
// map/list group definitions:
// Grp -----Criteria-----
//  #  Qty  Price Section
//  0   OK    OK    --
//  1   +1    OK    --
//  2   all other situations not fitting one of the above

	    if (Number(tg.tgQty) < ssc.listCriteria.reqQty  ||
		        Number(tg.tgPrice.replace(/,/g,'')) < ssc.listCriteria.minPrice  || (ssc.listCriteria.maxPrice > 0 && Number(tg.tgPrice.replace(/,/g,'')) > ssc.listCriteria.maxPrice) ) { 
		    gpX = 2;
	    } else {
		    gpX = ((Number(tg.tgQty) - ssc.listCriteria.reqQty == 1 && ssc.listCriteria.reqQty > 0) || (Number(tg.tgQty) == 4 &&  ssc.listCriteria.reqQty == 1) ) ? 1 : 0; // Qty+1 OK or Qty OK	
	    }
        ssc.tgArray[i].tgMapGroup  = ssc.tgArray[i].tgListGroup = gpX;
	    ssc.listCriteria.groupCts[gpX]++; // bump count of TGs in this bucket whether this TG will be displayed or not
      //alert ("tgArray[i].lg=" + ssc.tgArray[i].tgListGroup + " mg=" + ssc.tgArray[i].tgMapGroup)   
	}
    ssc.tt ("$AsgnTgGps-End: Cts=" + ssc.listCriteria.groupCts.toString());
}, // end of assignTgsToGroups

//=============================================================================================
// loop through all the TGs in tgArray and assemble the TG list on the web page 

buildAndShowList: function () {
    ssc.tt ("List-Start: S+1=" + ssc.listCriteria.showReqQtyPlus1);
	var rowClass,
      // get shorthand list type flags
        SL   = ssc.cp.listType.match(/scrolled/i),
        AIOL = ssc.cp.listType.match(/allInOne/i),
    
// initialize the Buckets for the table of displayed TGs: [0]= onMap [& selected], [1]= on-Map/not selected, [2]= offMap;
	    listBuckets  = [[],[],[]], // array for items TO BE DISPLAYED: on-map selected, on-map not selected and off-map tgs
	    listBucketOddEvens = [1,1,1],  // odd(val=0) even(1) memory for shading of rows
   	    listBucketX = 0,
   	    dispBucketX = 0,
   	    dispBucket2visible = ! (ssc.cp.showTGsNotOnMap == 'hidden' || ssc.cp.showTGsNotOnMap != 'bottom' && ssc.listCriteria.selectedMapSections != ""),
   	    listHeight,
   	    i,
   	    scrollTop,
   	    tGroup = [],
   	    secsWithTxBox = 
          "<div style='border-width:1px; font-size:6pt; border-style:solid; border-color:#000000; display:inline; width:12px; height:12px;" +
          "background-color:#" + ssc.cp.sectionInListColor + ";'>&nbsp;&nbsp;&nbsp;</div>",
   	    selSecsWithTxBox = "<div style='display:inline; border: solid 1px #000000; padding-top:2px; width:12px; height:12px;" +
   	      "background-color:#" + ssc.cp.sectionInListColor +  "; color:#" + ssc.cp.sectionSelectColor + "'><b>&#8226;</b></div>";
   	
   	ssc.listCriteria.offerPlus1 = false;   
   	ssc.listBucketCts = [0,0,0];

	// Loop through the tgArray of TGs and build HTML 		
	for (i=0; i < ssc.tgArray.length; i++) {	
		tGroup = ssc.tgArray[i];
	    if (ssc.mapStatus < 3) {
	        dispBucketX = 0;
	    } else if (tGroup.tgOnMap) {
		    // debug if (listCriteria.selectedMapSections) ssc.tt ("SelSec test. SelSec=" + (","+ssc.listCriteria.selectedMapSections+",").toUpperCase().replace(/[^\dA-Z,]/g,'') + "< SecName=" + (","+tGroup.tgCanonSec.toUpperCase().replace(/[^\dA-Z]/g,'')+",") + "<" );
		    dispBucketX  = (ssc.listCriteria.selectedMapSections == "" ||
		                   (","+ ssc.listCriteria.selectedMapSections+",").toUpperCase().replace(/[^\dA-Z,]/g,'').indexOf((","+tGroup.tgCanonSec.toUpperCase().replace(/[^\dA-Z]/g,'')+","))>=0) ? 0 : 1;
		} else {
		    dispBucketX = 2;
		}  
		if (tGroup.tgListGroup == 1 && (dispBucketX < 2 ||dispBucket2visible) ) ssc.listCriteria.offerPlus1 = true;		        
		listBucketX = dispBucketX;
        if (ssc.cp.showTGsNotOnMap == 'inList' && dispBucketX == 2) listBucketX = 0;
		if (tGroup.tgListGroup == 0 || tGroup.tgListGroup == 1 && ssc.listCriteria.showReqQtyPlus1) { // build HTML only if we might use it		    
	        if ([true,ssc.cp.showTGsInNotSelectedSections, dispBucket2visible][dispBucketX]) {
		        rowClass = [["ssc_lrOddOnMap", "ssc_lrEvenOnMap"], ["ssc_lrOddNotSel", "ssc_lrEvenNotSel"], ["ssc_lrOddOffMap", "ssc_lrEvenOffMap"]][dispBucketX][(listBucketOddEvens[listBucketX] = 1 - listBucketOddEvens[listBucketX])];
		        listBuckets[listBucketX][ssc.listBucketCts[listBucketX]++] = 
		            "<tr><td class='" + rowClass +"'" +
		            " onclick='ssc.listRowClicked(" + i + ")'" +
		            " onMouseOver='ssc.listRowEntered(this," + i + ")'" +
		            " onMouseOut= 'ssc.listRowExited(this," + i + ",\"" + rowClass + "\")'>" + 
		            ssc.cp.tgListRowHTML(ssc.listCriteria,i,tGroup) + "</td></tr>";	
		    }
	    } 
	  
	} // end for loop building the tg list HTML
    
    ssc.pushToPage("ssc_filterDiv", ssc.cp.tgListFilterHTML(ssc.listCriteria));

	ssc.tt ("$List-EndLoop: " + ssc.listBucketCts.toString() + " NotSel=" + ssc.cp.showTGsInNotSelectedSections + " OffMap=" + ssc.cp.showTGsNotOnMap);
	  
	ssc.selectedBktHdrTxt = "<div class='ssc_selectedBktHdrTxt'>" +
	      ((ssc.listBucketCts[0] == 0) ?  "There are NO ticket choices" :((ssc.listBucketCts[0] == 1) ? "Ticket choice":"Ticket choices")) +
	      ((ssc.mapStatus  < 3) ? "" : ((ssc.listCriteria.selectedMapSections.length > 0) ? " in SELECTED sections (" + selSecsWithTxBox +" on the map)" : " in&nbsp;" + secsWithTxBox + "&nbsp;sections on the map" )) + 
	   "</div>";
	     
 	ssc.notSelBktHdrTxt = "<div class='ssc_notSelBktHdrTxt'>" + 
 	       ( ((ssc.listBucketCts[1] == 1) ? "Ticket choice" : "Ticket choices")) + 
 	                      " in sections you DID NOT SELECT (" + secsWithTxBox + "&nbsp;on the map)</div>";
 	                      
	ssc.notOnMapBktHdrTxt = "<div class='ssc_notOnMapBktHdrTxt'>" +
	 ( ((ssc.listBucketCts[2] == 1) ? "Ticket choice" : "Ticket choices")) + " we couldn't locate accurately on the map.</div>";
     
    ssc.cp.tgListReady(ssc.listCriteria, {'listBucketCts' : ssc.listBucketCts}); // call web page's summary routine, if any.

    if (SL) {
	    $("#ssc_listBktHdr").html(ssc.cp.showListGroupHeaders ? ssc.selectedBktHdrTxt : ""); // fill in current top banner with initial info of 
        $("#ssc_listColHdr").html(ssc.listColHdr);
    
        // == calculate height of list div	
        listHeight = Number(ssc.listHgtMemory) +
            (($("#ssc_filterDiv").css("display") == "none") ? ssc.fltrHgtMemory : 0) - // test visibility to keep IE happy; compensate for vfs border
            ((ssc.vfsIsOpen && (ssc.cp.vfsImageAnimate || 'vertical-list') == 'vertical-list') ? ssc.vfsImageHgt : 0) - 
            $("#ssc_listBktHdr").height() -
            $("#ssc_listColHdr").height();
        $('#ssc_tktGroups').height(listHeight);
        //String(Number(ssc.listHgtMemory)-Number(VFSHdr)-Number(VFSHgt)- Number(fltrHgt)-Number(selSecHgt)-Number(critHdrHgt)-Number(grpHdrHgt)-Number(colHdrHgt))  );
        ssc.tt("List-Hgts: Tot=" + ssc.listHgtMemory +
     //	" VFShdr=" + VFShdrHgt +
            " vfs=" + ssc.vfsImageHgt +
            " fltr=" + (($("#ssc_filterDiv").css("display") == "none") ? ssc.fltrHgtMemory : 0) +
            " bkt=" + $("#ssc_listBktHdr").height() +
            " col=" + $("#ssc_listColHdr").height() + 
		    " LstSet=" + listHeight.toString() + " css(height)=" +  $('#ssc_tktGroups').css('height'));
	 
        scrollTop = $("#ssc_tktGroups").scrollTop();
        ssc.tt ("List-testScroll: "+ scrollTop);
    
        if( scrollTop > 0) {
            $("#ssc_tktGroups").scrollTop(0); // reset scroll to top
            ssc.tt ("List-setScroll=0");
        }
    }
    if (AIOL) {
	      
    }
	
    document.getElementById("ssc_tktGroups").innerHTML =  "xxxxx";
    ssc.tt("List-cleared."); // 1st row=" + listBuckets[0][0]);
	
	document.getElementById("ssc_tktGroups").innerHTML = 	 // don't use jquery $(...).html(). Takes 10x time!
	"<table class='ssc_lrListTable' cellpadding='0' cellspacing='0'>" + 
	    ((AIOL) ? "<tr><td>" + ssc.selectedBktHdrTxt + "</td></tr><tr><td>"+ ssc.listColHdr + "</td></tr>" : '') +
	    ( ((ssc.listBucketCts[0]+ssc.listBucketCts[1]+ssc.listBucketCts[2]) == 0) ? 
	        "<tr><td class='ssc_noneInCritHdrTxt'>There are NO ticket choices that meet your criteria.</td></tr>"
        :  
            listBuckets[0].join('') +
	        ((ssc.listBucketCts[1] == 0) ? 
	            "" 
	        : 
	            ("<tr id='ssc_notSelBktHdr'><td>" + ssc.notSelBktHdrTxt + "</td></tr>" ) +
	            ( (AIOL) ? "<tr><td>" +ssc.listColHdr + "</td></tr>": "" )  +
	            listBuckets[1].join('')
	        ) +
	        ((ssc.listBucketCts[2] == 0) ?
	           "" 
	        :  
	            ("<tr id='ssc_notOnMapBktHdr'><td>" + ssc.notOnMapBktHdrTxt + "</td></tr>") +
	            ( (AIOL) ? "<tr><td>" +ssc.listColHdr+ "</td></tr>" : "" )  +
	            listBuckets[2].join('')
	        ) 
	    ) +
	"</table>";
    ssc.tt ("$List-filled");   
}, // end of buildAndShow List

buildMapGroupLabels: function  (criteria) {
    var lbls  = [],
        reqQtyTxt = "tickets",
        reqQtyPlus1Txt = "",
        i,
        minPriceStr = criteria.currencySymbol + String(criteria.minPrice),
	    maxPriceStr = criteria.currencySymbol + String(criteria.maxPrice), 	
	    priceCtlTxt = ["", " at " +  minPriceStr + " and up", " at " + maxPriceStr + " or less", " at "   + minPriceStr + " - " + maxPriceStr][((criteria.minPrice > 0) ? 1:0)+ ((criteria.maxPrice > 0) ? 2:0)];
	
// determine text to display for # tickets requested
	if (criteria.reqQty > 0) {
		reqQtyTxt =  String(criteria.reqQty) + " ticket" + ((criteria.reqQty == 1) ? "" : "s");
		reqQtyPlus1Txt =  String(criteria.reqQty+1) + " tickets";
	}	

	if (criteria.reqQty == 0) {  
	    for (i=0; i<=2; i++) { 
	        lbls[i] = {}; 
	        lbls[i].type = "#tkts" ;
	    }
	    lbls[0].pattern  = ["No tickets" + priceCtlTxt, "1 ticket, {range}", "{#tkts} tickets, up to {#cozy} together, {range}" ];	           
	    lbls[1].pattern  = ["", "", ""];			       		           
	    lbls[2].pattern  = ["",                         "1 ticket, {range}", "{#tkts} tickets, up to {#cozy} together, {range}"];			       		           
	} else {
	    for (i=0; i<=2; i++) { 
	        lbls[i] = {}; 
	        lbls[i].type = "#gps";
// removed 2009-08-11 lbls[i].color = Number("0x"+ssc.mapGroupColors[i]);
	    }
	    lbls[0].pattern  = ["No choices of " + reqQtyTxt + priceCtlTxt, "1 choice of " + reqQtyTxt + ", {range}",      "{#gps} choices of " + reqQtyTxt + ", {range}"];
	    lbls[1].pattern  = ["",                                         "1 choice of " + reqQtyPlus1Txt + ", {range}", "{#gps} choices of " + reqQtyPlus1Txt + ", {range}"];
	    lbls[2].pattern  = ["",                                         "1 other choice of tickets, {range}",          "{#gps} other choices of tickets, {range}"];
	}
	return lbls;

}, // end of buildMapGroupLabels
//db:function(txt) {
//    document.getElementById("debugsureTxt").value += txt;
//    },
    
buildPageSkeleton: function  () {
    ssc.pushToPage("ssc_listAndMapDiv", 
    '<table class="ssc_listAndMap" cellspacing="0" cellpadding="0" valign=top border="1">' + // don't use width=100% as Opera will misbehave
	// '<tr><td colspan=2 ><input id="debugTxt" type=text size=150 value = ">"> </td></tr>' +
	 '<tr>' + 
	  '<td id="ssc_filterAndListCell" valign=top>' + 
	     '<div id="ssc_vfsDiv"></div>' + 
	     '<div id="ssc_filterDiv"></div>' +
	     '<div id="ssc_tktListDiv"></div>' +
	  '</td>' +
      '<td id="ssc_mapCell"> <!-- Cell for the map --><div id="ssc_map"></div></td>' +
     '</tr>' +
    '</table>');
    
    $("#ssc_mapCell").bind("mousewheel DOMMouseScroll",ssc.mouseWheelMoved);
   
    ssc.pushToPage("ssc_tktListDiv",
	    '<div id="ssc_listBktHdr" style="display:block;"></div>' + 
	    '<div id="ssc_listColHdr" style="display:block;"></div>' + //'<br>' +
	    '<div id="ssc_tktGroups" onscroll="ssc.tgBucketHdrCheck()"></div>');   


    ssc.pushToPage("ssc_vfsDiv",
        '<table  id="ssc_vfsTbl" cellpadding=0 cellspacing=0>' + 
	    '<tr onMouseOver="ssc.vfsImageEntered()"  onMouseOut="ssc.vfsImageExited()">' +
	    '<td class="ssc_vfsPanCell"><a href="#" onclick="ssc.vfsPan(\'L\'); return false;" title="Click to see the view from one section to your left" id="ssc_vfsLeftArrow">' +
	        '&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&#9668;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;</a></td>' +
	    '<td id="ssc_vfsImageCell" align="center">' +
	     '<div id="ssc_vfsImageDiv0"><img id="ssc_vfsImage0" onload="ssc.showVFSloaded()" /></div>' +
	     '<div id="ssc_vfsImageDiv1"><img id="ssc_vfsImage1" onload="ssc.showVFSloaded()" /></div>' +
	    '</td>' + 
	    '<td class="ssc_vfsPanCell"><a href="#" onclick="ssc.vfsPan(\'R\'); return false;" title="Click to see the view from one section to your right" id="ssc_vfsRightArrow">' +
	         '&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&#9658;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;</a></td>' +
	    '</tr>' +
	    '</table>' +
	    '<div id="ssc_vfsHdr">' +
	  	 '<table width="100%"><tr><td ID="ssc_vfsCaption" align=left></td>' +
	    '<td width="15px">' +
        '<input  type="button" id="ssc_vfsClose" value="[X]"' +
                'title="Close view-from-section pane;"' +
                'onclick="ssc.vfsClose(); return false;">' +    
	    '</td></tr>' +
	    '</table>' +
        '</div>'    );	    
    ssc.vfsImageHgt = $("#ssc_vfsDiv").height(); // use this vs .css("height") to keep Opera happy

    ssc.listHgtMemory = $("#ssc_tktGroups").height(); //  get nominal height of list (including headers)

    if (typeof(ssc.cp.swfMapURL) != "undefined" && ssc.cp.swfMapURL != '') {
		if(ssc.flashAvailable) {
		// ===== set up vars for caling SWFObject and call it to imbed the shell
			ssc.flashVars.domain = document.domain;
			var attributes = {},
			    params = {};
			params.allowScriptAccess = 'always';
			params.menu = "false";
			params.quality = "autohigh";
			params.wmode = "opaque";
			window.setTimeout('ssc.checkShellLoad()',10000);
			swfobject.embedSWF(ssc.cp.mapShellURL, "ssc_map", $("#ssc_mapCell").width() , $("#ssc_mapCell").height(), "9.0.0", false, ssc.flashVars, params, attributes);
			ssc.mapStatus = 1; // note that we've initiated the map load
			ssc.tt("$SWF load:" + ssc.cp.mapShellURL + " with:" + ssc.cp.swfMapURL);
			ssc.tt("CellDims: $Lst W=" + $("#ssc_tktListDiv").width() + " Map W=" + $("#ssc_mapCell").width() + " H=" + $("#ssc_mapCell").height());
	    } else {
   
			ssc.loadStaticMap('<span class="ssc_onMapMsg">An interactive map is available but you need Adobe\'s Flash player 9 or above to see it. ' +
				'<br/>Enable Flash if it\'s installed on your system or <a href="http://www.adobe.com/go/getflashplayer">click here to get Flash.' +
				'</a></span>');
			ssc.raM("nF");
		}
	} else {
        ssc.loadStaticMap('');
		ssc.raM("nI");
	}
}, // end of buildPageSkeleton
    mapClick: function (event) {
        alert(event.type);
},

// called for each TG while building the DOM to make sure all/only the relevant lo- and hi-price values are selected
buildQtyAndPriceChoices: function  (qty, price) {
	var px;
	if (Number(qty) > ssc.listCriteria.hiQty) {
	    ssc.listCriteria.hiQtyNxt = ssc.listCriteria.hiQty;
	    ssc.listCriteria.hiQty = Number(qty);
	} else if (Number(qty) < ssc.listCriteria.hiQty && Number(qty) > ssc.listCriteria.hiQtyNxt) {
	    ssc.listCriteria.hiQtyNxt = Number(qty);
	}
	//ssc.tt ("bQaPCs q=" + qty + " Hi=" + ssc.listCriteria.hiQty + " Nxt=" + ssc.listCriteria.hiQtyNxt + " $=" + price);
	
	price = Number(price.replace(/,/g,''));
    for (px=1; px < ssc.listCriteria.okPricePoints.length; px++) {
		if (ssc.listCriteria.okPricePoints[px] > Number(price) ) {
			ssc.listCriteria.loPricePoints[px-1] = true; 
			break;
		}
	}
	for (px=1; px< ssc.listCriteria.okPricePoints.length; px++) {
		if (ssc.listCriteria.okPricePoints[px] >= Number(price) ) {
			ssc.listCriteria.hiPricePoints[px] = true; 
			break;
		}
	}
},		   
//=============process the string from the server that comprises a list of ticket Groups 
buildTheDOM: function  (tgList) {
     ssc.gpDelim = tgList.substr(0,1);
     ssc.itDelim = tgList.substr(1,1);
 var ticketGroups = [],
     tGroupTokens = [],
     tGroup = {},
	 x = tgList.indexOf(ssc.gpDelim,2), // get index of delimiter after currency symbol
	 i; 
	ssc.listCriteria.currencySymbol = tgList.substring(2,x); // get currency symbol
	
	ticketGroups = tgList.substr(x+1).split(ssc.gpDelim); // skip over gp delim, it delim, curr symbol and it's delim
	
	ssc.hiPrice = [];
	ssc.listCriteria.loPricePoints = [];	
	for (i=0; i< ticketGroups.length; i++) {	
		tGroupTokens = ticketGroups[i].split(ssc.itDelim);
		if (tGroupTokens.length > 1) {
			ssc.tgArray[i] = tGroup = ssc.tgObjectFromTokens(tGroupTokens);
			if (tGroupTokens.length < 7) {
			    ssc.tt ("short tGroup. #=" + i + " L=" + tGroupTokens.length + " TG="  + tGroupTokens); 
			} else {
			    ssc.buildQtyAndPriceChoices(tGroup.tgQty, tGroup.tgPrice);
			}
		}
	}	
}, // end of buildTheDOM

// called at expiration of SWF load timer to see if anything has happened. If not, load static map
checkShellLoad: function() {
    if (ssc.mapStatus != 1) return;
    ssc.loadStaticMap('<span class="ssc_onMapMsg">The interactive map is temporarily unavailable. Here is a plain version.</span>');
    ssc.raM("fX");// note that we got a SHELL load error
    ssc.buildAndShowList();
    ssc.cp.listAndMapLoaded(-2)
},
//handle a change in ticket group list display criteria
criteriaChanged: function  (parm) {
	ssc.stopOneMO(); // holdoff on mouseovers for a few milliseconds (in case pull-downs are over tg list);
	var x = parm.split('&'),
		i,
		nv,
		v;
	
	for (i in x) {
	    nv = x[i].split('=');
	    //ssc.tt("cc i=" + i + " nv=" + nv);
	    v = Number(nv[1]);
	    switch(nv[0]) {
	        case "ReqQty":
		        ssc.listCriteria.reqQty = v;   
		        ssc.ra("Q",v);             
                break;
            case "MinPrice":
                ssc.listCriteria.minPrice = v;
                ssc.ra("L",v);             
                break;
            case "MaxPrice":
                ssc.listCriteria.maxPrice = v;
                ssc.ra("H",v);             
                break;
            default:
	    }
	}

	ssc.tt ("CritChg: Q:" + ssc.listCriteria.reqQty + " +1:" + ssc.listCriteria.showReqQtyPlus1 + " Mn:" + ssc.listCriteria.minPrice + " Mx:" + ssc.listCriteria.maxPrice );
	ssc.assignTgsToGroups();
    ssc.mapGroups = ssc.buildMapGroupLabels(ssc.listCriteria);
	if (ssc.sortCtl['QTY']) {
	    ssc.sortTgList('QTY',['DESC',,'ASC'][ssc.sortCtl['QTY']+1]);	
	} else {
	    ssc.buildAndShowList();
	}
	if (ssc.mapStatus >= 3) {
    	//document["ssc_map"].sendTGsToMap(ssc.mapGroups, ssc.tgArray);
    	document["ssc_map"].sendTGsToMap(ssc.mapGroups, ssc.tgStringFromArray());
    	ssc.tt ("CritChg: Gps, TGs reloaded.");
    }
},

//========================================================
// build the actual pull-down list HTML for qty, lo and hi prices limits; include script to handle reset (custom users will be called same way)
// initial questions won't be repeated....
qtyIntro : "<span class='ssc_qtyAsk'>How many tickets do you want?</span> ",
priceIntro : "<span class='ssc_priceAsk'>What's your price range?</span>",
 
filterHTMLdefault: function (criteria) {
 ssc.tt ("Filter-Start: width=" + $("#ssc_filterDiv").width());
   var selList = '<table class="ssc_filterTbl" border="0" cellpadding="0" cellspacing="0"><tr><td NOWRAP colspan="2">',
       i,
       px,
       qtyWidth,
       qtyFollow;
 // build qty combo
    if (criteria.reqQty == 0) {
        qtyFollow = "";
        qtyWidth = '13em';
   } else {
        qtyWidth = (String(criteria.reqQty).length * .6 + 2.5) + 'em';
	    ssc.qtyIntro = "<span class='ssc_qtyTell'>You've selected </span>";
        qtyFollow = "<span class='ssc_qtyTell'> ticket" + ((criteria.reqQty == 1) ? '':'s') + "</span>"; 
	
	if (criteria.offerPlus1) {
	    qtyFollow += " <sub><input type='checkbox' id='ssc_showPlus1' " + (criteria.showReqQtyPlus1?'checked':'') + " onclick='ssc.showPlus1(+(this.checked?1:0));'></sub>" +
	            "<label for='ssc_showPlus1' class='ssc_offerPlus1' onmouseover='$(\"#ssc_whyPlus1\").show()' onmouseout='$(\"#ssc_whyPlus1\").hide()'> Include sets of " + String(criteria.reqQty+1) + " tickets <u>why?</u></label>" +
		    	"<span id='ssc_whyPlus1'>" + 
	            "There are sets of tickets for this event where the owner will not sell " + String(criteria.reqQty)  + " but <i>will</i> sell " + String(criteria.reqQty + 1) + "." + 
	            "<br/>Even though you would have to buy one extra ticket, the price might be attractive.<br/>Check this box to include those sets of tickets." +
			    "</span>" +
			    "";
	}

   }
    selList += ssc.qtyIntro + ' <select size="1" id="ssc_reqQtySel" style="width:' + qtyWidth + '" onchange="ssc.criteriaChanged(\'ReqQty=\'+this.value)">' +
                '<option value="0"' + 
                    ((criteria.reqQty == 0) ? " selected" : "") + 
                    '>I\'ll decide at checkout</option>';
	for (i=1; i <= criteria.hiQty; i++) {
	    if (i == criteria.hiQty - 1 && i != criteria.hiQtyNxt) continue;
	    selList += '<option class="ssc_qtyValues" value="' + i + '" ' + ((criteria.reqQty == i) ? "selected" : "") + '>' + i + '</option>'
	}
	selList += '</select>' + qtyFollow + '</td></tr><tr><td NOWRAP>';
// build min and max price combos
    if (criteria.minPrice != 0 || criteria.maxPrice != 0) {
        ssc.priceIntro = "<span class='ssc_priceTell'>Price should be from </span>";
    }
    // Build No minimum (top ) entry
	selList += ssc.priceIntro + '&nbsp;' + 
        '<select size="1" id="ssc_minPriceSel" onchange="ssc.criteriaChanged(\'MinPrice=\' + this.value);">\n' + 
			 '<option value="0" ' + ((criteria.minPrice == 0) ? "selected" : "") + '>No minimum</option>\n';
	for (px=1; px < criteria.okPricePoints.length; px++) {
		if (criteria.loPricePoints[px] && (criteria.okPricePoints[px] < criteria.maxPrice || criteria.maxPrice == 0) ) {
           // alert ("px="+px + " $:"+pricePoints[px])
            selList += '<option class="ssc_priceValues" value="' + criteria.okPricePoints[px] + '" ' + 
                    ((criteria.minPrice == criteria.okPricePoints[px]) ? "selected" : "") +
                     '>' + criteria.currencySymbol + criteria.okPricePoints[px] + '</option>\n'
		}
	}
	selList += '</select>'
// build Max price combo	
    selList += '&nbsp;to&nbsp;' + 
        '<select size="1" id="ssc_maxPriceSel" onchange="ssc.criteriaChanged(\'MaxPrice=\'+ this.value);">\n' + 
			 '<option value="0" ' + 
			 ((criteria.maxPrice == 0) ? "selected" : "") + 
			 '>No maximum</option>\n';
	for (px=1; px< criteria.okPricePoints.length; px++) {
		if (criteria.hiPricePoints[px] && criteria.okPricePoints[px] > criteria.minPrice) {
           // alert ("px="+px + " $:"+pricePoints[px])
            selList += '<option class="ssc_priceValues" value="' + criteria.okPricePoints[px] + '" ' + 
                        ((criteria.maxPrice == criteria.okPricePoints[px]) ? "selected" : "") + 
            '>' + criteria.currencySymbol + criteria.okPricePoints[px] + '</option>\n'
		}
	}
    selList += '</select></td><td>';
 //build "show All" button    
     if (criteria.reqQty || criteria.minPrice || criteria.maxPrice || criteria.selectedMapSections) {
       selList+= '<input type="button" id="ssc_resetBtn" value="Show All" onClick=\'' + 
        '$("#ssc_reqQtySel").attr("selectedIndex", 0); ' +
	    '$("#ssc_maxPriceSel").attr("selectedIndex", 0); ' + 
	    '$("#ssc_minPriceSel").attr("selectedIndex", 0); ' +
	    'ssc.setMapOptions("clearSectionSelect=*"); ' + 
	    'ssc.criteriaChanged("MinPrice=0&MaxPrice=0&ReqQty=0");\'>';
	 }
    selList += '</td></tr></table>';
     
	    /*+'<font size=1>'+ssc.version+'</font>' */
    ssc.tt ("Filter-End.");
    return selList
},	
// called when shell and map are both loaded
initializeMap: function(by) {	
	ssc.tt ("InitMap-by: " + by )// + " loc=" + window.location)
	document["ssc_map"].sendControlsToMap("id=LTGL" +
	   "&activeGroup=" + (ssc.listCriteria.showReqQtyPlus1 ? 1 : 0) + 
	   "&currencySymbol=" + encodeURIComponent(ssc.listCriteria.currencySymbol) + 
	   "&mapColors=" + ssc.mapColors +
//	   "&vfsImageSet=" + encodeURIComponent(ssc.cp.vfsImageSet) +
	   "&eventID=" + encodeURIComponent(window.location)
	   );
	ssc.tt ("InitMap-CtlsSent.");
    ssc.tgMapHitPct =	document["ssc_map"].sendTGsToMap(ssc.mapGroups, ssc.tgStringFromArray());
	ssc.tt ("InitMap-TGsLoaded: Hit%=" + ssc.tgMapHitPct);
	if (ssc.tgMapHitPct < ssc.cp.dynMapMinTgMapHitPct) {
		ssc.setMapOptions('showDynamicMap=0');
		ssc.cp.showTGsNotOnMap='inList';
		ssc.cp.showListGroupHeaders = false;
		ssc.mapStatus = 2;
		ssc.raM("fS" + ssc.tgMapHitPct + 'p');
	} else {
		ssc.raM("fI" + ssc.tgMapHitPct + 'p');
	}	 
	ssc.buildAndShowList();
	ssc.cp.listAndMapLoaded([-1,0,0,1,2,2][ssc.mapStatus+1]);
	ssc.tt("InitMap-Done.")   
},
//======= handle mouse events on a TG in the list
listRowClicked: function (tgX) {
    if (ssc.bubbleStop) {
        ssc.bubbleStop = false;
    } else {
       ssc.tt ("TG click on " + ssc.tgArray[tgX].tgCanonSec);
       if (ssc.tgArray[tgX].tgOnMap && ssc.cp.vfsEnable) ssc.showVFS(ssc.tgArray[tgX].tgCanonSec,'G');
    }
},

listRowEntered: function (tgt,tgX) {
	if (ssc.skipMouseOver()) { return}
	tgt.className = 'ssc_lrHilite';
  	if (ssc.mapStatus >= 3)  document["ssc_map"].sendSecEnteredToMap(ssc.tgArray[tgX].tgCanonSec,ssc.tgArray[tgX].tgUserRow);
},

listRowExited: function (tgt,tgX,rClass) {
		tgt.className = rClass;
	if (ssc.mapStatus >= 3) document["ssc_map"].sendSecExitedToMap(ssc.tgArray[tgX].tgCanonSec/*,ssc.tgArray[tgX].tgUserRow*/);
},

loadStaticMap: function  (msg) {
        ssc.tt("Load Static:" + ssc.cp.staticMapURL + " mapStatus=" + ssc.mapStatus + " msg=" + msg);
		ssc.pushToPage("ssc_mapCell", '<center>' + ((msg) ? msg + '<br />' : '') + '<img id="ssc_staticMap" src="' + ssc.cp.staticMapURL + '"></center>');
		ssc.cp.showListGroupHeaders = false;
	// removed 2009-08-18 15:00	ssc.mapStatus = 0;
},

// main entry point from web page to load data, initialize lots of stuff

loadTgList: function (tgl,p) {  // code invoked by web page (when HMTL and JS are all loaded)
    if (p.loadTime) {ssc.loadTime = ssc.startTime = ssc.lastTime = p.loadTime}
  // set default for customizable routines 
    ssc.cp.tgListFilterHTML = ssc.filterHTMLdefault;
    ssc.cp.tgListHdrHTML    = ssc.tgListHdrDefault; // point at function to build heading row for tg list
    ssc.cp.tgListRowHTML    = ssc.tgListRowDefault; // point at function to build a single TG list row entry
    ssc.cp.tgListReady      = ssc.noOp;
    ssc.cp.listAndMapLoaded = ssc.noOp;
  // pick up all parameters from the web page (bad ones will just be ignored)
	for (var px in p) { 
        ssc.cp[px] = p[px];
    }
    ssc.mapColors=  // OLD, to be replaced.... uses styleSheet-like format: <codename of colorToSet>:<hex string of color without # or 0x>; ...
    ' inList:'    + ssc.cp.sectionInListColor + ';' + 
    ' notInList:' + ssc.cp.sectionNotInListColor + ';' + 
    ' noSeats:'   + ssc.cp.sectionNoSeatsColor + ';' + 
    ' rowHilite:FFFF00;' +
    ' sectionHilite:' + ssc.cp.sectionHiliteColor + ';' +
    ' sectionSelect:' + ssc.cp.sectionSelectColor;
 // removed 2009-08-11   ssc.mapGroupColors= [ssc.cp.sectionInListColor, ssc.cp.sectionInListColor, ssc.cp.sectionInListColor];
    ssc.listCriteria.okPricePoints  = ssc.cp.tgListFilterPricePoints;
    ssc.sortArrowsReset();
    ssc.flashVars.innerMap  = ssc.cp.swfMapURL;
    ssc.flashVars.tt        = ssc.cp.mapTrace;
    ssc.flashVars.tgfb      = ssc.cp.mapTgFb;
    ssc.flashAvailable      = (swfobject.getFlashPlayerVersion().major >= 9);
    ssc.flashVars.vfsEnable = ssc.cp.vfsEnable;
    ssc.docStatus = 1; // show we are loaded but DOM, TGs not built
    ssc.tt("$LoadTgList-St");
    ssc.buildPageSkeleton();
    ssc.tt("$LoadTgList-AfterSkel");
    ssc.buildTheDOM(tgl);
	ssc.tt("$LoadTgList-AfterDOM");
    ssc.assignTgsToGroups();
	ssc.tt("$LoadTgList-AfterPushFilter");
	ssc.fltrHgtMemory = $("#ssc_filterDiv").height();
	ssc.tt("$LoadTgList-AfterGetFilterHgt");
    ssc.mapGroups = ssc.buildMapGroupLabels(ssc.listCriteria);
    ssc.listColHdr = ssc.cp.tgListHdrHTML(ssc.listCriteria);
	if(ssc.flashAvailable && ssc.cp.swfMapURL) {
	    if (ssc.mapStatus == 3) ssc.initializeMap("load"); // push data to map if it's loaded already (unlikely)
	} else {
  	    // we don't have flash (or the right level, so...
  	    ssc.buildAndShowList();
  	    ssc.cp.listAndMapLoaded(0);
	}
	ssc.docStatus = 2;
},

mouseWheelMoved: function(e) {
    var dir = e.wheelDelta || - e.detail; // Fwd/back: all but Firefox +/- || Firefox -/+
    //ssc.tt("wheel wheelDelta=" + e.wheelDelta + " detail=" + e.detail);
    //ssc.db (" wX=" + e.screenX + " Y=" + e.screenY + " delta=" + e.wheelDelta + " detail=" + e.detail + " dir=" + dir);
    if (ssc.mapStatus >= 2) document["ssc_map"].sendControlsToMap("id=Whl&mouseWheel=" + dir);
    return false;
},

 noOp: function() {
    return;
},

pushToPage: function (id,info) {
    if (document.getElementById(id) != null) {
        document.getElementById(id).innerHTML = info; // use vs jquery $().html for speed
        return true;
    } else{
        ssc.tt ("pTp did not find: " + id);
        return false;
    }
},

// record user choices for passing to the server
ra: function  (item,itemvalue) {
    ssc.actionHistory += item + String(itemvalue) + ";"
},
raM: function (x) {
    ssc.ra("M",x + ssc.tgArray.length + 'g' + ssc.msecSinceLoad()+'t')
},

skipOneMO : 0,
stopOneMO: function  () {
 ssc.skipOneMO = (new Date()).getTime();
},

skipMouseOver: function () {
  	return (new Date()).getTime() < ssc.skipOneMO + 500;
},

// function to be called by web page to set any needed options
setMapOptions: function (p) {
    if (ssc.mapStatus > 1) {
        document["ssc_map"].sendControlsToMap("id=SMO&" + p)
    } else {
        ssc.mapOptionsHeld += "&" + p;
    }
},

showPlus1: function (v) {
    ssc.listCriteria.showReqQtyPlus1 = v;
   if (ssc.mapStatus >=4) document["ssc_map"].sendControlsToMap("id=sp1&activeGroup=" + (v ? "1" : "0") );
    ssc.ra("P",v);
    ssc.buildAndShowList();
},

showVFS: function (cSec,cd,cb) {
	 ssc.tt("showVFS:" + cSec + " cd:" + cd);
	 var newSecInfo,
	     imageURL;
	 if (ssc.mapStatus < 2) return;
	 newSecInfo = document["ssc_map"].getSectionInfo(cSec);
	 ssc.tt("   ... SN:" + newSecInfo.sectionName + " LN:" + newSecInfo.longName + " IS:" + newSecInfo.vfsImageSet + " ISs:" + newSecInfo.vfsImageSets + " IC:" + newSecInfo.vfsImageCode + " CF:" + newSecInfo.vfsConfig + " L:" + newSecInfo.leftSectionName + " R:" + newSecInfo.rightSectionName);
	 if (newSecInfo.vfsImageCode) {
	// if (newSecInfo.sectionName !== ssc.secInfo.sectionName || ! ssc.vfsIsOpen) {
	    ssc.secInfo  = newSecInfo;
	    ssc.showVFScb = cb;
	    imageURL=ssc.vfsURLpatterns[ssc.secInfo.vfsImageSet].replace(/<cf>/,ssc.secInfo.vfsConfig).replace(/<ic>/,ssc.secInfo.vfsImageCode);	    
	    ssc.tt("getSecI iURL=" + imageURL);
	    $("#ssc_vfsImage" + ssc.vfsActiveImage).attr('src',imageURL);	
        ssc.ra('V',cd);
    } else {
        ssc.vfsClose();    
    }
},
showVFSloaded: function () {
    if (ssc.showVFScb) {
      ssc.showVFScb();
    } else {
      ssc.showVFSfinish();
    }
},
showVFSfinish: function () {
    var t = 'Approximate view from ' + ssc.secInfo.longName;
    $("#ssc_vfsCaption").html(t);
    $("#ssc_vfsImage" + ssc.vfsActiveImage).attr('alt',t);
	$("#ssc_vfsLeftArrow").css({visibility:(ssc.secInfo.leftSectionName != '' ? 'visible' : 'hidden')});
	$("#ssc_vfsRightArrow").css({visibility:(ssc.secInfo.rightSectionName != '' ? 'visible' : 'hidden')});
	if (! ssc.vfsIsOpen) ssc.vfsOpen();
},

sortArrowsReset: function () {
    for (var i = 0; i < ssc.sortKeys.length; i++) {
       ssc.listCriteria.columnSortArrows[ssc.sortKeys[i]] = '<span class="ssc_sortNoArrow">' + ssc.cp.sortArrows[1] + '</span>';
    }
},

sortRowRule: function (a,b) {
	var A = ssc.sortCanonSec(a.tgUserRow).toUpperCase(),
	    B = ssc.sortCanonSec(b.tgUserRow).toUpperCase();
	return A == B ? 0 : ssc.sortAD * (A > B ? 1 : -1);
},

sortSectionRule: function (a,b) {;
	var A = ssc.sortCanonSec(a.tgCanonSec).toUpperCase(),
	    B = ssc.sortCanonSec(b.tgCanonSec).toUpperCase();
	return A == B ? 0 : ssc.sortAD * (A > B ? 1 : -1);
},
sortSecRowRule: function (a,b) {
	var A = (ssc.sortCanonSec(a.tgCanonSec) + '.' + a.tgUserRow).toUpperCase(),
	    B = (ssc.sortCanonSec(b.tgCanonSec) + '.' + b.tgUserRow).toUpperCase();
	return A == B ? 0 : ssc.sortAD * (A > B ? 1 : -1);
},

sortCanonSec: function  (sec) {
    var secParts = sec.toUpperCase().replace(/([^\d])(\d)/g,'$1 $2').replace(/(\d)([^\d])/g,'$1 $2').replace(/([A-Z])([^A-Z])/g,'$1 $2').replace(/([^A-Z])([A-Z])/g,'$1 $2').replace(/\s+/g,' ').replace(/^\s+/,'').replace(/\s+$/,'').split(' '),
        iS;
    for (iS = 0; iS < secParts.length; iS++) {
        if (!isNaN(secParts[iS])) {secParts[iS] = '00000000'.substr(0,8-secParts[iS].length) + secParts[iS];}
   //     if (secParts[iS].match(/^(?:[a-zA-Z]|([a-zA-Z])\1|([a-zA-Z])\2\2)$/))  secParts[iS] = '00000000'.substr(0,8-secParts[iS].length) + secParts[iS];
        if (secParts[iS].match(/^([A-Z])\1*$/))  secParts[iS] = '^^^^^^^^'.substr(0,8-secParts[iS].length) + secParts[iS];
    }
    return secParts.toString();
},

sortQtyRule: function (a,b) {
	 return ssc.sortAD * ((a.tgListGroup == 1 ? 1000 + a.tgQty : a.tgQty ) - ( b.tgListGroup == 1 ? 1000 + b.tgQty : b.tgQty ));
},

sortPriceRule: function (a,b) {
	return ssc.sortAD * ( Number(a.tgPrice.replace(/,/g,'')) - Number(b.tgPrice.replace(/,/g,'')));
},
sortStarRule: function (a,b) {
	return ssc.sortAD * ( Number(Boolean( + + a.tgStar)) - Number(Boolean(+ + b.tgStar)));
},
sortTgList: function (col,ad) {
    var ix, adx,
        sortFunc,
        sortFuncs = [ssc.sortSectionRule, ssc.sortRowRule, ssc.sortSecRowRule, ssc.sortQtyRule, ssc.sortPriceRule, ssc.sortStarRule];
    for (ix = 0; ix< ssc.sortKeys.length; ix++) {
        if (col.toUpperCase() == ssc.sortKeys[ix] ) {
            sortFunc = sortFuncs[ix];
            break;
        }
    }
    ad = (typeof(ad) == "undefined" ) ? ad = '' : ad.toUpperCase();
   switch (ad) {
     case 'ASC':    
        adx= 1;
        break;
     case 'DESC':
        adx = -1;
        break;
     default:
        adx = 0;
     }
    if (ix>=0 && adx >= -1) {
       ssc.sortAD = adx != 0 ? adx : (ssc.sortCtl[ssc.sortKeys[ix]] || ssc.sortDflts[ix]) <= 0 ? 1 : -1;
       ssc.tt ("Sort-St: col=" + col + " ix=" + ix + " adx=" + adx + " ctl=" + ssc.sortCtl[ssc.sortKeys[ix]] + " AD=" + ssc.sortAD);
       ssc.sortCtl = {};
       ssc.sortCtl[ssc.sortKeys[ix]] = ssc.sortAD;
       ssc.sortArrowsReset();
       ssc.listCriteria.columnSortArrows[ssc.sortKeys[ix]] = 
         ['<span class="ssc_sortDnArrow">','<span class="ssc_sortNoArrow">','<span class="ssc_sortUpArrow">'][ssc.sortAD+1] + 
         ssc.cp.sortArrows[ssc.sortAD+1] + '</span>';
       ssc.ra(["D","","A"][ssc.sortAD+1],ssc.sortKeys[ix]);
       ssc.tgArray.sort(sortFunc);
       ssc.tt ("$Sort-End: col=" + col + " ix=" + ix + " adx=" + adx + " ctl=" + ssc.sortCtl + " ad=" + ssc.sortAD);
       ssc.listColHdr = ssc.cp.tgListHdrHTML(ssc.listCriteria);
       if (ssc.mapStatus != 1) ssc.buildAndShowList();
       ssc.tt ("Sort-Ex: col=" + col + " ix=" + ix + " adx=" + adx + " ctl=" + ssc.sortCtl + " ad=" + ssc.sortAD + " mStat=" + ssc.mapStatus);
     }
},		

tgListHdrDefault: function  (criteria) {
	 return '<table class="ssc_lhTable" cellspacing="0" cellpadding="0">' +
	'<tr valign="bottom">' +
    '<td class="ssc_lhSec" onclick="ssc.sortTgList(\'sec\');">Section' + criteria.columnSortArrows['SEC'] + '</td>' +
	'<td class="ssc_lhRow" onclick="ssc.sortTgList(\'row\')">Row' + criteria.columnSortArrows['ROW'] + '</td>' +
	'<td class="ssc_lhQty" onclick="ssc.sortTgList(\'qty\')">' + ((criteria.reqQty > 0) ? '# to Buy' : '# Avail') + criteria.columnSortArrows['QTY'] + '</td>' +
	'<td class="ssc_lhPri" onclick="ssc.sortTgList(\'price\')">Price (each)' + criteria.columnSortArrows['PRICE'] + '</td>' +
	'<td class="ssc_lhBuy"></td></tr>' +
	'</table>'
},

// ======================================== determine what to show in the TG row
tgListRowDefault: function  (criteria, tgIndex, tg) {
	var buyQty,
        dispQty = "",
	    qtyClass = "ssc_lrQty",
        showNotes = tg.tgNotes != ""; //&& tGroup.tgNotes != undefined
	if (criteria.reqQty <= 0 || tg.tgListGroup >= 2 ) {
		// modify this code to achieve the desired "look" of ticket qty when no qty filter present (or applicable)
		dispQty = ["0", "", "", "1 or ", "2 or ", "1-" + String(Number(tg.tgQty)-2) + " or "][Math.min(Number(tg.tgQty),5)] + String(tg.tgQty);
		buyQty = (Number(tg.tgQty) == 1 || Number(tg.tgQty) == 3) ? 1 : 2;
	} else {
		dispQty = Number(criteria.reqQty);
		if (tg.tgListGroup == 1) {
		    qtyClass = "ssc_lrQtyPlus1";
		    dispQty++
		}
		buyQty = dispQty
	}


     return "<table class='ssc_lrTable' cellpadding='0' cellspacing='0'>" + 
                "<tr>" +
		        "<td class='ssc_lrSec'>" + tg.tgUserSec + 
		  //  " <font size=1>[TN=" + tg.tgCanonSec + "]</font>" +   // ??? for debugging 
		        "</td>" + 
			    "<td class='ssc_lrRow'>" + tg.tgUserRow + "</td>" + 
			    "<td class='" + qtyClass + "'>" + dispQty + "</td>" + 
			    "<td class='ssc_lrPri'>" + criteria.currencySymbol + tg.tgPrice + "</td>" + 
			    "<td class='ssc_lrBuy' rowspan='" + ((showNotes) ? 2 : 1) + "'>" +
				"<input type=button class='ssc_lrBuyBtn' name='buyBTN' value='Buy' onclick=\"ssc.bubbleStop=true; buyTickets(" + tgIndex + "," + buyQty + ")\"></td>" +
			    "</tr>" +
                ( (showNotes) ? "<tr>" + "<td colspan=4 class='ssc_lrNotes'><b>Note</b>: " + tg.tgNotes + "</td></tr>" : "") +
                "</table></tr>"; 
},	

tgBucketHdrCheck: function () {
    if (! ssc.cp.showListGroupHeaders) return;
    var abh = 0;
 //ssc.tt("Scroll Pos=" + String(($("#ssc_tktGroups").scrollTop()) + " NOM=" + String($("#ssc_notOnMapBktHdr").position() && $("#ssc_notOnMapBktHdr").position().top))+ " NSel=" + String($("#ssc_notSelBktHdr").position() && $("#ssc_notSelBktHdr").position().top));
    if ($("#ssc_notOnMapBktHdr").position() && $("#ssc_notOnMapBktHdr").position().top < $("#ssc_tktGroups").position().top ) {
        abh=2;
    } else if ($("#ssc_notSelBktHdr").position() && $("#ssc_notSelBktHdr").position().top < $("#ssc_tktGroups").position().top ) {
        abh=1;
    }
    if (ssc.activeBktHdr != abh) {
        $("#ssc_listBktHdr").html([ssc.selectedBktHdrTxt,ssc.notSelBktHdrTxt,ssc.notOnMapBktHdrTxt][abh]);
        ssc.activeBktHdr = abh;
    }
},

tgObjectFromTokens: function  (tgp) {
	return {		 
	tgCanonSec     : tgp[ssc.cp.tgCanonSecIX], 
	tgUserSec      : tgp[ssc.cp.tgUserSecIX],
	tgUserRow      : tgp[ssc.cp.tgUserRowIX],
	tgQty          : tgp[ssc.cp.tgQtyIX],
	tgPrice        : tgp[ssc.cp.tgPriceIX],
	tgTGcode       : tgp[ssc.cp.tgTGcodeIX],
	tgNotes        : tgp[ssc.cp.tgNotesIX],
	tgTps          : tgp[ssc.cp.tgTpsIX],
	tgStar         : tgp[ssc.cp.tgStarIX],
	tgRecc         : tgp[ssc.cp.tgReccIX],
	tgOnMap        : true };
},

sum: function (arr) {
    var s = 0, i;
    for  (i=0; i< arr.length;i++) { s += arr[i]}
    return s
},
 testFunc1: function() {
	ssc.displayTT();
},

tgStringFromArray: function () {
    ssc.tt("StFrAr-St #tgs="  + ssc.tgArray.length);
    var tgStrings = [],
        tgString = "", 
       tg = {},
       i;

    for (i = 0; i < ssc.tgArray.length; i++) {
     tg = ssc.tgArray[i];
    tgStrings[i] = tg.tgCanonSec + ssc.itDelim + tg.tgUserSec + ssc.itDelim + tg.tgUserRow + ssc.itDelim + tg.tgQty + ssc.itDelim + tg.tgPrice + ssc.itDelim + tg.tgMapGroup + ssc.gpDelim;
    }
    tgString = ssc.gpDelim + ssc.itDelim + ssc.listCriteria.currencySymbol + ssc.gpDelim + tgStrings.join('');
    ssc.tt("StFrAr-End StLen=" + tgString.length);
    return tgString;
},

vfsIsOpen: false,
vfsOpen: function () {   
    vfs_Opened();
	var tgHgtChange = 
	(((ssc.cp.vfsFilterAnimate || 'vertical-list') == 'vertical-list') ? ssc.fltrHgtMemory : 0)  - 
	(((ssc.cp.vfsImageAnimate || 'vertical-list') == 'vertical-list') ? ssc.vfsImageHgt : 0) -
	  $("#ssc_listBktHdr").height() -
      $("#ssc_listColHdr").height();
    ssc.tt("VFS O:" + " IHM=" + ssc.vfsImageHgt + " FHM=" + ssc.fltrHgtMemory + " LHM=" + ssc.listHgtMemory + " LHC=" + (tgHgtChange) + " animate " + " I:" + ssc.cp.vfsImageAnimate) + " F:" + ssc.cp.vfsFilterAnimate + " T:" +  ssc.cp.vfsMsecs;
	ssc.vfsMeasure("Ob   "); 
    $("#ssc_vfsImageDiv" + (1 - ssc.vfsActiveImage)).css({"opacity":"0"}); //make sure the inactive div is invisible.

	if ((ssc.cp.vfsImageAnimate || 'vertical-list').match('vertical'))  {
	     $("#ssc_vfsDiv").height(1);
	     $("#ssc_vfsDiv").animate({height:ssc.vfsImageHgt}, ssc.cp.vfsMsecs,null,ssc.vfsOpenDoneImage);
	} else {
	    $("#ssc_vfsDiv").height(ssc.vfsImageHgt);
	    if (ssc.cp.vfsImageAnimate.match(/corner/)) $("#ssc_vfsDiv").show(ssc.cp.vfsMsecs);
		else if (ssc.cp.vfsImageAnimate.match(/fade/)) $("#ssc_vfsDiv").animate({opacity:1.0},ssc.cp.vfsMsecs);
}
	if ((ssc.cp.vfsFilterAnimate.match(/list/ || ssc.cp.vfsImageAnimate.match(/list/))))  {
	    ssc.scrollMemory = $("#ssc_tktGroups").scrollTop();
	    $("#ssc_tktGroups").animate ({height:(ssc.listHgtMemory + tgHgtChange)},ssc.cp.vfsMsecs,null,ssc.vfsOpenDoneList);
	}
	if ((ssc.cp.vfsFilterAnimate || 'vertical-list').match(/vertical/)) $("#ssc_filterDiv").animate({height:0},ssc.cp.vfsMsecs,null,ssc.vfsOpenDoneFilter)
    ssc.vfsIsOpen= true;
},

vfsOpenDoneFilter: function () {
	ssc.vfsMeasure("OeF1");
	$("#ssc_filterDiv").hide();
	ssc.vfsMeasure("OeF2");
},
vfsOpenDoneImage: function () {
	ssc.vfsMeasure("OeI1");
},

vfsOpenDoneList: function () {
	ssc.vfsMeasure("OeL1" );
	$("#ssc_tktGroups").css("overflow","auto"); // to keep jQuery in Safari 3.3.2 from switching to "visible"
	ssc.tgBucketHdrCheck(); //check to see if we need to show a different bucket header
   // $("#ssc_tktGroups").scrollTop(ssc.scrollMemory);
	ssc.vfsMeasure("OeL2");
},

 vfsClose: function() {
    vfs_Closed();
	ssc.vfsMeasure("Cb   ");
	if (! ssc.vfsIsOpen) return;
	if ((ssc.cp.vfsImageAnimate || 'vertical-list').match(/vertical/i))  {
	    $("#ssc_vfsDiv").animate({height:1}, ssc.cp.vfsMsecs,null,ssc.vfsCloseDoneImage);
	} else {
	    $("#ssc_vfsDiv").hide(ssc.cp.vfsMsecs);
	}
	if ((ssc.cp.vfsFilterAnimate || 'vertical-list').match(/vertical/i)) $("#ssc_filterDiv").animate({height:ssc.fltrHgtMemory},ssc.cp.vfsMsecs,null,ssc.vfsCloseDoneFilter);
	if ((ssc.cp.vfsFilterAnimate.match(/list/i || ssc.cp.vfsImageAnimate.match(/list/i))))  {
	    ssc.scrollMemory = $("#ssc_tktGroups").scrollTop();
	    $("#ssc_tktGroups").animate ({height: (ssc.listHgtMemory - $("#ssc_listBktHdr").height() - $("#ssc_listColHdr").height())},ssc.cp.vfsMsecs,null,ssc.vfsCloseDoneList);
	}
    ssc.vfsIsOpen = false;
    ssc.ra("V","C");
},

vfsCloseDoneFilter: function () {
	ssc.vfsMeasure("CeF1");
	$("#ssc_filterDiv").height(ssc.fltrHgtMemory); // to correct cumulative animate error in IE
	ssc.vfsMeasure("CeF2");
},

vfsCloseDoneImage: function () {
	ssc.vfsMeasure("CeI1");
    $("#ssc_vfsDiv").css("display","none");
	ssc.vfsMeasure("CeI2");
},
 vfsCloseDoneList: function() {
	ssc.vfsMeasure("CeL1");
	ssc.tgBucketHdrCheck(); //check to see if we need to show a different bucket header
//	$("#ssc_tktGroups").scrollTop(100); // needed to "shake up" browser so next set scroll works
    $("#ssc_tktGroups").scrollTop(ssc.scrollMemory);
	//alert ("vfs close end. scroll temp=" + temp + " scroll=" + $("#ssc_tktGroups").scrollTop())

	//$("#ssc_tktGroups").css("overflow","auto"); // to keep jQuery in Safari 3.3.2 from switching to "visible"
	ssc.vfsMeasure("CeL2");
},
vfsMeasure: function(msg) {
    ssc.tt(" vfs" + msg + " IW:" + $("#ssc_vfsDiv").width()        + " IH:" + $("#ssc_vfsDiv").height()        + " ID:" + $("#ssc_vfsDiv").css("display") + " FW:" + $("#ssc_filterDiv").width() + " FH:" + $("#ssc_filterDiv").height() + " FD:" + $("#ssc_filterDiv").css("display") + " LW:" + $("#ssc_tktGroups").width() + " LH:" + $("#ssc_tktGroups").height() + " LO:" + $("#ssc_tktGroups").css("overflow") ) + " LD:" + $("#ssc_tktGroups").css("display");
},
vfsImageEntered: function (){
    if (ssc.mapStatus >= 3 && ssc.secInfo.sectionName) document["ssc_map"].sendSecEnteredToMap(ssc.secInfo.sectionName,'');
},
vfsImageExited: function () {
   if (ssc.mapStatus >= 3 && ssc.secInfo.sectionName) document["ssc_map"].sendSecExitedToMap(ssc.secInfo.sectionName);
},
 
vfsPan: function (LR) {
    ssc.vfsActiveImage = 1 - ssc.vfsActiveImage;
    $("#ssc_vfsImageDiv" + ssc.vfsActiveImage).css({'opacity' : '0'});
    ssc.vfsImageExited(); // turn off hilighting of old section on map
    ssc.showVFS((LR == 'L') ? ssc.secInfo.leftSectionName : ssc.secInfo.rightSectionName,LR, ssc.vfsPanOnload);
},
vfsPanOnload: function () {
    ssc.vfsImageEntered();
    $("#ssc_vfsImageDiv" + ssc.vfsActiveImage).animate({opacity:1}, ssc.cp.vfsMsecs,"linear",ssc.showVFSfinish);
    $("#ssc_vfsImageDiv" + (1 - ssc.vfsActiveImage)).animate({ opacity:0}, ssc.cp.vfsMsecs);
},

//=======================================================
oldmsg : "",
startTime : 0,
lastTime : 0,
eventLog : "",
tt: function (msg) {
  if (! ssc.cp.jsTrace) return;
  var timeNow = (new Date()).valueOf();
  if (ssc.startTime == 0) {
		ssc.startTime = timeNow;
		ssc.lastTime = timeNow;
   }
  if (! ssc.oldmsg) ssc.oldmsg= "<start> " + ssc.version;
  if (msg.match(/^\$/)) {
       msg = msg.slice(1);
      
      ssc.eventLog += ssc.env() + '|' + ssc.cp.staticMapURL.replace(/(^.+_.+)_.*/,'$1') + '|Tbl' + '|' + msg.replace(/:.*/,'') + '|' + String(timeNow - ssc.lastTime) + '|' + ssc.tgArray.length + '|' + ssc.sum(ssc.listBucketCts) +  String.fromCharCode(10);
     // alert (ssc.eventLog);
  }
  ssc.oldmsg += String.fromCharCode(10) +  ("____" + String(timeNow - ssc.startTime)).slice(-5) + " " + ("____" + String(timeNow - ssc.lastTime)).slice(-5) + ": " + msg ;
  ssc.lastTime = timeNow;
},

testFunc2: function(parm) {
	    //ssc.tt(" function2call Fltr:" + " MemHgt=" + ssc.fltrHgtMemory + " CurHgt=" + $("#ssc_filterDiv").height() + " Disp=" + $("#ssc_filterDiv").css("display")+ 
	    //"  List CurHgt=" + $("#ssc_tktGroups").height()+ " Oflo=" + $("#ssc_tktGroups").css("overflow"));
        confirm(ssc.eventLog);
        //ssc.tt ("func2 called. parm=" + parm);
       // ssc.tt (navigator.userAgent);
        //ssc.displayTT();
    },
msecSinceLoad: function() {
        return (new Date()).getTime() - ssc.cp.loadTime;
},

displayTT: function () {
    if ( ! confirm (ssc.oldmsg)) {ssc.oldmsg="";}
	ssc.startTime=0;
},
env: function () {
    var t = navigator.userAgent,
        b = ["Chrome","Safari","MSIE","Opera","Firefox"],
        i;
    for (i = 0;i<=4;i++) { if(t.match(b[i])) {return b[i]}}
    return "????"
}
}
 })(); // close out anonymous fucntion and invoke it to initialize everything.
// ================functions called dirctly by the map so left out of anonymous function for now ====================

// make note of sections not found on the map ( so display can be adjusted) and sections with Canonical name updated
function updateTGs (tgList) {
   ssc.tt ("$updateTGs-Start: #=" + tgList.length);
    for (var tgX = 0; tgX < tgList.length; tgX++) {
		ssc.tgArray[tgList[tgX].index].tgCanonSec = tgList[tgX].tgCanonSec;
		ssc.tgArray[tgList[tgX].index].tgOnMap    = ( typeof tgList[tgX].tgOnMap == "undefined") ? true : tgList[tgX].tgOnMap;
	}
	ssc.tt ("updateTGs-End");
}

// called from the Map

function setSelectedSections(secList) {
	ssc.listCriteria.selectedMapSections = secList || "";
	if (secList) {
		ssc.ra("S",secList.replace(/[^,]/g,'').length+1);
	} else {
		ssc.ra("S","0");
	}
	ssc.buildAndShowList();
return "OK";
}

function mapLoaded(code) {
    ssc.mapStatus = code; 
	// code =  -1 0 1 2 3 4
	ssc.tt ( (([0,0,1,0,0,1][code+1]) ? '$' : '') + "mapLoad" + code + "-St: docStat=" + ssc.docStatus)// + " If ==1 and >=2, will send TGs to map. msg="+msg)
    if (ssc.mapStatus < 0 ) {
		ssc.loadStaticMap('<span class="ssc_onMapMsg">Our interactive map is temporarily unavailable. Here is a plain version.</span>');
		ssc.buildAndShowList();
		ssc.raM("fE");// note that we got a load error
		ssc.cp.listAndMapLoaded(mapStatus);
    } else {
		if (ssc.mapStatus == 3) {
		    if ($("#ssc_staticMap").attr("src")) {$("#ssc_staticMap").remove();} // to handle (just IE6?) delay in loading swfs
		
		     document["ssc_map"].sendControlsToMap("id=ML&mouseWheel=-1" + ssc.mapOptionsHeld); //tell web we'll control zooming and send along any queued options
		     ssc.mapOptionsHeld = "";
		
	        if (ssc.docStatus >= 2) {
			    ssc.initializeMap("map");
		    }
		}
	}
	ssc.tt("mapLoad" + code + "-End");
}

function showVFS(sec) {
    return ssc.showVFS(sec,'M')
}

