// Debug thru #14
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var pe_copyright = "<br><a href=\"javascript: top.about_pe()\">" +
		"Protein Explorer &copy; 2005 by Eric Martz</a>";

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function set_atoms_model1()
{
//	alert("util_top.js #2 top.atoms_selected=" + top.atoms_selected + "\n" +
//		"top.last_model=" + top.last_model + "\n" +
//		"top.cmp_at_top=" + top.cmp_at_top + "\n" +
//		"top.expert=" + top.expert + "\n" +
//		"top.chime_is_busy()=" + top.chime_is_busy(false));

	if (top.last_model > 1) // even if expert! see snmrview1 in loadit2.js
		top.atoms_model1 = top.atoms_selected;
	else
		top.atoms_model1 = -1; // for one-model PDB files

//	alert("util_top.js #3 atoms_model1=" + atoms_model1);
}

// Rather than complex logic to decide expert and which page we're on,
// it will work well enough to just test for all and model 1.

// This scheme fails in QuickViews for NMR models in expert mode:
// the present scheme for set_atoms_model1() is not called b/c model 1
// is not selected in FirstView.

function all_atoms_selected()
{
//	if (top.last_model <= 1 || top.expert ||
//		(top.control_page != "quickvs" && top.control_page != "load-pdb"))
//		return (top.atoms_total);
//	else
//		return (top.atoms_model1);

// top.atoms_model1 is -1 when non-NMR, see set_atoms_model1()

	if (top.atoms_selected == top.atoms_total ||
		top.atoms_selected == top.atoms_model1)
			return true;
	else return false;
}

// "SPEED": Time tests for one 'select temporary' e.g. in Water toggle
// Note that atgcu and polarity color schemes have multiple select temp's!
// P5 = polarity5 color scheme. 2d = Secondary button.
// S = SLOW = 300 MHz P2, F = FAST = 800 MHz P3
// General goal: don't warn for 30" on SLOW machine.
// These molecules are available in PDBTYPES.HTM
//                                                      P5/1   S/F
// 1ffk 65K atoms (NUCLEIC!), S: 70"     F: 23".               3.0
// 1aon 59K atoms             S: 58"     F: 18", P5 97" 5.3X   3.2
// 1g3i 45K atoms             S: 32"     F:  8", P5 42" 5.2x   4
// 7ahl 23K atoms,                       F:  3", P5 8"  2.6X
// 1k28.mmol 21K atoms        S:  ~5 sec
// 1aol 12K atoms             S:  ~2 sec

// It is much faster to 'select a and tmp' than to 'select tmp and a',
// provided a (adenine) is a small subset of tmp.

// Seconds on reference computer for atoms selected in 1g3i (45K total) with
// select atomno<=N (667 MHz P3)
// -----------------------------------------------------------------
// No. Atoms    Water    Polarity3   Polarity5
//  1,000       2, 1     3, 3        3, 3
//  5,000                            11, 10
// 10,000       4, 4     13, 13      20, 21
// 40,000       10,11,12 38,39       60,61
// -----------------------------------------------------------------

// Rationale for predicted_sec()
// 1. The time for select temp, where temp is constant 45K atoms, varies with
//   the total number of atoms, from 8" (45K tot) to 37" (98K tot).
//   Therefore the predicted sec should increase faster than linearly
//   with the total number of atoms.
// 2. For a given total, time is roughly linear with selected atoms.

var threshold_sec = 12.0;
var slowness_tog = 1.0;
var slowness_cs = 2.5; // up to 5 for Polarity5, see data above

// predicted_sec() is based on the following data for Mz8 800 MHz PIII.
// From these data, slowness_cs = ~2.5.
// (all atom counts in thousands, obs/pred in seconds; eqtn Diana Ditmore)
// pdb   total selected  obs  pred   obs-pol2  factor obs-acgtu  factor
// 1g3i  45    12         4    3.6   10        2.5
//             45         8   13.5   27        3.4

// 1ffk  65    12         5    5.2                    12          2.4
//             30        10    9                   
//             45        23   19.5                    39          1.7

// 1jsa  73    12 (4mod)  5    6   
// (all mods)  45 (15md) 24   22

// 1jj2  98    12         8    8                      17          2.1
//             29        17   19
//             45        37   29.4                    90          2.4

function predicted_sec(n) // predict_
{
	var tot = parseFloat(top.atoms_total)/1000.;
	var sd = parseFloat(n)/1000.;
	var ps = (((tot * sd)/150.) / chime_speed); // thanks to Diana Ditmore!

	if (top.watch_chime_speed)
	{
		echo("Predict " + Math.ceil(ps - 0.5) + // toInteger (rounded up)
			"\" (threshold " + threshold_sec + "\")");
	}
	return ps;
}


function confirm_huge(slowness) // slower is slowness_tog or slowness_cs
{
	if (all_atoms_selected())
		return true;

	var ps = predicted_sec(top.atoms_selected) * slowness;
//	alert("util_top.js #9 ps " + ps);
	if (ps < threshold_sec)
		return true;

	var v = "";
	if (ps > 2 * threshold_sec)
		v = " VERY";
	if (ps > 4 * threshold_sec)
		v = " VERY VERY";

	var m = "Warning: this operation may take a" + v + " long time\n" +
		"because of the large subset of atoms selected.\n" +
		"FAST solution: Cancel, SELECT All, then re-do.\n" +
		"SLOW solution: Click OK (the current selection is preserved).\n";
	if (confirm(m))
		return true;
	else return false;
}

