// JavaScript for Browse Keyword interface

// Global variables
var currentStatus  = 4

var coordinates   // Coordinate Systems 
var fields        // Table fields to display
var format        // Output format
var keywords      // Table selection keywords
var metatables    // Metadata tables 
var positions     // Positions for cone searches
var qqualifiers   // Parameter qualifiers
var radius        // Radius of cone search queries
var rows          // Max number of rows to display
var tableCount    // Max number of tables to display
var missions      // Selected missions
var times         // Times/time ranges for queries
var unknown       // Unparseable tokens
var vizier        // Query vizier?
var windowTarget  // Browser target window

var nonMissions   // Tokens that are not mission names.
var testPosition

// Named constants
var COORD  = 1
var FIELDS = 2
var FORMAT = 3
var KEYWORD= 4
var META   = 5
var POSIT  = 6
var QUAL   = 7
var RADIUS = 8
var ROWS   = 9
var TABLES = 10
var TIME   = 11
var UNKNOWN= 12
var VIZIER = 13
var WINTAR = 14
var MISSION= 15

var DFT_TAB = 50
var DFT_ROW = 1000

var async_req

// Make a hash object
function makeHash(array) {
    var newObj = new Object()
    for (var i in array) {
        elem = array[i]
        newObj[elem[0]] = elem[1]
    }
    return newObj
}

var words = makeHash([
  ["J2000" ,   COORD],
  ["J2000" ,   COORD],
  ["B1950" ,   COORD],
  ["FK5"   ,   COORD],
  ["FK4"   ,   COORD],
  ["GALACTIC",   COORD],
  ["VIZIER",   VIZIER],
  ["ALL"   ,   FIELDS],
  ["TEXT"  ,   FORMAT],
  ["TABBED",   FORMAT],
  ["VO"    ,   FORMAT],
  ["PURE"  ,   FORMAT],
  ["TABLE" ,   FORMAT],
  ["FITS"  ,   FORMAT],
  ["EXCEL" ,   FORMAT],
  ["ZZGEN" ,   META],
  ["ZZEXT" ,   META],
  ["ZZPAR" ,   META],
  ["ZZBIB" ,   META],
  ["ZZLINK",   META],
  ["ZZDPSETS", META],
  ["ZZLINK",   META],
  ["ZZMASTER", META],
  ["ZZWORDS",  META],
  ["ZZDP"  ,   META],
  ["HERE"  ,   WINTAR] ])
  

var theMissions = makeHash([
  ["HST",    "HST"],
  ["HUBBLE", "HST"],
  ["ISO",    "ISO"],
  ["IUE",    "IUE"],
  ["MSX",    "MSX"],
  ["TD1",    "TD1"],
  ["UIT",    "UIT"],
  ["ASCA",   "ASCA"],
  ["GRO",   "CGRO"],
  ["CGRO",   "CGRO"],
  ["COMPTON","CGRO"],
  ["EUVE",   "EUVE"],
  ["FUSE",   "FUSE"],
  ["IRAS",   "IRAS"],
  ["OSO8",   "OSO8"],
  ["RXTE",   "RXTE"],
  ["XTE",    "RXTE"],
  ["BBXRT",  "BBXRT"],                
  ["COS B",  "COS B"],
  ["COS-B",  "COS B"],
  ["FAUST",  "FAUST"],
  ["GINGA",  "GINGA"],
  ["FERMI",  "FERMI"],
  ["HEAO1",  "HEAO1"],
  ["HEAO 1", "HEAO1"],
  ["ROSAT",  "ROSAT"],
  ["SAS-2",  "SAS-2"],
  ["SAS 2",  "SAS-2"],
  ["SAS-3",  "SAS-3"],
  ["SAS 3",  "SAS-3"],
  ["SWIFT",  "SWIFT"],
  ["UHURU",  "UHURU"],
  ["EXOSAT", "EXOSAT"],
  ["HETE-2", "HETE-2"],
  ["HETE 2", "HETE-2"],
  ["SUZAKU", "SUZAKU"],
  ["ASTRO E2", "SUZAKU"],
  ["ARIEL V", "ARIEL V"],
  ["ARIEL-V", "ARIEL V"],
  ["ARIEL 5", "ARIEL V"],       
  ["ARIEL-5", "ARIEL V"],
  ["CHANDRA", "CHANDRA"],
  ["AXAF",    "CHANDRA"],
  ["SPITZER", "SPITZER"],
  ["SIRTF",   "SPITZER"],
  ["VELA 5B", "VELA 5B"],
  ["VELA5B",  "VELA 5B"],
  ["BEPPOSAX","BEPPOSAX"],
  ["SAX",     "BEPPOSAX"],
  ["EINSTEIN","EINSTEIN"],
  ["INTEGRAL","INTEGRAL"],
  ["COPERNICUS", "COPERNICUS"],
  ["WMAP", "WMAP"],
  ["XMM-NEWTON", "XMM-NEWTON"],
  ["XMM",     "XMM-NEWTON"]])
  