// when 'select temporary' has to be used multiple times, e.g.
// atgcu and polarity color schemes as .spt files (see 0notes.txt re
// converting them to javascript and using all_atoms_selected() to omit
// select temp's.

function select_all()
{
	if (top.last_model <= 1 ||
		(top.expert && top.control_page != "quickvs") ||
		(top.control_page != "quickvs" && top.control_page != "load-pdb"))
		return ("select all;\n");
	else
		return ("select model=1;\n");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function clean_word_string(to_do)
{
	// replace newlines with spaces
	var re = /\n/g;
	to_do = to_do.replace(re, " ");
	var re = /\r/g;
	to_do = to_do.replace(re, " ");

	// replace tabs with spaces
	var re = /\t/g;
	to_do = to_do.replace(re, " ");

	re = /  /g; // two spaces
	// collapse any multiple spaces to single spaces
	while (to_do.indexOf("  ") != -1)
		to_do = to_do.replace(re, " ");

	// trim off leading spaces
	while (to_do.charAt(0) == " ")
		to_do = to_do.substring(1);
	return to_do;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function trim_ends(s)
{
	// \t,\n to spaces, spaces singularized, leading spaces trimmed
	s = top.clean_word_string(s);

	// trim trailing end
	while (s.charAt(s.length - 1) == " ")
		s = s.substring(0, s.length - 1);
	return s;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function pad_right(w, v)
{
	var s = "" + v; // cast to string
	var l = s.length;
	while (l < w)
	{
		s = " " + s;
		l++;
	}
	return (s);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function valid_pdbid(pid, announce)
{
	var valid = true;

// Last character can be a digit, e.g. 12e8, 15c8, 1a00-09 - 1a9[n], 3bc2,
// 3f58, 3fx2, 5cp4
// It appears likely that at least one letter must occur. NOPE:
/*
April 11, 2000:
You are correct that the first digit must be numeric and that the remaining
digits may be either numbers or letters.  However, there is no restriction
that one position must be a letter.  Therefore:
1111 is a valid ID whereas b111 is not.

I do not believe there is an existing ID with all digits and no letters.

Rachel Kramer
RCSB PDB
*/

	if (pid.length != 4)
		valid = false;

	// 1st char must be a digit	
	var ci = pid.charAt(0);
	if (ci < '1' || ci > '9') // PDB Format HEADER: structures don't begin 0
		valid = false;

	// 2nd-4th chars must be letter or digit
	pid = pid.toLowerCase();
	for (i = 1; i <= 3; i++)
	{
		ci = pid.charAt(i);
		if ((ci < 'a' || ci > 'z') && (ci < '0' || ci > '9'))
			valid = false;
	}
	if (!valid && announce)
		say_bad_pdbid(pid);
	return valid;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function say_bad_pdbid(id)
{
	alert("ERROR: \"" + id + "\" is not a valid PDB ID code.\n" +
		"PDB ID codes are 4 characters long and begin with\n" +
		"a digit in the range 1-9.");
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function strip_pdb(pname)
{
	var j = pname.indexOf(".pdb");
	if (j != -1)
		pname = pname.substring(0, j);
	return(pname);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function chime_is_busy(say_so)
{
	if (top.chime_busy || typeof(top.fstak[0]) == "function")
	{
		if (typeof(say_so) != "undefined")
		{
			if (say_so)
				top.say_busy();
		}
		return true;
	}
	return false;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function say_busy(ss)
{
	var msg = "REQUEST IGNORED:\n";
	if (top.debug_show_all_scripts && typeof(ss) != "undefined")
		msg += "\"" + ss + "\"\n";

	msg += "Sorry, Chime is busy.  Please wait\n" +
			"a few moments for Chime to catch up and\n" +
			"then try your request again.";
	msg += "\n(If you believe Chime is not busy,\n" +
		"click Force Ready below the message box.)";

	alert(msg);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function quit_pe()
{
	if (top.chime_is_busy(true))
		return; // do nothing

	if (top.expert)
	{
		top.window.close();
		return; // in IE, execution continues below despite window.close()!
	}

	var qmsg = "Quit session\n\"" + top.session_name.replace("_", " ") + "\"?";
//	if (confirm("Quit Protein Explorer?"))
	if (confirm(qmsg))
		top.window.close();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function beg()
{
	with (document)
	{
		writeln("<font color=red>For-profit users:</font>");
		writeln("please <a href=\"donation.htm\">make a donation</a>");
		writeln("to support development of this software.");
	}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function load_special_common()
{
	if (top.pref_spinning)
		top.spin = true;
	else
		top.spin = false;
//	top.water = 1; // 0, 1, 2 // NOW A PREF HANDLED IN LOADIT2.JS
	top.hetero = true;
	top.slab = false;
	top.nmr_m1_water_said = false;
	top.nmr_m1_ligand_said = false;
	for (i = 0; i <= 8; i++)
		top.surfex[i] = "";
	top.catpi_cycle1 = true;
//	top.previously_selected_atom_count = 0;
	top.previously_click_selected_count = 0;
	top.saved_selected_count = 0;

	top.set_atoms_model1();
	top.show_atoms_selected();
	top.saved_atom_total_sets = 0;

//	alert("util_top.js #6 setting ready");
	// See loadit2, which sets an extra busy!
	top.setCBusy(false, "ready");

	finish_pdbheader() //jpd
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

var timeout_handle = false;

function clear_ld_timer()
{
//	alert("timeout_handle = " + timeout_handle);

//	clearTimeout(top.timeout_handle); fails to stop timeout action

	top.timeout_handle = false; // THIS WORKS

//	alert("timeout CLEARED");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function undotdot(path)
{
//alert(path);
	var dd = path.indexOf("..");
	while (dd != -1)
	{
		ddl = path.lastIndexOf("/", dd - 3);
		path = path.substring(0, ddl) + path.substring(dd + 2);
		dd = path.indexOf("..");
//alert(path);
	}
//alert(path);
	return (path);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function show_msa3d_result_page()
{
	// this occasionally fails despite use of fstak, so give it a delay.
	// 500 not enough.
	// 1000 makes it fail 100%!

	// This code fails intermittantly.
//	if (top.chime_is_busy(false))
//		setTimeout("top.show_msa3d_result_page()", 500);
//	else
//		top.fr_control.fr_ur.traverse_link('msa3dr2.htm');

// Supposedly, this function is not called until Chime is ready!
// It is called with do_waiting_sptfunc() in funcstak.js

		setTimeout("top.show_msa3d_result_page2()", 1000);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function show_msa3d_result_page2()
{
	if (top.chime_is_busy(false))
		setTimeout("top.show_msa3d_result_page2()", 200);
	else
		top.fr_control.fr_ur.traverse_link('msa3dr2.htm');
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function show_string_in_window(dbody, t, w, h)
{
//	alert("util_top.js #1 dbody\n" + dbody);
//	alert("util_top.js #1 t\n" + t);

	var wp = "";
	if (typeof(h) != "undefined")
	{
		wp = "scrollbars=1,menubar=1,resizable=1," +
			"width=" + w + ",height=" + h;
		ShStWin=window.open("", "ShStWinT", wp);		
	}
	else
		ShStWin=window.open("", "ShStWinT");

	with (ShStWin.document)
	{
		open();
		writeln("<html><head>");
		if (typeof(t) != "undefined")
			writeln("<title>" + t + "</title>");
		writeln("</head><body>");
		writeln(dbody);
		writeln("</body></html>");
		close();
	}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function refresh_qv_chain_options()
{
// index 5 is the 6th item, i.e. 0-5
//	alert("util_top.js #4: SELECT menu option 5 is " +
//		top.fr_control.fr_ur.qvtop.document.qv.mselect.options[5].value);

	// THE FOLLOWING MUST BE ADJUSTED WHEN THE SELECT MENU IS CHANGED:
	// Position of first chain in menu, counting SELECT (null op) as #1.
	var qv1st_chain = 8; // index is qv1st_chain - 1.
	var od = new Array("Residue", "Range", "Solvent",
		"Water", "Ligand", "Element",
		"Hydrogen", "", "Clicked", "Saved",
		"Inverse", "Neighbors", "",
		"Helices", "Strands", "Alpha C",
		"Backbone", "Sidechain", "Neutral",
		"Aromatic", "Hphobic", "Polar",		
		"Charged", "Acidic", "Basic",
		"Cysteine", "Cystine");
	var ov = new Array("g", "r", "v",
		"w", "l", "e",
		"h", "-", "=", "<",
		"!", "ne", "-",
		"2h", "2s", "ac",
		"b", "s", "%neutral",
		"%aromatic", "%hydrophobic", "%polar",
		"%charged", "%acidic", "%basic",
		"%cys", "%cystine");
	// count of menu items after chains (count in above arrays).
	var after_chains = 26;

	var cc = top.acf_chains;
	if (top.application_id == "comparator" && !top.cmp_at_top)
		cc = top.acf2_chains;

//	alert("util_top.js #5 chains |" + cc + "|\nlength " + cc.length);
	// if there is only one chain with no name, cc==" ", don't put in
	// a menu entry; but if it has a name, put it in.
	// Example of why: 1cq2 includes heme in the one chain :a.
	var ccount = cc.length;
	if (ccount == 1 && cc == " ")
		ccount = 0;

//	if (cc.length > 1)
//	{
		for (i = 0;
			(i < ccount && (i == 0 || cc.charAt(i) != cc.charAt(0))); i++)
		{
			var o = new Option("Chain " + cc.charAt(i), "c" + cc.charAt(i));
			top.fr_control.fr_ur.qvtop.document.qv.mselect.options[qv1st_chain + i - 1] = o;
		}
//	}

	var chain_positions = 4;

	// guarantee 4 options positions for chains (some blank if ccount < 4)
	for (i = chain_positions; i > ccount; i--)
	{
		var o = new Option("", "c");
		top.fr_control.fr_ur.qvtop.document.qv.mselect.options[qv1st_chain + i - 2] = o;
	}

//	var maxl = (qv1st_chain - 1) + ccount + after_chains; // was 17
//	if (cc.length > 4)
//		maxl = cc.length - 4 + maxl;
//	top.fr_control.fr_ur.qvtop.document.qv.mselect.length = maxl;

	var start_last5 = 4 + qv1st_chain - 1; // lowest possible position
	if (cc.length > 4)
		start_last5 = cc.length + qv1st_chain - 1;
	for (i = 0; i < after_chains; i++)
	{
		var o = new Option(od[i], ov[i]);
		top.fr_control.fr_ur.qvtop.document.qv.mselect.options[i + start_last5] = o;
	}
	setSelectedIndex(top.fr_control.fr_ur.qvtop.document.qv.mselect, 0);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function do_center()
{
	if (!confirm(
		"Click OK to center one atom\n" +
		"by clicking on it.\n" +
		"Cancel to center the currently selected\n" +
		"group of atoms."))
	{
		var s = "center selected\n";
		s += "move 0 0 0 +1 0 0 0 0 0.1\n";
		top.echo_msgs = true;
		top.s2c(s);

		if (top.control_page == "quickvs")
		{
			top.fr_control.fr_ur.qv_msg = "center_sel_msg";
			top.fr_control.fr_ur.say_main_msgn();
		}
	}

	else

//	if (confirm(
//		"Click OK for the next click on an\n" +
//		"atom to make it become the center of\n" +
//		"rotation and zooming. Traces and\n" +
//		"cartoons don't work well for this."))
	{
		top.pick_center_once = true;
		top.echo_msgs = true;
		top.s2c("set picking center");

		if (top.control_page == "quickvs")
		{
			top.fr_control.fr_ur.qv_msg = "center_pick_msg";
			top.fr_control.fr_ur.say_main_msgn();
		}
	}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var clear2a_msg =
"OK to clear ";

var clear2b_msg =
" selected atoms to zero\n" +
"before accumulating clicked selections.\n" +
"Cancel to add clicked to currently selected.";

function exec_set_picking(show, bool, cmd)
{
	var clear2_msg = clear2a_msg + top.atoms_selected + clear2b_msg;

	var s;
	switch(top.set_picking)
	{
		case "i":
			s = "set picking identify\n";
			break;
		case "d":
			s = "set picking distance\n";
			break;
		case "m":
			s = "set picking monitor\n";
			break;
		case "a":
			s = "set picking angle\n";
			break;
		case "t":
			s = "set picking torsion\n";
			break;
		case "l":
			s = "set picking select;show selected off;select none\n";
			top.label_picked = true;
			break;

		case "1":
			s = "set picking select atom\n";
			break;
		case "2":
			s = "set picking select residue\n";
			break;
		case "3":
			s = "set picking select chain\n";
			break;
	}
	switch(top.set_picking)
	{
		case "1":
		case "2":
		case "3":
//			if (bool == 0)
//				setTimeout("alert(top.clear2_msg)", 500);

				if (confirm(clear2_msg))
					s += "select none\n";

			break;
		default:
			s += "show selected false\n";
	}
	s += cmd; // for saving click-selected set

	if (show == "echo")
		top.echo_msgs = true;
	else
		top.echo_msgs = false;
	top.s2c(s);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function filetype(fn)
{
	fn = top.just_filename(fn);
	var i = fn.lastIndexOf(".");
	if (i == -1)
		return "";
	fn = fn.substring(i + 1);
	return fn;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function squash(s)
{
	// delete all spaces
	var i;
	while ((i = s.indexOf(" ")) != -1)
		s = s.substring(0,i) + s.substring(i + 1);
	return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// New strategy for spin control in PE 2.2:
// Spin will stop automatically without confirmation after 3 minutes.
// There will be a button in qv_msg spin help for "non-stop spin",
// alias nss.
// In PiPE Audience mode, non-stop spin will be the default.
//
// Former, still active spin variables:
// top.spin
// top.spinStopDelay
// top.spinStopDelayDefault
// top.spinTimeoutHandle
//
// New spin variables:
// top.nonStopSpin
//
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function spinstop()
{
	top.spinTimeoutHandle = null;

	if (!top.spin)
		return;

	if (top.nonStopSpin)
		return;

	if (top.chime_is_busy(false))
	{
		setTimeout("spinstop()", 1000);
	}
	else
	{
		top.s2c("spin off\n# Enter alias nss for non-stop spinning.");
		top.spin = false;
	}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This function, being owned by top, means that the timeout is not owned
// by a disappearing frame or document.
function set_spinstop()
{
	if (top.spinTimeoutHandle != null)
		clearTimeout(top.spinTimeoutHandle);		

	if (top.nonStopSpin)
		return;

	if (top.pipemode == "a") return; // Audience, non-stop spin is default

	top.spinTimeoutHandle = setTimeout("top.spinstop()", top.spinStopDelay);

//			alert("spinTimeoutHandle=|" + top.spinTimeoutHandle + "|");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function format_path(p)
{
	if (top.client_os == "mac")
		return (p); // no reformatting needed

	// C:\ -> c|/
	p = p.replace(/\\/g, "/");
	p = p.replace(/:/, "|");
	p = p.toLowerCase();

	return (p);
}

function make_pdbcode_url(toload)
{
	// GET mirror
//alert("util_top.js make_pdbcode_url(" + toload + ")");
	var mirror = top.getCookie("pe_pdbid_mirror");
//	alert("fetch_bnl mirror = " + mirror);
	if (mirror == null || mirror == "")
		mirror = top.default_pdb_url; // once www.pdb.bnl.gov, now www.rcsb.org

// RCSB server discontinued as an option in PE 2.78, see linkto.js
//	if (top.server_id == "rcsb") // internal/local mirror fetching
	// but see below for going to rcsb from elsewhere
//	{
//		mirror += "pdb/cgi/export.cgi/" + toload + ".pdb?";
//		mirror += "comp=chime&pdbId=" + toload;
//	}
//	else
//	{

		if (top.control_page == "right1ld")
		{
			if (!top.confirm_net_fetch(toload, mirror))
				return "";
		}

		// RCSB:
 		// MIRROR LIST THAT MUST BE MAINTAINED TO CORRESPOND TO shared/mirror.htm
		// In January 2006, RCSB abolished all mirrors! See mirror.htm
		if (mirror.indexOf("rcsb.org") != -1)
		{
			// NEW URL for RCSB as of January 2006:
			// www.rcsb.org/pdb/files/1d66.pdb.gz 
			// For RCSB, mirror = "http://www.rcsb.org/pdb" (see default_pdb_url)

			// COMPLETE RCSB URL
			if (mirror.charAt(mirror.length - 1) != "/")
				mirror += "/";
			mirror += "files/" + toload + ".pdb.gz";
		}

		// BNL query parameter
		// in PE1.98, pdb-bin no longer worked at India, but oca-bin did.
//		else if (mirror.indexOf("pdb.icm.edu.pl") != -1)
//			mirror += "pdb-bin/send-x-pdb?id=" + toload;

		// OCA query parameter
		else
		{
			mirror += "oca-bin/send-x-pdb?id=" + toload;
		}

//alert("util_top.js make_pdbcode_url returns:\n" + toload);

	return (mirror);

}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function confirm_net_fetch(toload, mirror)
{
		var msg = "Requesting " + toload + ".pdb via Internet\n" +
						"from the PDB at ";
		msg += mirror;
		msg += "\n\n" +
			"If you wish to specify a closer or different\n" +
			"PDB mirror site, ";
		if (top.control_page == "right0")
			msg += "press the [Change PDB URL] button.";
		else if (top.control_page == "load-pdb")
			msg += "Cancel, use PDB Mirror button.";
		else
			msg += "Cancel, press [?] at the PDB ID slot.";

		if (top.client_os == "mac")
			msg += "\n\n" +
				"If you are not on the Internet, or you wish to\n" +
				"change PDB mirrors first, press Cancel.\n";
		else
			msg += "\n\n" +
				"If you are not connected to the Internet, or you\n" +
				"wish to specify a different PDB mirror, press Cancel.\n";

		if (!confirm(msg))
			return false;
		return true;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function ul_corner(x, y)
{
	var s = ",";
	if (top.isIE) // not isgecko?
		s += "top=" + y + ",left=" + x;
	else
		s += "screenY=" + y + ",screenX=" + x;
	return(s);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// cntail = Chime Name Tail, unique chime names required for
// concurrent sessions in IE
function cntail()
{
	// IF PE IS OFF-LINE/LOCAL, SUFFIX CHIME NAME WITH 'F'.
	// THIS PREVENTS NAME CONFLICTS WHEN PE IS BEING USED
	// CONCURRENTLY ON-LINE AND OFF-LINE (NUMBERS MAY BE THE SAME).
	var f = "";
	if (top.document.location.href.substring(0, 8) == "file:///")
		f = "F";

	return ("graphics" + top.window_number_string + f);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// color chain color color_chain_color chain_pe
/* Limitations (unable to distinguish easily):
	Magenta cannot be used with violet and purple
*/
var blue="6060FF";         //3
var bluelight = "B0B0FF";  //10
var brown="a42028";        //5  was b06000; a42028 is close to Chime's "brown"
var cyan="00FFFF";         //0
var cyandark="00A0A0";     //11
var graylight="C0C0C0";
var gray="909090";
var graydark="606060";     //12
var green="00FF00";        //2
var greendark="00C000";    //8
var magenta="FF00FF";            // not with all
var magentadark="C000C0";
var orange="FFB000";       //9
var purple="D020FF";       //1
var pink="FFD8D8";         //6   red is reserved for water
var violet="FF80C0";       //4  was FF40C0
var white="FFFFFF";        //13
var yellow="FFFF00";       //7

/* copy of above list in numeric order
var cyan="00FFFF";         //0
var purple="D020FF";       //1
var green="00FF00";        //2

var blue="6060FF";         //3
var violet="FF80C0";       //4  was FF40C0
var brown="a42028";        //5  was b06000; a42028 is close to Chime's "brown"

var pink="FFD8D8";         //6   red is reserved for water
var yellow="FFFF00";       //7
var greendark="00C000";    //8

var orange="FFB000";       //9
var bluelight = "B0B0FF";  //10
var cyandark="00A0A0";     //11

var graydark="606060";     //12
var white="FFFFFF";        //13

UNUSED
var graylight="C0C0C0";
var gray="909090";
var magenta="FF00FF";            // not with all
var magentadark="C000C0";
*/


var chain_pe_color_limit = 14;

	var arccol = new Array(); // ARray of Chain COLors
	var arccoln = new Array(); // ARray of Chain COlor Names
	arccol[0] = cyan; arccoln[0] = "cyan";
	arccol[1] = purple; arccoln[1] = "purple";
	arccol[2] = green; arccoln[2] = "green";

	arccol[3] = blue; arccoln[3] = "blue";
	arccol[4] = violet; arccoln[4] = "violet";
	arccol[5] = brown; arccoln[5] = "brown";

	arccol[6] = pink; arccoln[6] = "pink";
	arccol[7] = yellow; arccoln[7] = "yellow";
	arccol[8] = greendark; arccoln[8] = "greendark";

	// orange conflicts w/ SSbonds, so use late
	arccol[9] = orange; arccoln[9] = "orange";
	arccol[10] = bluelight; arccoln[10] = "bluelight";
	arccol[11] = cyandark; arccoln[11] = "cyandark";

	arccol[12] = graydark; arccoln[12] = "graydark";
	arccol[13] = white; arccoln[13] = "white";

// white is reserved for hetero

// make a script to color the selected chains with the chain-PE color scheme.
// If there are more chains in this molecule than chain-PE can handle,
// returns "". If the user cancels because it would take too long,
// returns "canceled".
function make_chain_pe_spt(nosorry)
{
	// acf_chain_count excludes NMR chains, unlike top.acf_chains.length!!
	var nc = top.acf_chain_count;
	var clist = top.acf_chains;
	if (top.application_id == "comparator" && !top.cmp_at_top)
	{
		nc = top.acf2_chain_count;
		clist = top.acf2_chains;
	}

	if (nc > chain_pe_color_limit)
	{
		if (!nosorry)
			alert("Sorry, the Chain (PE) color scheme\n" +
				"is limited to " + chain_pe_color_limit + " chains.\n");
		return "";
	}

	var i;
	var s = "";
	if (!confirm_huge(slowness_tog)) // will never ask in Firstview since all atoms selected.
		return "canceled";

	var allsel = top.all_atoms_selected();
	if (!allsel)
		s += "define arccol_temp selected;\n"; 

	s += "select (protein,dna,rna);\n";
	if (allsel)
	{
		// Color all chains the color of the first chain in hopes of not running
		// out of colors.
		s += "color [x" + arccol[0] + "] # " + arccoln[0] + ";\n";
	}
	// for each chain in this molecule, apply its color
	for (i = 0; i < nc; i++)
	{
		if (allsel)
			s += "select :" + clist.charAt(i) + " and not hetero;";
		else
			s += "select :" + clist.charAt(i) + " and arccol_temp and not hetero;";
		s += "color [x" + arccol[i] + "] # " + arccoln[i] + ";\n";
	}
	if (!allsel)
		s += "select arccol_temp;\n";
	else
		s += select_all();
//	alert ("make_chain_pe_spt(nosorry) finished\n"
//		+ "allsel = " + allsel +"\ns = " + s);

	return(s);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function goto_consurf_with_pdbid()
{
	var pid = get_pdbid(top.cmp_at_top);
	if (pid != "")
		pid = "index.html?id=" + pid;
	var h = "http://consurf.tau.ac.il/" + pid;
	CSWin=window.open(h, "CSWinT");
	window.CSWin.focus();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function popback_sitemeter()
{
// could make it dependent, then it closes automatically

	var wf = "scrollbars=1,menubar=0,width=300,height=300,resizable=1";
	wf += top.ul_corner(0, screen.height - 350);
	var mtr = "sitemetr.htm";
	if (top.local_pe)
		mtr = "sitemetl.htm";
	top.SiteMeterWin=window.open(mtr, "SiteMeterWinT", wf);
	top.SiteMeterWin.blur(); // force into background
	// restore main PE window to focus
	top.focus(); // works!
//	setTimeout("top.pe_cmdfocus()", 1000); // doesn't work -- ??
// top.pe_cmdfocus(); // doesn't work -- ?? neither does an onLoad in sitemet?.htm
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function no_input()
{
	alert("This slot does not accept input.");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// During PE startup, shared\cmd2way2.htm
//		sets waiting_for_chime_speed = true,
//		then calls get_chime_speed().
// This sets timeouts to watch for stalling, then
// creates a window for shared\speed_ch.htm which reports a time by calling
// set_chime_speed(). That records the time. Meanwhile, speed_ch.htm
// has called retest_chime_speed() which starts another test after
// a delay. After desired_number_of_speed_tests have been successful,
// speed_ch.htm stops calling retest_chime_speed(), and
// set_chime_speed() falsifies waiting_for_chime_speed.
// Meanwhile, cmd2way2.htm is running a setTimeout loop watching
// waiting_for_chime_speed; when it goes false, PE starts.

// On the first call (number of tests completed zero)
// get_chime_speed() sets a Timeout to watch for
// the first result. On some Mac G3's, Chime inexplicably fails to load
// into speed_ch.htm, so it never reports. If the Timeout elapses before
// the first result is reported, bypass_chime_speed_test() is called.
// When the first result is reported, the Timeout is cancelled
// by set_chime_speed().
// Another Timeout is set to watch for completion of the 
// desired_number_of_speed_tests, just in case the first test report
// comes back but a later test fails. It also bypasses, or is cancelled.

var desired_number_of_speed_tests = 4.;
// These are setTimeout's invoked in cmd2way2.htm
// They must be external!
var ChimeSpeedWatchFirst;
var ChimeSpeedWatchCompletion;

function get_chime_speed()
{
	// in case a competing process calls after bypassing
	if (!waiting_for_chime_speed)
		return;

	var cspeed = parseFloat(getCookie("chime_speed"));
	var csn = getCookie("chime_speed_n");
	var fcsn = parseFloat(csn);
	var mslo = parseFloat(getCookie("chime_speed_msec_lo"));
	var msav = parseFloat(getCookie("chime_speed_msec_av"));
	var mshi = parseFloat(getCookie("chime_speed_msec_hi"));

	if (isNaN(fcsn) == true || csn == null || csn == "")
	{
		set_chime_speed(0., 0., 0., 0., 0.);
		csn = "";
	}
	else
		// this falsifies waiting_for_chime_speed
		set_chime_speed(cspeed, csn, mslo, msav, mshi);

	if (fcsn >= desired_number_of_speed_tests)
		return;

	// Generally, with a downloaded copy on a Mac, chime fails to load
	// into the speed meter, stalling startup. get_chime_speed() has
	// an elaborate setTimeout scheme to detect failure in general
	// and bypass it if 45" passes without the first speed test report.
	// But for downloaded PE on Macs, let's just skip it.
	if (top.server_id == "local_files" && top.isMac)
	{
		top.fr_control.fr_control2.document.location.href = "../shared/askmac.htm";		
		return;
	}

	if (csn == "") // then it is the first cycle
	{
		// On 100 MHz 486, Av msec is 5000. Time from alerts #11-#12 was 1:23.
		// For downloaded copies of PE on Macs, get_chime_speed() is not called:
		// see cmd2way2.htm and askmac.htm.
//		alert("util_top.js #11 setting ChimeSpeedWatch timeouts");
		top.ChimeSpeedWatchFirst = setTimeout("bypass_chime_speed_test(1)", 45000); // 45 sec
		top.ChimeSpeedWatchCompletion = setTimeout("bypass_chime_speed_test(2)", 120000); // 2 min
	}

	var wf = "scrollbars=1,menubar=0,width=300,height=300,resizable=1";
//	wf += top.ul_corner(0, screen.height - 350);
	wf += top.ul_corner(0, 0);
	top.ChSpeedWin=window.open(top.shared_base + "speed_ch.htm",
		"ChSpeedWinT", wf);
	top.ChSpeedWin.blur(); // force into background

	// speed_ch.htm in the new window determines chime's speed and
	// calls set_chime_speed();
	// cmd2way2 does not proceed to load PE until speed is reported.
}

function bypass_chime_speed_test(whocalled)
{
//	alert("util_top.js #10 bypass_chime_speed_test(" + whocalled + ")");

	if (whocalled == 1) // ChimeSpeedWatchFirst called bypass
		clearTimeout(ChimeSpeedWatchCompletion);
	// if ChimeSpeedWatchCompletion called, ChimeSpeedWatchFirst
	// must have been cleared after a successful first test.

	if (isMac) // G3 speed is about 0.25
		set_chime_speed(0.25, desired_number_of_speed_tests, 0., 0., 0.);
	else // slow windows? 100 MHz 486 is 0.05
		set_chime_speed(0.1, desired_number_of_speed_tests, 0., 0., 0.);

	top.waiting_for_chime_speed = false; // lets cmd2way2.htm start PE
}

function retest_chime_speed()
{
//	alert("retest_chime_speed() executing, chime_speed_n = " + top.chime_speed_n);
	if (!top.waiting_for_chime_speed) // just for extra safety, shouldn't be necc.
		return;
	setTimeout("get_chime_speed()", 1000);
}

// set_chime_speed(speed) is called by speed_ch.htm
function set_chime_speed(speed, n, diff_lo, diff_av, diff_hi)
{
//	alert("util_top.js #7 set_chime_speed(), speed is " + speed + "\n" +
//		"n " + n + "\n" +
//		"lo " + diff_lo + "\n" +
//		"av " + diff_av + "\n" +
//		"hi " + diff_hi);

	// it is not a javascript error to clear an unset timeout, as long
	// as the variable has been defined (even if no value assigned).
	if (parseFloat(n) == 1.)
		clearTimeout(ChimeSpeedWatchFirst);

	top.putCookie_year("chime_speed", speed);	// average
	top.putCookie_year("chime_speed_n", n);	 // number of observations
	top.putCookie_year("chime_speed_msec_lo", diff_lo);	
	top.putCookie_year("chime_speed_msec_hi", diff_hi);	
	top.putCookie_year("chime_speed_msec_av", diff_av);	
	// This is not used in PE 1.98, but can be used to re-determine the speed
	// when a newer version of PE is released, if necessary.
	// The first speed-enabled release was "1.98 Beta".
	top.putCookie_year("chime_speed_version", top.pe_version);	

	top.chime_speed = parseFloat(speed); // speed is a string
	top.chime_speed_n = parseFloat(n); // speed is a string
	top.chime_speed_msec_lo = parseFloat(diff_lo);
	top.chime_speed_msec_hi = parseFloat(diff_hi);
	top.chime_speed_msec_av = parseFloat(diff_av);

	// chime_speed_n records successful test results, after throwing away
	// the first, and maybe the second (see speed_ch.htm).
	if (top.chime_speed_n >= desired_number_of_speed_tests)
	{
		top.waiting_for_chime_speed = false; // lets PE continue to load
		clearTimeout(ChimeSpeedWatchCompletion);
//		alert("util_top.js #12 all speed tests completed");
	}
}
function show_chime_speed()
{
	var m = "Average speed (top.chime_speed) = " + top.chime_speed + "\n";
	m += "Number of tests averaged: " + top.chime_speed_n +  "\n";
	m += "Milliseconds per task (low, *average*, high): \n";
	m += "   " + top.chime_speed_msec_lo;
	m += "  *" + top.chime_speed_msec_av + "*  ";
	m += top.chime_speed_msec_hi + "\n";

	m += "\nClear results so test will be repeated\n";
	m += "on next startup of PE?";

	if (confirm(m))
		clear_chime_speed();
//		get_chime_speed();
}

function clear_chime_speed()
{
		top.putCookie_year("chime_speed", "");	
		top.putCookie_year("chime_speed_n", "");	
		top.putCookie_year("chime_speed_msec_av", "");	
		top.putCookie_year("chime_speed_msec_lo", "");	
		top.putCookie_year("chime_speed_msec_hi", "");	
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function show_pqs_report()
{
	var pid;
	if (typeof(top.application_id) != "string")
		pid = opener.top.get_pdbid(opener.top.cmp_at_top);
	else
		pid = top.get_pdbid(top.cmp_at_top);
//	var pi = document.pqsform.pdbid.value;
//	if (!valid_pdbid(pi, true))
//		return;
	var h = "http://pqs.ebi.ac.uk/pqs-bin/macmol.pl?filename=";
	h += pid;
	PQSWin=window.open(h, "PQSWinT");
	window.PQSWin.focus();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function set_chime_version() // from query parameters
{
	chimeVersionFP = parseFloat(getqpar("chiv"));
	chimeVersionSP = parseFloat(getqpar("chisp"));

//	alert("util_top.js #13\n" +
//		"cVFP=" + chimeVersionFP + " cvSP=" + chimeVersionSP);
}

function say_chime_version()
{
	var msg = "Chime version recorded within PE is\n" +	chimeVersionFP;
	if (chimeVersionSP > 0)
		msg += " SP" + chimeVersionSP;
	msg += "\nUse command 'show version' for Chime's report\n";
	msg += "(inappropriately '1.0' for all versions prior to 2.6 SP4).";
	alert(msg);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// activei() returns 0 if explorer or comparator at top, 1 if bottom

function activei()
{
	if (top.cmp_at_top)
		return (0);
	else return (1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function show_counts() // in message window
{
	top.echo_msgs = true;
	var s = "";
	if (top.acf_structure == "N")
		s += "structure;\n";
	s += "show info;\n";
	top.s2c2_null(s);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function start_clock()
{
	top.time_start = new Date(); // records current time
	top.time_lap = new Date(); // records current time
}

function elapsed_msec()
{
	time_end = new Date();
	var tot = time_end.valueOf() - top.time_start.valueOf();
	var lap = time_end.valueOf() - top.time_lap.valueOf();
	top.time_lap = new Date(); // records current time
	return(tot + " (" + lap + ") msec");
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// delays initial spinning to avoid interfering with speed meter,
// see speed_ch.htm

function delayed_spin_on()
{
	if (!top.waiting_for_chime_speed &&
		top.cmd2way3_loaded &&
		!chime_is_busy())
	{
//			alert("util_top.js #14: delayed_spin_on()");
//			top.echo_msgs = true;

//				s2c("spin on;"); bizzarely, this starts spinning in IE and sometimes
// stops within a fraction of a second, even tho Chime's menu shows Rotation ON.
// This "bug" happens only when the speed meter needs to run! The delay below
// seems to cure it.
			setTimeout('s2c(\"spin on\\n;\")', 500);
	}
	else
	{
//		alert("nope");
		setTimeout("delayed_spin_on()", 500);
	}
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