for (var word in theMissions) {
    words[word] = MISSION
}
  
var coords = makeHash([
  ["J2000",   "J2000"],
  ["FK5",     "J2000"],
  ["B1950",   "B1950"],
  ["FK4",     "B1950"],
  ["GALACTIC","Galactic"]])
  
var modes = makeHash([
  ["VO",    "VODisplay"],
  ["TABBED","TabbedDisplay"],
  ["TEXT",  "TextDisplay"],
  ["FITS",  "FitsDisplay"],
  ["TABLE", "Display"],
  ["EXCEL", "ExcelDisplay"],
  ["PURE",  "PureTextDisplay"]])
  

var infoPages = new Array()


function colonExtract (val, prefix) {
    var match = colonMatch(val,prefix);
    if (match > 0) {
        return strip(val.substr(match+1))
    } else {
        return val
    }
}

function colonMatch (val, prefix) {
    var colons = val.split(":", 2)
    if (colons.length == 2 && colons[0].length > 0) {
        var ind = colons[0].length
	if (val.substr(0,ind) == prefix.substr(0,ind)) {
	    return ind
	}
    }
    return 0
}

function missPush(i, matches) {
    missions[missions.length] = theMissions[matches[i].toUpperCase()].toLowerCase();
    return 0
}
    

// Push a keyword.  Merge or'ed values
function keyPush(i, matches) {

    var token = colonExtract(matches[i], "keyword")
    var add   = 0
	
    while (i+add+1 < matches.length) {
	var test = matches[i+add+1]
	if (test.length > 3) {
	    var col = test.indexOf(":")
	    if (col > 0) {
	        if (test.substr(0,col) == "keyword".substr(0,col)) {
	            test = test.substr(col+1)
	        } else {
		    break
		}
	    }
	}
	if (token.charAt(token.length-1) == '|') {
	    add   +=  1
	    token +=  test
	} else if (test.substring(0,1) == '|' || test.toLowerCase() == "or") {
	    add   +=  1
	    token += "|"
	} else {
	    break
	}
    }
    keywords.push(token)
    return add
}

// Push a position.  Split or'ed values
function posPush(i, matches) {
    
    var token = colonExtract(matches[i], "position")
    
    if (token.match(/^[+\-\d\.\ ]*$/)) {
        return numPush(i, matches)
    } else {
        positions.push(token)
	return 0
    }
}

// Handle a position that may be a sequence of numbers
function numPush(i, matches) {
        
    var token = matches[i]
	
    var pos = 1
    if (token.match(/\./)) {
	pos = 3
    }
    var add   = 0
    var comma = 0
    var loopCount = 0
    while (pos < 6 && i + add + 1 < matches.length) {
	loopCount += 1
	if (loopCount > 6) {
	    break
	}
	
	var test = matches[i+add+1]
	    
	if (test == ",") {
	    if (comma > 0 || pos > 3) {
		break
	    } else {
		comma += 1
		add   += 1
		token += test
		continue
	    }
		
	}
	if (test == ";") {
	    // Skip it but don't concatentate it.
	    add += 1
	    break 
	}
	    
	if (test.match(/^([\+\-]?)\d+(\.\d*)?$/) ){
	    
	    if (RegExp.$1.length > 0) {
		if (pos < 3) {
		    break
		} else {
		    pos = 3
		}
	    }
		
            if (RegExp.$2.length > 0) {
		if (pos < 3) {
		    pos = 2
		} else {
		    if (pos == 3 && comma == 0) {
			token += ","
		    }
		    pos = 5
		}
	    }
	    if (pos == 3  && comma == 0) {
		token += ","
	    }
	    pos   += 1
	    add   += 1
		
	    token += " " + test
		
	} else {
	    break
	}
    }
	
    positions.push(token)
    return add
}

// Initialize the form.
function bqueryInit() {
    var text = document.getElementById("infoDiv").innerHTML
    infoPages.push(text)
    checkText()
    return true
}
   
// Display the information on a table.
function displayInfo(page) {
    
    var prefix = ""
    var dv     = ""
    if (page > 0) {
	prefix = "<a href=\"\" onClick='return displayInfo("+(page-1)+")'>Back</a>"
	dv     = " - "
    }
    if (page < infoPages.length-1) {
	prefix += dv + "<a href='' onClick='return displayInfo("+(page+1)+")'>Forward</a>"
    }
    if (prefix.length > 0) {
	prefix += "<p>"
    }
    var text = prefix + infoPages[page]
    document.getElementById("infoDiv").innerHTML = text
    return false
}


// Create a string for displaying the values in an array.
function addArray(prefix, arr, join) {
    
    var str = ""
    if (join == null) {
        join = " OR ";
    }
    
    if (arr.length > 0) {
        str = "<tr><th align=right>"+prefix+":</th><td>"+arr.join(join)+"</td></tr>"
    }
    return str
}


// Create a string for displaying a set of positions.
function addPositions(prefix, arr) {
       
    var str   = ""
    if (arr.length > 0) {
       
        str = "<tr><th align=right>"+prefix+":</th><td>"
	var i
	var dv = ""
	for (i=0; i<arr.length; i += 1) {
	    str += dv + "<a href='' onClick='return loadPosition(\"" + escape(arr[i]) + "\")'>"+arr[i]+"</a>"
	    dv = " OR "
	}
	str += "</td></tr>"
    }
    return str
}

// Display the text returned by the coordinate converter
function loadPosition(posit) {

    
    posit = unescape(posit)
    
    var url = "/cgi-bin/Tools/convcoord/convcoord.pl?NoCache=Y&"
    if (coordinates.length > 0) {
	var uc = coordinates[0].toUpperCase()
	if (uc == "B1950" || uc == "FK5") {
	    url += "CoordType=B1950&"
	} else if (uc == "GALACTIC") {
	    url += "CoordType=Galactic&"
	}
    }
    url += "CoordVal="+escape(posit)
    var req = getReq()
    req.open("GET", url, false)
    req.send(null)
	
    var text = req.responseText
    var xdiv  = text.split(/name=OldCoords/, 2)
    if (xdiv.length == 2) {
	ydiv = xdiv[1].split('<p>',2)
	if (ydiv.length > 1) {
	    zdiv = ydiv[1].split('<HR>', 2)
	    if (zdiv.length == 2) {
	        infoPages.push("<h2>Target/Position Resolver: "+posit+"</h2>"+ zdiv[0])
		displayInfo(infoPages.length-1)
		return false
	    }
	}
    }
    infoPages.push("<h2>Target/Position Resolver</h2>Unable to resolve coordinates: "+posit)
    displayInfo(infoPages.length-1)
    return false
}


// Display the text returned by a query
function loadResult() {
    
    var elems = document.primary.elements
    var xrl   = document.primary.action + "?"
    var len = elems.length
    var i
    var dv = ""
    for (i=0; i<len; i += 1) {
	if (elems[i].value.length > 0) {
	    var val = elems[i].value
	    xrl += dv + elems[i].name + '=' + escape(val)
	    dv = '&'
	}
    }
    var req = getReq()
    req.open("GET", xrl, false)
	    
    req.send(null)
	
    var text = req.responseText
    infoPages.push("<h2>Query Results</h2><pre>"+text+"</pre>")
    displayInfo(infoPages.length-1)
    return false
}
    
    
// Get rid of terminal space and enclosing quotes.
function strip (token) {
    
    var length = token.length
    if (length == 0) {
	return token
    }
    
    while (token.length > 0) {
	var code = token.charCodeAt(token.length-1)
	if (code <= 32) {  // Space or special
	    token = token.substr(0,token.length-1)
	} else {
	    break
	}
    }
	
    if (token.length < 2) {
	return token
    }
	
    if (token.charAt(0) == "'"  || token.charAt(0) == '"' &&
	token.charAt(token.length-1) == token.charAt(0)) {
	token = token.substr(1, token.length-2)
    }
	
    return token
}
    
// Allow flexibility in date format
function fixDate(dat) {
        
    if (dat.match(/^\s*(\d\d(\d\d)?)-(\d{1,2})-(\d{1,2})\s*$/)) {
	
        var year = RegExp.$1
	if (year < 50) {
	    year = "20"+year
	} else if (year < 100) {
	    year = "19"+year
	}
	var mn = RegExp.$3
	if (mn.length == 1) {
	    mn = '0'+mn
	}
	var dy = RegExp.$4
	if (dy.length == 1) {
	    dy = '0'+dy
	}
	return year+'-'+mn+'-'+dy
    } else {
	return dat
    }
}

// Allow flexibility in time format
function fixTime(tod) {
    if (tod.match(/^\s*(\d{1,2}):(\d{1,2})(:(\d{1,2})(\.\d*)?)?\s*$/)) {
	var hr = RegExp.$1
	var mn = RegExp.$2
	var sc = RegExp.$4
	
	if (hr.length == 1) hr = "0"+hr
	if (mn.length == 1) mn = "0"+mn
	if (sc.length == 1) sc = "0"+sc
	
	var time = hr+":"+mn
	if (sc.length > 0) {
	    time += ":"+sc+RegExp.$5
	}
	return time
    } else {
	return tod
    }
}

function initVars() {

    coordinates= new Array()
    format     = new Array()
    fields     = new Array()
    keywords   = new Array()
    metatables = new Array()
    positions  = new Array()
    qualifiers = new Array()
    rows       = new Array()
    tableCount = new Array()
    radius     = new Array()
    times      = new Array()
    unknown    = new Array()
    vizier     = new Array()
    missions   = new Array()
    windowTarget= new Array()
    nonMissions = new Array()
}

function massageText(text) {
    text = text.replace(/,/g, ' , ')
    text = text.replace(/;/g, ' ; ')
    text = text.replace(/\s+/g, ' ')
    return text
}
	

// Parse the input text string
function parseText() {

    //var text  = document.forms[0].tableinfo.value
    var text  = document.primary.tableinfo.value
    text      = massageText(text);
    
    initVars()

    var re = /(\w+\:)?('([^\'\\]*(?:\\.[^\'\\]*)*)\'\s?|"([^\"\\]*(?:\\.[^\"\\]*)*)\"\s?|([^\s]+)\s?|\s)/g

    var matches = text.match(re)
    if (text.length == 0  || matches.length == 0) {
	return false
    }

    var i
    for (i=0; i<matches.length; i += 1) {
	matches[i] = strip(matches[i])
    }

    var lastMission = false
    // Find everything except missions
    for (i=0; i<matches.length; i += 1) {
	if (matches[i].length == 0) {
	    continue
	}
    
        if (theMissions[matches[i].toUpperCase()] == null) {
	
	    if (lastMission && (nonMissions.length > 0) ) {
	    // We have a mission separating non-mission tokens,
	    // so we don't have target.  Just add a few tokens
	    // so that we don't treat the non-mission strings as a target.
	    // and we're done here
	         nonMissions.push(0)
		 nonMissions.push(0)  // Length is at least 3 now.
		 break
	     }
	
	    nonMissions.push(matches[i])
	    lastMission = false
	    
	} else {
	    lastMission = true
	}
    }
	    
    for (i=0; i<matches.length; i += 1) {
    
	token = matches[i]
	if (token.length == 0) {
	    continue
	}
	
	var type = parseToken(token)
	
	
	if (type == KEYWORD) {
	    i += keyPush(i, matches)
	} else if (type == MISSION) {
	    i += missPush(i, matches)
	} else if (type == POSIT) {
	    i += posPush(i, matches)
	} else if (type == TIME) {
	    i += processDate(i, matches)
	    
	} else if (type == TABLES) {
	    tableCount.push(colonExtract(token, "tables"))
	    
	} else if (type == FORMAT) {
	    format.push(token)
	} else if (type == VIZIER) {
	    vizier.push("Vizier")
	} else if (type == META) {
	    metatables.push(token)
	} else if (type == QUAL) {
	    qualifiers.push(token)
	} else if (type == COORD) {
	    coordinates.push(token)
        } else if (type == FIELDS) {
	    fields.push(colonExtract(token, "fields"))
	} else if (type == ROWS) {
	    rows.push(colonExtract(token, "rows"))
	} else if (type == RADIUS) {
	    radius.push(token)
	} else if (type == WINTAR) {
	    windowTarget.push(token)
	} else {
	    unknown.push(token)
	}
    }
    return true;
}

function parseToken(token) {

    if (token.indexOf(":") > 0) {
        if (colonMatch(token, "keyword")) {
	    return KEYWORD
	} else if (colonMatch(token, "position") ) {
	    return POSIT
	} else if (colonMatch(token, "rows")) {
	    return ROWS
	} else if (colonMatch(token, "fields")) {
	    return FIELDS
	} else if (colonMatch(token, "tables")) {
	    return TABLES
	}
    }
	
    var uc = token.toUpperCase()
	
    if (words[uc]) {
	return words[uc]

    } else if (token.match(/^\d{6}(\d\d)?[a-z]?$/i)) {  
         // check for GRB name before time
         return POSIT;
	    
    } else if (token.match( /^\d\d(\d\d)?-\d{1,2}-\d{1,2}/ )) {
	return TIME
	    
    } else if (token.match( /^\d{5,}/ )) {
	return TIME
	    
    } else if (token.match(/^[+\-\d\.\ ]*$/)) {
	return POSIT
	    
    } else if (token.match(/^([a-z]\w*)(!=|=|>=|<=|>|<)(.*)$/i)) {
	return QUAL
	    
    } else if (token.match(/^\-?[a-z].*$/i)) {
	
	// Vizier table names
	if (token.match(/^[ivjb].*\//i)) {
	    return KEYWORD
	    
	// Strings with embedded numbers or spaces are assumed to be targets
	} else if (token.match(/(\d\d|\s)/) ) {
	    return POSIT
	} else {
	    return KEYWORD
	}
		
    } else if (token.match(/^\d+(\.\d*)?['"]$/)) {
	return RADIUS
		
    } else if (token.match(/^\d/)) {
	return POSIT
		
    } else if (token == ";") {
	// Ignore
    } else {
	return UNKNOWN
    }
}

// Handle ISO data formats
function processDate(i, matches) {
    
    var add   = 0
    var token = matches[i]
    if (token.match(/^\d\d\d\d\d/)) {
        return processDate2(i, matches)
    }
    
    var test
	
    // Keep adding to the time until we either fill it
    // or the next token doesn't match what we need.
	
//  re =     /^ ([\d\-]+)  (\s+[\d\:\.]*)?  (\s*\.\.\s*  ([\d\-]+  (\s+[\d\:\.]*)?  )?  )? ([\,\;])?$/
    var re = /^([\d\-]+)(\s+([\d\:\.]*))?(\s*\.\.\s*(([\d\-]+)(\s+([\d\:\.]*))?)?)?$/
    var a1=""
    var a2=""
    var a3=""
    var a4=""
	    
    while (i+add < matches.length-1) {
	
	test = token + " "+matches[i+add+1]
        if (test.match(re) ){
	    a1 = RegExp.$1
	    a2 = RegExp.$3
	    a3 = RegExp.$6
	    a4 = RegExp.$8
	    token = test
	    add  += 1
		
	} else {
	    break
	}
    }
	
    if (add == 0) {
	if (token.match(re)) {
	    a1 = RegExp.$1
	    a2 = RegExp.$3
            a3 = RegExp.$6
	    a4 = RegExp.$8
	}
    }
	
    var res = token
    if (a1.length > 0) {
        res = fixDate(a1)
	
        if (a2.length > 0) {
	    res += " "+fixTime(a2)
	}
        if (a3.length > 0) {
	    res += ".."+fixDate(a3)
	}
	if (a4.length > 0) {
	    res += " "+fixTime(a4)
	}
    }
    times.push(res)
    return add
}

// Handle MJD format dates.
function processDate2(i, matches) {
    
    var add   = 0
    var token = matches[i]
    var test
	
    // Keep adding to the time until we either fill it
    // or the next token doesn't match what we need.
    var re = /^(\d{5,}(\.d*)?)(\s*\.\.\s*(\d{5,}(\.d*))?)?$/
    
    while (i+add < matches.length-1) {
	
	test = token+matches[i+add+1]
        if (test.match(re) ){
	    token = test
	    add  += 1
	} else {
	    break
	}
    }
	
    times.push(token)
    return add
}

// See what the user has entered and display results.
function checkText() {
    var status = parseText()
    var elem = document.getElementById('update')
    if (elem) {
        if (status) {
	    updateStatus(elem)
        } else {
	    elem.innerHTML = "<b>Query Specs: </b><br>No inputs specified"
        }
    }
	    
    if (currentStatus == 4) {
        elem = document.getElementById("countDiv")
	if (elem) {
	    if (keywords.length > 0  || missions.length > 0) {
	        updateCount(keywords, missions)
	    } else {
	        elem.innerHTML = "<b>Number of matching tables</b>: No table selection keywords or missions."
	    }
	}
    }
}
    
// Display the current status of what the user has entered/
function updateStatus(element) {
	
    var output = ""
	
    output += addArray("Keywords", keywords, " AND ")
    
    if (coordinates.length > 0) {
	output += "<tr><th align=right> Coordinates: </th><td>"+coords[coordinates[0].toUpperCase()]+"</td></tr>"
    } else {
	output += "<tr><th align=right> <font size=-2>Coordinates: </font></th><td><font size=-2> J2000 (default) </font></td></tr>"
    }
    
    
    if (tableCount.length > 0) {
	output += "<tr><th align=right> Tables: </th><td>"+tableCount[0]+"</td></tr>"
    } else {
	output += "<tr><th align=right> <font size=-2>Tables:</font></th><td><font size=-2>"+DFT_TAB+" (default)</font></td></tr>"
    }
    
    if (rows.length > 0) {
	output += "<tr><th align=right> Rows: </th><td>"+rows[0]+"</td></tr>"
    } else {
	output += "<tr><th align=right><font size=-2> Rows:</font> </td><td><font size=-2>"+DFT_ROW+" (default)</font></td></tr>"
    }
    
    if (fields.length > 0) {
	output += "<tr><th align=right> Fields: </th><td>"+fields[0]+"</td></tr>"
    } else {
	output += "<tr><th align=right><font size=-2> Fields:</font></th><td><font size=-2>Standard</font></td></tr>"
    }

    if (format.length > 0) {
	output += "<tr><th align=right> Format: </th><td>"+format[0]+"</td></tr>"
    }
	
	
    if (vizier.length > 0) {
	output += "<tr><th align=right> Vizier: </th><td> Yes </td></tr>"
    }
	
    output += addPositions("Positions", positions)
    if (radius.length > 0) {
	output += "<tr><th align=right> Radius: </th><td>"+radius[0]+"</td></tr>"
    }
    output += addArray("Times",         times)
    output += addArray("Missions",      missions)
    output += addArray("Qualifiers",    qualifiers)
    output += addArray("Meta",          metatables)
    output += addArray("Unknown",       unknown)
	
    if (output.length > 0) {
	output = "<table valign=top><tr><th colspan=2 align=center>Query Specs</th></tr>"+output+"</table>"
    }
	
    element.innerHTML = output
}

// Update the count of matching tables.
function updateCount(keywords, missions) {
   
    var fields    = ""
    if (keywords.length > 0) {
        fields   += keywords.join(" ")
    }
    if (missions.length > 0) {
        fields   += " "+missions.join("|")
    }
    
    var query     = fields
    currentStatus = 0
    async_req     = getReq()
    var url       = "/cgi-bin/W3Browse/checkWord?data="+escape(fields)
	
    if (vizier.length > 0) {
	url += "&vizier=1"
    }
    async_req.open("GET", url, true)
    async_req.onreadystatechange = processReturn
    async_req.send(null)
	
    return true
	
}

// Display information about a particular table.
function loadInfo(table) {
	
    var url 
    if (table.match(/\//)) {
	url = "/cgi-bin/W3Browse/vizdoc?"+table
    } else {
        url = "/W3Browse/all/"+table+".html"
    }
    
    var newWin = window.open(url, "helpWin", "resizable,height=500,width=500,scrollbars");
    newWin.focus();
    return false
}
	
// Display the list of currently selected tables.    
function infoTables() {
    
    infoPages = infoPages.slice(0,1)
	
    if (keywords.length == 0  && missions.length == 0) {
	infoPages.push("<h2> Tables selected. </h2> No keywords or missions specified yet. Please specify one or more keywords or missions")
    } else {
	var allKeys = ""
	if (keywords.length > 0) {
	    allKeys = keywords.join(" ");
	}
	if (missions.length > 0) {
	    allKeys += " "+missions.join("|")
	}
	var url = '/cgi-bin/W3Browse/tablesd.pl?data=' + escape(allKeys)+'&tables=1'
	if (vizier.length > 0) {
	    url += "&vizier=1"
	}
	if (tableCount.length > 0 && tableCount[0].toUpperCase() != "ALL" && tableCount[0].match(/^\d+$/)) {
	    url += "&maxtab="+tableCount[0];
	}
	if (tableCount.length == 0) {
	    url += "&maxtab="+DFT_TAB;
	}
        var req = getReq()
	
	req.open("GET", url, false)
	req.send(null)
	infoPages.push("<h2> Tables selected. </h2>"+req.responseText)
    }
    displayInfo(1)
    return false
}


// Handle the asynchonous call for getting the number of matching tables.
function processReturn() {
    
    if (async_req.readyState == 4) {
	if (async_req.status == 200) {
	    var elem = document.getElementById("countDiv")
	    if (elem) {
	        elem.innerHTML = "<b>Number of matching tables:</b> "+async_req.responseText +" (<a href='' onClick='return infoTables()'>List</a>)"
	    }
	} else {
	    alert("Error:"+async_req.statusText)
	}
	currentStatus = 4
    }
}

function simplePosition() {

    testPosition = nonMissions.join(" ");
    var req = getReq();
    var url =  "/cgi-bin/Tools/convcoord/convcoord.pl?CoordVal="+escape(testPosition,1)+"&Output=Batch&NoCache=Y";
    req.open("GET", url, false);
    req.send(null);
    var results = req.responseText;
    if (results != null) {
        var count = results.split('|').length;
	if (count > 6) {
	    return true;
	}
    }
    return false
}
    

// Handle a query submission request.
function doSubmit() {
        
    var stat = parseText()
    
    if (nonMissions.length == 1 || nonMissions.length == 2) {
        if (simplePosition()) {
	    var oldMissions    = missions;
	    initVars();
	    missions     = oldMissions
	    positions[0] = testPosition
	}
    }
    
    var limits = keywords.length + missions.length + positions.length + times.length + metatables.length
    if (limits == 0) {
	if (qualifiers.length > 0) {
	    alert("Currently Browse does not support queries of all tables with just a parameter "+
		  "qualifier.  You must select the tables to be searched using table selection "+
		  "keywords, or you can search all tables by time and/or position")
	    return false
		
	} else {
	    alert("You have not entered anything that defines the query results to be returned.\n"+
	      "Please select the tables to be searched using table selection "+
	      "keywords, or you can search all tables by time and/or position \n"+
	      " \n"+
	      "Please specify keywords to limit the tables and/or query criteria to limit "+
	      "the results to be returned.  E.g., to get all of the x-ray data on the Coma "+
	      "cluster just enter: \n"+
	      "\n"+
	      "   a1656 x-ray \n"+
	      "\n"+
	      "To get Chandra observations of the North galactic pole with long exposures you might try\n"+
	      "\n"+
	      "   chandra bii>80 exposure>20\n"+
	      "\n"+
	      "As you enter keywords the form will display the number of matching tables.\n"+
	      "Click on the list link to display the list. This may suggest further keywords to"+
	      "use.  Remember you can prefix a keyword with a dash to get rid of tables that match it.")
	}
	return false
    }
    
    var elem = document.getElementById("update")
    if (elem) {
        updateStatus(elem)
    }
	
    document.primary.tablehead.value   = ""
    document.primary.Entry.value       = ""
    document.primary.Time.value        = ""
    document.primary.Radius.value      = ""
    document.primary.Coordinates.value = ""
    document.primary.ResultMax.value   = ""
    document.primary.displaymode.value = ""
    document.primary.Fields.value      = ""
	
    if (positions.length > 0) {
	document.primary.Entry.value = positions.join(';')
    }
	
    if (times.length > 0) {
	document.primary.Time.value = times.join(';')
    }
	
    if (radius.length > 0) {
	var val = radius[0].substr(0,radius[0].length-1)
	if (val.length > 0) {
	    if (radius[0].charAt(radius[0].length-1) == '"') {
	        val /= 60
	    }
	    document.primary.Radius.value= val
	}
    } else {
	document.primary.Radius.value="Default"
    }
	
    if (coordinates.length > 0) {
	document.primary.Coordinates.value = coords[coordinates[0].toUpperCase()]
    } else {
	document.primary.Coordinates.value = "J2000"
    }
	
    if (rows.length > 0) {
	if (rows[0].match(/^\d+$/)) {
	    document.primary.ResultMax.value = rows[0]
	} else {
	    if (rows[0].toLowerCase() == 'all') {
	        document.primary.ResultMax.value = 0
	    } else {
	        if (!confirm("Max row count value is not an integer.  Click on Cancel to abort the request, or"+
		         " continue with the default ("+DFT_ROW+").\n"+
		         "\n"+
		         "Use rows:nnn to set the maximum number of rows to be displayed for a given table.")) {
	            return false
	        } 
	        document.primary.ResultMax.value = DFT_ROW
	    }
	}
    } else {
	document.primary.ResultMax.value = DFT_ROW
    }
    
    
	
    if (format.length > 0) {
	document.primary.displaymode.value = modes[format[0].toUpperCase()]
    } else {
        document.primary.displaymode.value = "TabbedDisplay"
    }
	
    if (qualifiers.length > 0) {
	
	var mx = qualifiers.length
	if (mx > 10) {
	    mx = 10
	}
	for (i=0; i<mx; i += 1) {
	    token = qualifiers[i]
	    
	    token.match(/^([a-z]\w*)((=|!=|>=|<=|>|<)(.*)|=(.+)(\.\.)(.+))$/i)
		
	    var name = RegExp.$1
	    var len  = name.length
		
	    if (len < 1) {
		continue
	    }
		
	    elem = eval("document.primary.v"+i)
	    var val = token.substring(len)
		
	    // For ranges we don't want to send the initial '='
	    if (val.match(/^\=.*\.\..*/)) {
		val = val.substring(1)
	    }
	    elem.value = val
	    elem.name  = "bparam_"+name.toLowerCase()
	}
    }
    
    if (positions.length == 0 && times.length == 0 && qualifiers.length == 0 && metatables.length==0) {
	if (!confirm("You have not entered any criteria for the search.\n\n "+
	             "If you want to display all rows in the matching tables just click  OK.\n"+
		     "To fix the query click Cancel\n\n"+
		     "Possible issues:\n "+
		     "  Is a target name being treated as a table keyword?  Use p:crab rather than just crab.\n"+
		     "  If a target has embedded spaces you may have to quote it. 'ty pyx' not just ty pyx.")) {
	    return false
	}
    }
	
    if (fields.length > 0) {
	document.primary.Fields.value = "All"
    } else {
	document.primary.Fields.value = "Standard"
    }
	
    var req = getReq()
	
    var maxTab = DFT_TAB
    if (tableCount.length > 0) {
	if (!tableCount[0].match(/^\d+$/)) {
	    if (tableCount[0].toLowerCase() == 'all') {
	        maxTab = 0
	    } else {
	        if (!confirm("Maximum table count value is not an integer.  Click on Cancel to abort the request, or"+
		         " continue with the default ("+DFT_TAB+").\n"+
		         "\n"+
		         "Use tables:nnn to set the maximum number of rows to be displayed for a given table.")) {
	            return false
	        } 
	        maxTab = DFT_TAB
	    }
	} else {
	    maxTab = tableCount[0];
	}
    }
    if (keywords.length > 0  || missions.length > 0) {
    
        var currVal = ""
	if (keywords.length > 0) {
	    currVal = keywords.join(" ")
	}
	if (missions.length > 0) {
	    currVal += " "+ missions.join("|")
	}
	
	url  = "/cgi-bin/W3Browse/checkWord?tables=1\&data="+escape(currVal)
	if (vizier.length > 0) {
	    url += "&vizier=1"
	}
	req.open("GET", url, false)
	req.send(null)
	if (req.responseText.length < 3) {
	    var elem = document.getElementById("countDiv")
	    if (elem) {
	        elem.innerHTML = "Table count: 0"
	    }
	    alert("No matching tables.\n\n"+
	          "Did you forget to enclose positions/targets with spaces in quotes ('ty pyx' rather than ty pyx)?"+
	          "Maybe you can try using fewer or different keywords.\n"+
		  "You can start with very general keywords, e.g., x-ray or star, and take a look at the number "+
		  "of tables returned to the right as you increase the number of table keywords.\n\n" +
	          "Normally tables are matched when their metadata has words in it which match all of the "+
	          "specified keywords.  You can 'OR' keywords together by using '|'.  E.g.,\n"+
	          "ascamaster|wgacat\n"+
	          "will match both of those catalogs (and the DXRBS catalog which has WGACAT in its description).")
	     return false
	}
	     
	document.primary.tablehead.name  = 'tablehead'
	var text = req.responseText
	    
	while (text.length > 0 && text.charCodeAt(text.length-1) < 32) {
	    text=text.substr(0,text.length-1)
	}
	
	var tables = text.split(",")
	
	tables = getMaxTables(tables, maxTab, vizier.length)
	if (metatables.length == 0) {
	    for (var it=0; it<tables.length; it += 1) {
		// Escape doesn't handle '+' without the 1 argument...  Do modern IE's work with this?
		var bef = tables[it]
	        tables[it] = escape(tables[it], 1)
		tables[it] = tables[it].replace("+", "%2B")
	    }
	    document.primary.tablehead.value = 'name='+tables.join("%00")
	    
	} else {
       	    if (text.length > 0) {
	        text = text.replace(/,/g, ";")
       	        elem = eval("document.primary.v"+qualifiers.length)
		elem.name  = "bparam_table_name"
		elem.value = tables.join(";")
	    }
	}
    } else {
	document.primary.tablehead.name  = 'notables'
    }
	
    if (metatables.length > 0) {
	document.primary.tablehead.name  = 'tablehead'
	document.primary.tablehead.value = 'name='+metatables.join('%00')
    }
    
    if (windowTarget.length > 0) {
	loadResult()
	return false
    } else {
	return true
    }
}

// Get the maximum tables from both the HEASARC and Vizier lists.
function getMaxTables(tables, maxTab, vizier) {
    if (maxTab == 0  || tables.length <= maxTab) {
        return tables
    }
    
    if (vizier <= 0) {
        return tables.slice(0,maxTab);
    } 
    
    var vs;
    for (vs=0; vs<tables.length; vs += 1) {
        if (tables[vs].indexOf('/') > 0) {
	    break
	}
    }
    // All or none in Vizier
    if (vs == 0  || vs == tables.length) {
        return getMaxTables(tables, maxTab, 0)
    }
    
    var t1 = getMaxTables(tables.slice(0,vs), maxTab, 0)
    var t2 = getMaxTables(tables.slice(vs, tables.length), maxTab, 0)
    return t1.concat(t2)
}
	
    
    
// Need to handle the updates to the innerhtml elements
// that the reset implicitly changes.
function doReset() {
    document.primary.reset()
    checkText()
    return false
}

// Try to support IE.
function getReq() {

    var req = false
    try {
        req = new ActiveXObject("Msxml2.XMLHTTP")
    } catch (e) {
        req = false
        try {
            req = new ActiveXObject("Microsoft.XMLHTTP")
        } catch (ex) {
            req = new XMLHttpRequest()
        }
    }
    return req
}

// Add some text to the window.
function addText(text) {
    var re = new RegExp("\\b" + text + "\\b")
    var content  = document.primary.tableinfo.value
    if (!content.match(/re/i)) {
        document.primary.tableinfo.value += " "+text;
    }
}

// Delete some text from the window.
function delText(text) {
    var content  = document.primary.tableinfo.value
    var re = new RegExp("\\b( )?" + text + "\\b")
    content = content.replace(re, "");
    re = new RegExp("^\\s{1,}");
    content = content.replace(re, "");
    document.primary.tableinfo.value = content
}

function doText(elem, text) {
    if (elem.checked) {
        addText(text)
    } else {
        delText(text);
    }
    return true;
}
    
        



