
// fingeringkeyboard.js
// By Andrew Botros, 2001-2004
//
// Specifies the interactive fingering chart behaviour of The Virtual Flute.


var foot = "B";
var UNCONVENTIONAL = false;
var USINGCOOKIE = false;
var INITIALISING = false;

// Cookie constants
var COOKIE_NAME = "tvfconfig";
var COOKIE_DELIM = "-";
var COOKIE_EXPIRY = "Thursday, 31-Dec-2099 23:59:59 GMT";
var COOKIE_INDEX_F_CODE = 0;
var COOKIE_INDEX_F_FOOT = 1;
var COOKIE_INDEX_F_SPLITE = 2;
var COOKIE_INDEX_F_UNCONVENTIONAL = 3;
var COOKIE_INDEX_NM_FOOT = 4;
var COOKIE_INDEX_NM_SPLITE = 5;
var COOKIE_INDEX_NM_UNCONVENTIONAL = 6;

var fingering_images = new Object();
var current_fingering = new Object();

var BbTh = new Object();
var Th = new Object();
var L1 = new Object();
var Asharp = new Object();
var L2 = new Object();
var L3 = new Object();
var Gsharp = new Object();
var G = new Object();
var FsharpBblever = new Object();
var R1 = new Object();
var R2 = new Object();
var R3 = new Object();
var tr1 = new Object();
var tr2 = new Object();
var Dsharp = new Object();
var Csharp = new Object();
var C = new Object();
var B = new Object();
var gizmo = new Object();


// load all the required images

tick = new Image();
  tick.src = "pictures/tick.gif";
no_tick = new Image();
  no_tick.src = "pictures/no_tick.gif";

badinput = new Image();
  badinput.src = "pictures/badinput.gif";
no_badinput = new Image();
  no_badinput.src = "pictures/no_badinput.gif";

BbTh["up"] = new Image();
  BbTh["up"].src = "pictures/BbTh_up.gif";
BbTh["down"] = new Image();
  BbTh["down"].src = "pictures/BbTh_down.gif";
BbTh["over"] = new Image();
  BbTh["over"].src = "pictures/BbTh_over.gif";

Th["up"] = new Image();
  Th["up"].src = "pictures/Th_up.gif";
Th["down"] = new Image();
  Th["down"].src = "pictures/Th_down.gif";
Th["over"] = new Image();
  Th["over"].src = "pictures/Th_over.gif";

L1["up"] = new Image();
  L1["up"].src = "pictures/smallhole_up.gif";
L1["down"] = new Image();
  L1["down"].src = "pictures/smallhole_down.gif";
L1["over"] = new Image();
  L1["over"].src = "pictures/smallhole_over.gif";

Asharp["none"] = new Image();
  Asharp["none"].src = "pictures/greykey.gif";
Asharp["up"] = new Image();
  Asharp["up"].src = "pictures/largehole_grey.gif";
Asharp["down"] = new Image();
  Asharp["down"].src = "pictures/largehole_down.gif";
Asharp["over"] = new Image();
  Asharp["over"].src = "pictures/largehole_over.gif";

L2["up"] = new Image();
  L2["up"].src = "pictures/largehole_up.gif";
L2["down"] = new Image();
  L2["down"].src = "pictures/largehole_down.gif";
L2["over"] = new Image();
  L2["over"].src = "pictures/largehole_over.gif";

L3["up"] = new Image();
  L3["up"].src = "pictures/largeholeraised_up.gif";
L3["down"] = new Image();
  L3["down"].src = "pictures/largeholeraised_down.gif";
L3["over"] = new Image();
  L3["over"].src = "pictures/largeholeraised_over.gif";

Gsharp["up"] = new Image();
  Gsharp["up"].src = "pictures/Gsharp_up.gif";
Gsharp["down"] = new Image();
  Gsharp["down"].src = "pictures/Gsharp_down.gif";
Gsharp["over"] = new Image();
  Gsharp["over"].src = "pictures/Gsharp_over.gif";

G["none"] = new Image();
  G["none"].src = "pictures/greykeyraised.gif";
G["up"] = new Image();
  G["up"].src = "pictures/largeholeraised_grey.gif";
G["down"] = new Image();
  G["down"].src = "pictures/largeholeraised_down.gif";
G["over"] = new Image();
  G["over"].src = "pictures/largeholeraised_over.gif";

FsharpBblever["none_up"] = new Image();
  FsharpBblever["none_up"].src = "pictures/Bblever_up.gif";
FsharpBblever["none_down"] = new Image();
  FsharpBblever["none_down"].src = "pictures/Bblever_down.gif";
FsharpBblever["none_over"] = new Image();
  FsharpBblever["none_over"].src = "pictures/Bblever_over.gif";
FsharpBblever["up_up"] = new Image();
  FsharpBblever["up_up"].src = "pictures/Fsharp_up_Bblever_up.gif";
FsharpBblever["up_down"] = new Image();
  FsharpBblever["up_down"].src = "pictures/Fsharp_up_Bblever_down.gif";
FsharpBblever["up_over"] = new Image();
  FsharpBblever["up_over"].src = "pictures/Fsharp_up_Bblever_over.gif";
FsharpBblever["down_up"] = new Image();
  FsharpBblever["down_up"].src = "pictures/Fsharp_down_Bblever_up.gif";
FsharpBblever["down_down"] = new Image();
  FsharpBblever["down_down"].src = "pictures/Fsharp_down_Bblever_down.gif";
FsharpBblever["down_over"] = new Image();
  FsharpBblever["down_over"].src = "pictures/Fsharp_down_Bblever_over.gif";
FsharpBblever["over_up"] = new Image();
  FsharpBblever["over_up"].src = "pictures/Fsharp_over_Bblever_up.gif";
FsharpBblever["over_down"] = new Image();
  FsharpBblever["over_down"].src = "pictures/Fsharp_over_Bblever_down.gif";

R1["up"] = new Image();
  R1["up"].src = "pictures/largehole_up.gif";
R1["down"] = new Image();
  R1["down"].src = "pictures/largehole_down.gif";
R1["over"] = new Image();
  R1["over"].src = "pictures/largehole_over.gif";

R2["up"] = new Image();
  R2["up"].src = "pictures/largehole_up.gif";
R2["down"] = new Image();
  R2["down"].src = "pictures/largehole_down.gif";
R2["over"] = new Image();
  R2["over"].src = "pictures/largehole_over.gif";

R3["up"] = new Image();
  R3["up"].src = "pictures/largehole_up.gif";
R3["down"] = new Image();
  R3["down"].src = "pictures/largehole_down.gif";
R3["over"] = new Image();
  R3["over"].src = "pictures/largehole_over.gif";

tr1["up"] = new Image();
  tr1["up"].src = "pictures/tr_up.gif";
tr1["down"] = new Image();
  tr1["down"].src = "pictures/tr_down.gif";
tr1["over"] = new Image();
  tr1["over"].src = "pictures/tr_over.gif";

tr2["up"] = new Image();
  tr2["up"].src = "pictures/tr_up.gif";
tr2["down"] = new Image();
  tr2["down"].src = "pictures/tr_down.gif";
tr2["over"] = new Image();
  tr2["over"].src = "pictures/tr_over.gif";

Dsharp["up"] = new Image();
  Dsharp["up"].src = "pictures/Dsharp_up.gif";
Dsharp["down"] = new Image();
  Dsharp["down"].src = "pictures/Dsharp_down.gif";
Dsharp["over"] = new Image();
  Dsharp["over"].src = "pictures/Dsharp_over.gif";

Csharp["up"] = new Image();
  Csharp["up"].src = "pictures/Csharp_up.gif";
Csharp["down"] = new Image();
  Csharp["down"].src = "pictures/Csharp_down.gif";
Csharp["over"] = new Image();
  Csharp["over"].src = "pictures/Csharp_over.gif";

C["up"] = new Image();
  C["up"].src = "pictures/B_up_C_up.gif";
C["down"] = new Image();
  C["down"].src = "pictures/B_down_C_down.gif";
C["over"] = new Image();
  C["over"].src = "pictures/B_over_C_over.gif";

B["up"] = new Image();
  B["up"].src = "pictures/B_up_C_up.gif";
B["down"] = new Image();
  B["down"].src = "pictures/B_down_C_down.gif";
B["over"] = new Image();
  B["over"].src = "pictures/B_over_C_over.gif";
B["none"] = new Image();
  B["none"].src = "pictures/B_none_C_none.gif";

gizmo["up"] = new Image();
  gizmo["up"].src = "pictures/gizmo_up.gif";
gizmo["down"] = new Image();
  gizmo["down"].src = "pictures/gizmo_down.gif";
gizmo["over"] = new Image();
  gizmo["over"].src = "pictures/gizmo_over.gif";
gizmo["none"] = new Image();
  gizmo["none"].src = "pictures/gizmo_none.gif";

fingering_images["BbTh"] = BbTh;
fingering_images["Th"] = Th;
fingering_images["L1"] = L1;
fingering_images["Asharp"] = Asharp;
fingering_images["L2"] = L2;
fingering_images["L3"] = L3;
fingering_images["Gsharp"] = Gsharp;
fingering_images["G"] = G;
fingering_images["R1"] = R1;
fingering_images["R2"] = R2;
fingering_images["R3"] = R3;
fingering_images["tr1"] = tr1;
fingering_images["tr2"] = tr2;
fingering_images["Dsharp"] = Dsharp;
fingering_images["Csharp"] = Csharp;
fingering_images["C"] = C;
fingering_images["B"] = B;
fingering_images["gizmo"] = gizmo;

current_fingering["BbTh"] = "up";
current_fingering["Th"] = "up";
current_fingering["L1"] = "up";
current_fingering["Asharp"] = "none";
current_fingering["L2"] = "up";
current_fingering["L3"] = "up";
current_fingering["Gsharp"] = "up";
current_fingering["G"] = "none";
current_fingering["Fsharp"] = "none";
current_fingering["R1"] = "up";
current_fingering["R2"] = "up";
current_fingering["R3"] = "up";
current_fingering["tr1"] = "up";
current_fingering["tr2"] = "up";
current_fingering["Bblever"] = "up";
current_fingering["Dsharp"] = "up";
current_fingering["Csharp"] = "up";
current_fingering["C"] = "up";
current_fingering["B"] = "up";
current_fingering["gizmo"] = "up";


// startUp() initialises the fingering interface
// by reading the page's Cookie.

function startUp(isusingcookie) {
  USINGCOOKIE = isusingcookie;
  if(USINGCOOKIE) {
    // INITIALISING flag indicates that cookie should
    // not be updated while updating (otherwise cookie will be lost).
    INITIALISING = true;
    var cookiestring = document.cookie;
    if(cookiestring.indexOf(COOKIE_NAME) != -1) {
      var cookiearray =
        cookiestring.substring(cookiestring.indexOf("=") + 1).split(COOKIE_DELIM);
      if(cookiearray[COOKIE_INDEX_F_FOOT] == "B")
        BFoot();
      else
        CFoot();
      if(cookiearray[COOKIE_INDEX_F_SPLITE] == "1")
        document.flute.fingeringsplitE.checked = true;
      else
        document.flute.fingeringsplitE.checked = false;
      if(cookiearray[COOKIE_INDEX_F_UNCONVENTIONAL] == "1")
        convention();
      initialiseKeys(cookiearray[COOKIE_INDEX_F_CODE]);
      if(cookiearray[COOKIE_INDEX_NM_FOOT] != null) {
        initialiseNMFoot(document.flute.notesfoot, cookiearray[COOKIE_INDEX_NM_FOOT]);
        initialiseNMFoot(document.flute.multiphonicsfoot, cookiearray[COOKIE_INDEX_NM_FOOT]);
      }
      if(cookiearray[COOKIE_INDEX_NM_SPLITE] != null) {
        initialiseNMSplitE(document.flute.notessplitE, cookiearray[COOKIE_INDEX_NM_SPLITE]);
        initialiseNMSplitE(document.flute.multiphonicssplitE, cookiearray[COOKIE_INDEX_NM_SPLITE]);
      }
      if(cookiearray[COOKIE_INDEX_NM_UNCONVENTIONAL] != null) {
        initialiseNMUnconventional(document.flute.notesunconventional, cookiearray[COOKIE_INDEX_NM_UNCONVENTIONAL]);
        initialiseNMUnconventional(document.flute.multiphonicsunconventional, cookiearray[COOKIE_INDEX_NM_UNCONVENTIONAL]);
      }
    }
    INITIALISING = false;
  }
  keyboardOutput();
}


// initialiseKeys() "presses" the keys specified in
// the Cookie to initialise the fingering diagram.

function initialiseKeys(code) {
  var keys = new Array("BbTh", "Th", "L1", "Asharp", "L2", "L3", "Gsharp",
                        "G", "Fsharp", "R1", "R2", "R3", "tr1", "tr2", "Bblever",
                         "Dsharp", "Csharp", "C", "B", "gizmo");
  for(i = 0; i < keys.length; i++) {
    if((code >> i)%2 == 1)
      changeFinger(keys[i]);
  }
}


// initialiseNMFoot() sets the notes and multiphonics foot option based on cookie

function initialiseNMFoot(nmradiobutton, nmfoot) {
  if(nmfoot == "B")
    nmradiobutton[0].checked = true;
  if(nmfoot == "C")
    nmradiobutton[1].checked = true;
  if(nmfoot == "both")
    nmradiobutton[2].checked = true;
}


// initialiseNMSplitE() sets the notes and multiphonics splitE option based on cookie

function initialiseNMSplitE(nmradiobutton, nmsplitE) {
  if(nmsplitE == "1")
    nmradiobutton[0].checked = true;
  if(nmsplitE == "0")
    nmradiobutton[1].checked = true;
  if(nmsplitE == "both")
    nmradiobutton[2].checked = true;
}


// initialiseNMUnconventional() sets the notes and multiphonics
// unconventional fingering option based on cookie

function initialiseNMUnconventional(nmcheckbox, nmunconventional) {
  if(nmunconventional == "1")
    nmcheckbox.checked = true;
  if(nmunconventional == "0")
    nmcheckbox.checked = false;
}


// splitE() sets split E configuration in cookie.

function splitE() {
  if(!INITIALISING)
    storeCookie();
  keyboardOutput();
}


// convention() is called to enable/disable the A#, G and F# keys.

function convention() {
  if(!UNCONVENTIONAL) {
    UNCONVENTIONAL = true;
    current_fingering["Asharp"] = "up";
    current_fingering["G"] = "up";
    current_fingering["Fsharp"] = "up";
    document.images["Asharp"].src = (fingering_images["Asharp"])["up"].src;
    document.images["G"].src = (fingering_images["G"])["up"].src;
    if(current_fingering["Bblever"] == "up")
      document.images["FsharpBblever"].src = FsharpBblever["up_up"].src;
    if(current_fingering["Bblever"] == "down")
      document.images["FsharpBblever"].src = FsharpBblever["up_down"].src;
    document.images["unconventional"].src = tick.src;
  } else {
    UNCONVENTIONAL = false;
    current_fingering["Asharp"] = "none";
    current_fingering["G"] = "none";
    current_fingering["Fsharp"] = "none";
    document.images["Asharp"].src = (fingering_images["Asharp"])["none"].src;
    document.images["G"].src = (fingering_images["G"])["none"].src;
    document.images["unconventional"].src = no_tick.src;
    if(current_fingering["Bblever"] == "up")
      document.images["FsharpBblever"].src = FsharpBblever["none_up"].src;
    if(current_fingering["Bblever"] == "down")
      document.images["FsharpBblever"].src = FsharpBblever["none_down"].src;
  }
  if(!INITIALISING)
    storeCookie();
}


// dummy function to work around the Netscape "spinning hourglass" bug.
function changeConvention() {}


// Bfoot() sets fingering interface as B foot.

function BFoot() {
  if(foot != "B") {
    current_fingering["B"] = "up";
    current_fingering["gizmo"] = "up";
    document.images["B"].src = (fingering_images["B"])["up"].src;
    document.images["gizmo"].src = (fingering_images["gizmo"])["up"].src;
    foot = "B";
    document.images["bfoot"].src = tick.src;
    document.images["cfoot"].src = no_tick.src;
    if(!INITIALISING)
      storeCookie();
    keyboardOutput();
  }
}


// Cfoot() sets fingering interface as C foot.

function CFoot() {
  if(foot != "C") {
    current_fingering["B"] = "none";
    current_fingering["gizmo"] = "none";
    document.images["B"].src = (fingering_images["B"])["none"].src;
    document.images["gizmo"].src = (fingering_images["gizmo"])["none"].src;
    foot = "C";
    document.images["bfoot"].src = no_tick.src;
    document.images["cfoot"].src = tick.src;
    if(!INITIALISING)
      storeCookie();
  keyboardOutput();
  }
}


// dummy function to work around the Netscape "spinning hourglass" bug.
function changeFoot() {}


// changeFinger() presses/depresses the selected key.

function changeFinger(key) {
  var current = current_fingering[key];
  if(current == "up") {
    current_fingering[key] = "down";
    if(key == "Fsharp" || key == "Bblever") {
      if(key == "Fsharp") {
        if(current_fingering["Bblever"] == "up")
          document.images["FsharpBblever"].src = FsharpBblever["down_up"].src;
        if(current_fingering["Bblever"] == "down")
          document.images["FsharpBblever"].src = FsharpBblever["down_down"].src;
      }
      if(key == "Bblever") {
        if(current_fingering["Fsharp"] == "none")
          document.images["FsharpBblever"].src = FsharpBblever["none_down"].src;
        if(current_fingering["Fsharp"] == "up")
          document.images["FsharpBblever"].src = FsharpBblever["up_down"].src;
        if(current_fingering["Fsharp"] == "down")
          document.images["FsharpBblever"].src = FsharpBblever["down_down"].src;
      }
    } else {
      document.images[key].src = (fingering_images[key])["down"].src;
      if(key == "BbTh") {
        document.images["Th"].src = (fingering_images["Th"])["down"].src;
        current_fingering["Th"] = "down";
      }
      if(key == "C") {
        document.images["Csharp"].src = (fingering_images["Csharp"])["down"].src;
        current_fingering["Csharp"] = "down";
      }
    }
  }
  if(current == "down") {
    if(key == "Fsharp" || key == "Bblever") {
      current_fingering[key] = "up";
      if(key == "Fsharp") {
        if(current_fingering["Bblever"] == "up")
          document.images["FsharpBblever"].src = FsharpBblever["up_up"].src;
        if(current_fingering["Bblever"] == "down")
          document.images["FsharpBblever"].src = FsharpBblever["up_down"].src;
      }
      if(key == "Bblever") {
        if(current_fingering["Fsharp"] == "none")
          document.images["FsharpBblever"].src = FsharpBblever["none_up"].src;
        if(current_fingering["Fsharp"] == "up")
          document.images["FsharpBblever"].src = FsharpBblever["up_up"].src;
        if(current_fingering["Fsharp"] == "down")
          document.images["FsharpBblever"].src = FsharpBblever["down_up"].src;
      }
    } else {
      document.images[key].src = (fingering_images[key])["up"].src;
      current_fingering[key] = "up";
      if(key == "BbTh") {
        document.images["Th"].src = (fingering_images["Th"])["up"].src;
        current_fingering["Th"] = "up";
      }
      if(key == "Th") {
        document.images["BbTh"].src = (fingering_images["BbTh"])["up"].src;
        current_fingering["BbTh"] = "up";
      }
      if(key == "C") {
        document.images["Csharp"].src = (fingering_images["Csharp"])["up"].src;
        current_fingering["Csharp"] = "up";
      }
      if(key == "Csharp") {
        document.images["C"].src = (fingering_images["C"])["up"].src;
        current_fingering["C"] = "up";
      }
    }
  }
  if(!INITIALISING)
    storeCookie();
  keyboardOutput();
}


// dummy function to work around the Netscape "spinning hourglass" bug.
function key() {}


// keyOver() changes key of fingering diagram to blue when mouse over.

function keyOver(key) {
  if(current_fingering[key] != "none") {
    if(key == "Fsharp" || key == "Bblever") {
      if(key == "Fsharp") {
        if(current_fingering["Bblever"] == "up")
          document.images["FsharpBblever"].src = FsharpBblever["over_up"].src;
        if(current_fingering["Bblever"] == "down")
          document.images["FsharpBblever"].src = FsharpBblever["over_down"].src;
      }
      if(key == "Bblever") {
        if(current_fingering["Fsharp"] == "none")
          document.images["FsharpBblever"].src = FsharpBblever["none_over"].src;
        if(current_fingering["Fsharp"] == "up")
          document.images["FsharpBblever"].src = FsharpBblever["up_over"].src;
        if(current_fingering["Fsharp"] == "down")
          document.images["FsharpBblever"].src = FsharpBblever["down_over"].src;
      }
    } else {
      document.images[key].src = (fingering_images[key])["over"].src;
      if(key == "BbTh") {
        document.images["Th"].src = (fingering_images["Th"])["over"].src;
      }
      if(key == "C") {
        document.images["Csharp"].src = (fingering_images["Csharp"])["over"].src;
      }
    }
  }
}


// keyOut() changes key of fingering diagram back to its
// current state when mouse out.

function keyOut(key) {
  if(current_fingering[key] != "none") {
    if(key == "Fsharp" || key == "Bblever") {
      var state = current_fingering[key];
      if(key == "Fsharp") {
        if(current_fingering["Bblever"] == "up")
          document.images["FsharpBblever"].src
            = FsharpBblever[state + "_up"].src;
        if(current_fingering["Bblever"] == "down")
          document.images["FsharpBblever"].src
            = FsharpBblever[state + "_down"].src;
      }
      if(key == "Bblever") {
        if(current_fingering["Fsharp"] == "none")
          document.images["FsharpBblever"].src
            = FsharpBblever["none_" + state].src;
        if(current_fingering["Fsharp"] == "up")
          document.images["FsharpBblever"].src
            = FsharpBblever["up_" + state].src;
        if(current_fingering["Fsharp"] == "down")
          document.images["FsharpBblever"].src
            = FsharpBblever["down_" + state].src;
      }
    } else {
      document.images[key].src
        = (fingering_images[key])[current_fingering[key]].src;
      if(key == "BbTh") {
        document.images["Th"].src
          = (fingering_images["Th"])[current_fingering["Th"]].src;
      }
      if(key == "C") {
        document.images["Csharp"].src
          = (fingering_images["Csharp"])[current_fingering["Csharp"]].src;
      }
    }
  }
}


// clearFingering() sets all keys to unpressed.

function clearFingering() {
  for(key in fingering_images) {
    if(current_fingering[key] != "none") {
      document.images[key].src = (fingering_images[key])["up"].src;
      current_fingering[key] = "up";
    }
  }
  current_fingering["Bblever"] = "up";
  if(UNCONVENTIONAL) {
    current_fingering["Fsharp"] = "up";
    document.images["FsharpBblever"].src = FsharpBblever["up_up"].src;
  } else {
    document.images["FsharpBblever"].src = FsharpBblever["none_up"].src;
  }
  storeCookie();
  keyboardOutput();
}


// fingeringCode() evaluates the bit string code of the current
// fingering interface.

function fingeringCode() {
  var code = 0;
  var keys = new Array("BbTh", "Th", "L1", "Asharp", "L2", "L3", "Gsharp",
                        "G", "Fsharp", "R1", "R2", "R3", "tr1", "tr2", "Bblever",
                         "Dsharp", "Csharp", "C", "B", "gizmo");
  for(i = 0; i < keys.length; i++) {
    if(current_fingering[keys[i]] == "down") {
      if(keys[i] == "Th" && current_fingering["BbTh"] == "down")
        continue;
      if(keys[i] == "Csharp" && current_fingering["C"] == "down")
        continue;
      code = code + Math.pow(2, i);
    }
  }
  return code;
}


// fingeringString() evaluates an alphabetic fingering notation, given the fingering code.
// JavaScript implementation of Fingering.java.

function fingeringString(fingering) {
  fs = "";

  if(pressed("BbTh", fingering))
    fs = fs + "BbTh";
  else {
    if(pressed("Th", fingering))
      fs = fs + "Th";
    else
      fs = fs + " ";
  }

  fs = fs + " ";

  if(pressed("L1", fingering))
    fs = fs + "1";
  else
    fs = fs + " ";

  fs = fs + " ";

  if(pressed("A#", fingering))
    fs = fs + "A# ";

  if(pressed("L2", fingering))
    fs = fs + "2";
  else
    fs = fs + " ";

  fs = fs + " ";

  if(pressed("L3", fingering))
    fs = fs + "3";
  else
    fs = fs + " ";

  fs = fs + " ";

  if(pressed("G#", fingering))
    fs = fs + "G#";
  else
    fs = fs + " ";

  fs = fs + " | ";

  if(pressed("G", fingering))
    fs = fs + "G ";

  if(pressed("F#", fingering))
    fs = fs + "F# ";

  if(pressed("R1", fingering))
    fs = fs + "1";
  else
    fs = fs + " ";

  fs = fs + " ";

  if(pressed("R2", fingering))
    fs = fs + "2";
  else
    fs = fs + " ";

  fs = fs + " ";

  if(pressed("R3", fingering))
    fs = fs + "3";
  else
    fs = fs + " ";

  if(pressed("tr1", fingering))
    fs = fs + " tr1";

  if(pressed("tr2", fingering))
    fs = fs + " tr2";

  if(pressed("Bblever", fingering))
    fs = fs + " Bblever";

  if(pressed("D#", fingering))
    fs = fs + " D#";

  if(pressed("C#", fingering))
    fs = fs + " C#";

  if(pressed("C", fingering))
    fs = fs + " C";

  if(pressed("B", fingering))
    fs = fs + " B";

  if(pressed("gizmo", fingering))
    fs = fs + " gizmo";

  return fs;
}


// pressed() determines whether a given key is pressed in a given fingering code.
// Uses bit shifting to read individual bits of the code.
// JavaScript implementation of Fingering.java.

function pressed(key, fingering) {
  bitshift = 0;

  if(key == "BbTh")
    bitshift = 0;
  if(key == "Th")
    bitshift = 1;
  if(key == "L1")
    bitshift = 2;
  if(key == "A#")
    bitshift = 3;
  if(key == "L2")
    bitshift = 4;
  if(key == "L3")
    bitshift = 5;
  if(key == "G#")
    bitshift = 6;
  if(key == "G")
    bitshift = 7;
  if(key == "F#")
    bitshift = 8;
  if(key == "R1")
    bitshift = 9;
  if(key == "R2")
    bitshift = 10;
  if(key == "R3")
    bitshift = 11;
  if(key == "tr1")
    bitshift = 12;
  if(key == "tr2")
    bitshift = 13;
  if(key == "Bblever")
    bitshift = 14;
  if(key == "D#")
    bitshift = 15;
  if(key == "C#")
    bitshift = 16;
  if(key == "C")
    bitshift = 17;
  if(key == "B")
    bitshift = 18;
  if(key == "gizmo")
    bitshift = 19;

  temp = fingering >> bitshift;
  if(temp%2 == 1)
    return true;
  else
    return false;
}


// storeCookie() stores a Cookie for the current state of the interface.

function storeCookie() {
  if(USINGCOOKIE) {
    var cookiestring = document.cookie;
    var cookiearray;
    if(cookiestring.indexOf(COOKIE_NAME) != -1)
      cookiearray = cookiestring.substring(cookiestring.indexOf("=") + 1).split(COOKIE_DELIM);
    else
      cookiearray = new Array;
    cookiearray[COOKIE_INDEX_F_CODE] = fingeringCode();
    cookiearray[COOKIE_INDEX_F_FOOT] = fingeringFootString();
    cookiearray[COOKIE_INDEX_F_SPLITE] = fingeringSplitEString();
    cookiearray[COOKIE_INDEX_F_UNCONVENTIONAL] = fingeringUnconventionalString();
    if(arguments.length > 0) {
      if(arguments[0] == "notes") {
        cookiearray[COOKIE_INDEX_NM_FOOT] = nmFootString(document.flute.notesfoot);
        cookiearray[COOKIE_INDEX_NM_SPLITE] = nmSplitEString(document.flute.notessplitE);
        cookiearray[COOKIE_INDEX_NM_UNCONVENTIONAL] = nmUnconventionalString(document.flute.notesunconventional);
      }
      if(arguments[0] == "multiphonics") {
        cookiearray[COOKIE_INDEX_NM_FOOT] = nmFootString(document.flute.multiphonicsfoot);
        cookiearray[COOKIE_INDEX_NM_SPLITE] = nmSplitEString(document.flute.multiphonicssplitE);
        cookiearray[COOKIE_INDEX_NM_UNCONVENTIONAL] = nmUnconventionalString(document.flute.multiphonicsunconventional);
      }
    }
    document.cookie =
      COOKIE_NAME + "=" +
      cookiearray.join(COOKIE_DELIM) +
      "; expires=" + COOKIE_EXPIRY;
  }
}


// searchFingering() sets up the correct URL query string
// and loads fingering.php

function searchFingering() {
  storeCookie();
  location = "fingering.php?fingering=" + fingeringCode() +
                "&foot=" + fingeringFootString() +
                "&splitE=" + fingeringSplitEString() +
                "&notes=";
}


// fingeringFootString() forms the foot part of the fingering cookie

function fingeringFootString() {
  return foot;
}


// fingeringSplitEString() forms the splitE part of the fingering.php URL query
// and fingering cookie

function fingeringSplitEString() {
  if(document.flute.fingeringsplitE.checked)
    return "1";
  else
    return "0";
}


// fingeringUnconventionalString() forms the unconventional fingering
// part of the fingering cookie

function fingeringUnconventionalString() {
  if(UNCONVENTIONAL)
    return "1";
  else
    return "0";
}


// anyKeys() unchecks the MUST INCLUDE boxes.

function anyKeys() {
  document.flute.BbThThbox.checked = false;
  document.flute.L1box.checked = false;
  document.flute.Asharpbox.checked = false;
  document.flute.L2box.checked = false;
  document.flute.L3box.checked = false;
  document.flute.Gsharpbox.checked = false;
  document.flute.Gbox.checked = false;
  document.flute.Fsharpbox.checked = false;
  document.flute.R1box.checked = false;
  document.flute.R2box.checked = false;
  document.flute.R3box.checked = false;
  document.flute.tr1box.checked = false;
  document.flute.tr2box.checked = false;
  document.flute.Bbleverbox.checked = false;
  document.flute.Dsharpbox.checked = false;
  document.flute.Csharpbox.checked = false;
  document.flute.Cbox.checked = false;
  document.flute.Bbox.checked = false;
  document.flute.gizmobox.checked = false;
}


// newKey() unchecks the INCLUDE ANY KEYS box
// and unchecks the key box for the MUST NOT include
// counterpart.

function newKey(opposite) {
  document.flute.anykeys.checked = false;
  document.flute.elements[opposite].checked = false;
}


// anyKeys() unchecks the MUST NOT INCLUDE boxes.

function notAnyKeys() {
  document.flute.notBbThThbox.checked = false;
  document.flute.notL1box.checked = false;
  document.flute.notAsharpbox.checked = false;
  document.flute.notL2box.checked = false;
  document.flute.notL3box.checked = false;
  document.flute.notGsharpbox.checked = false;
  document.flute.notGbox.checked = false;
  document.flute.notFsharpbox.checked = false;
  document.flute.notR1box.checked = false;
  document.flute.notR2box.checked = false;
  document.flute.notR3box.checked = false;
  document.flute.nottr1box.checked = false;
  document.flute.nottr2box.checked = false;
  document.flute.notBbleverbox.checked = false;
  document.flute.notDsharpbox.checked = false;
  document.flute.notCsharpbox.checked = false;
  document.flute.notCbox.checked = false;
  document.flute.notBbox.checked = false;
  document.flute.notgizmobox.checked = false;
}


// notNewKey() unchecks the DO NOT EXCLUDE ANY KEYS box
// and unchecks the key box for the MUST include
// counterpart.

function notNewKey(opposite) {
  document.flute.notanykeys.checked = false;
  document.flute.elements[opposite].checked = false;
}


// searchNote() checks for good note input. It then
// forms the correct URL query string and loads
// notes.php (or displays an error image).

function searchNote() {
  var noteindex = document.flute.note.selectedIndex;
  var sharpindex = document.flute.sharp.selectedIndex;
  var octaveindex = document.flute.octave.selectedIndex;

  var goodinput = true;

  var note;
  var sharp;
  var octave;

  if(noteindex == -1) {
    goodinput = false;
  } else {
    note = document.flute.note.options[noteindex].value;
  }
  if(sharpindex == -1) {
    sharp = "";
  } else {
    sharp = document.flute.sharp.options[sharpindex].value;
  }
  if(octaveindex == -1) {
    goodinput = false;
  } else {
    octave = document.flute.octave.options[octaveindex].value;
  }
  if((sharpindex == 1) && (noteindex == 2 || noteindex == 6)) {
    goodinput = false;
  }

  if(goodinput) {
    storeCookie("notes");
    location = "notes.php?note=" + escape(note + sharp + octave)
                + "&foot=" + nmFootString(document.flute.notesfoot) + "&splitE="
                  + nmSplitEString(document.flute.notessplitE)
                    + "&unconventional=" + nmUnconventionalString(document.flute.notesunconventional)
                      + "&keys=" + escape(keysString()) + "&nokeys=" + escape(noKeysString())
                        + "&order=intonation" + "&index=0";
  } else {
    document.images["badinput"].src = badinput.src;
  }
}


// nmFootString() forms the foot part of the URL query and cookie

function nmFootString(nmradiobutton) {
  if(nmradiobutton[0].checked)
    return "B";
  if(nmradiobutton[1].checked)
    return "C";
  if(nmradiobutton[2].checked)
    return "both";
}


// nmSplitEString() forms the splitE part of the URL query and cookie

function nmSplitEString(nmradiobutton) {
  if(nmradiobutton[0].checked)
    return "1";
  if(nmradiobutton[1].checked)
    return "0";
  if(nmradiobutton[2].checked)
    return "both";
}


// nmUnconventionalString() forms the unconventional fingering
// part of the URL query and cookie

function nmUnconventionalString(nmcheckbox) {
  if(nmcheckbox.checked)
    return "1";
  else
    return "0";
}


// keysString() forms the must include keys part of the
// notes.php URL query.

function keysString() {
  var ks = "";

  if(document.flute.BbThThbox.checked)
    ks = ks + "BbThTh;";
  if(document.flute.L1box.checked)
    ks = ks + "L1;";
  if(document.flute.Asharpbox.checked)
    ks = ks + "A#;";
  if(document.flute.L2box.checked)
    ks = ks + "L2;";
  if(document.flute.L3box.checked)
    ks = ks + "L3;";
  if(document.flute.Gsharpbox.checked)
    ks = ks + "G#;";
  if(document.flute.Gbox.checked)
    ks = ks + "G;";
  if(document.flute.Fsharpbox.checked)
    ks = ks + "F#;";
  if(document.flute.R1box.checked)
    ks = ks + "R1;";
  if(document.flute.R2box.checked)
    ks = ks + "R2;";
  if(document.flute.R3box.checked)
    ks = ks + "R3;";
  if(document.flute.tr1box.checked)
    ks = ks + "tr1;";
  if(document.flute.tr2box.checked)
    ks = ks + "tr2;";
  if(document.flute.Bbleverbox.checked)
    ks = ks + "Bblever;";
  if(document.flute.Dsharpbox.checked)
    ks = ks + "D#;";
  if(document.flute.Csharpbox.checked) {
    if(!document.flute.Cbox.checked)
      ks = ks + "C#;";
  }
  if(document.flute.Cbox.checked)
    ks = ks + "C;";
  if(document.flute.Bbox.checked)
    ks = ks + "B;";
  if(document.flute.gizmobox.checked)
    ks = ks + "gizmo;";

  if(ks != "")
    ks = ks.substring(0, ks.length - 1);
  return ks;
}


// noKeysString() forms the must not include keys part of the
// notes.php URL query.

function noKeysString() {
  var ks = "";

  if(document.flute.notBbThThbox.checked)
    ks = ks + "BbThTh;";
  if(document.flute.notL1box.checked)
    ks = ks + "L1;";
  if(document.flute.notAsharpbox.checked)
    ks = ks + "A#;";
  if(document.flute.notL2box.checked)
    ks = ks + "L2;";
  if(document.flute.notL3box.checked)
    ks = ks + "L3;";
  if(document.flute.notGsharpbox.checked)
    ks = ks + "G#;";
  if(document.flute.notGbox.checked)
    ks = ks + "G;";
  if(document.flute.notFsharpbox.checked)
    ks = ks + "F#;";
  if(document.flute.notR1box.checked)
    ks = ks + "R1;";
  if(document.flute.notR2box.checked)
    ks = ks + "R2;";
  if(document.flute.notR3box.checked)
    ks = ks + "R3;";
  if(document.flute.nottr1box.checked)
    ks = ks + "tr1;";
  if(document.flute.nottr2box.checked)
    ks = ks + "tr2;";
  if(document.flute.notBbleverbox.checked)
    ks = ks + "Bblever;";
  if(document.flute.notDsharpbox.checked)
    ks = ks + "D#;";
  if(document.flute.notCsharpbox.checked)
      ks = ks + "C#;";
  if(document.flute.notCbox.checked)
    ks = ks + "C;";
  if(document.flute.notBbox.checked)
    ks = ks + "B;";
  if(document.flute.notgizmobox.checked)
    ks = ks + "gizmo;";

  if(ks != "")
    ks = ks.substring(0, ks.length - 1);
  return ks;
}


// changeNote() removes the bad input image when
// the user clicks the note select menu again.

function changeNote() {
  document.images["badinput"].src = no_badinput.src;
}


// clearMultiphonic() clears the three note select
// boxes of the multiphonics interface

function clearMultiphonic() {
  document.flute.note1.selectedIndex = -1;
  document.flute.sharp1.selectedIndex = -1;
  document.flute.octave1.selectedIndex = -1;
  document.flute.note2.selectedIndex = -1;
  document.flute.sharp2.selectedIndex = -1;
  document.flute.octave2.selectedIndex = -1;
  document.flute.note3.selectedIndex = -1;
  document.flute.sharp3.selectedIndex = -1;
  document.flute.octave3.selectedIndex = -1;
  changeMultiphonic();
}


// searchMultiphonic() checks for good multiphonic input.
// It then forms the correct URL query string and loads
// multiphonics.php (or displays an error image).

function searchMultiphonic() {
  var note1index = document.flute.note1.selectedIndex;
  var sharp1index = document.flute.sharp1.selectedIndex;
  var octave1index = document.flute.octave1.selectedIndex;
  var note2index = document.flute.note2.selectedIndex;
  var sharp2index = document.flute.sharp2.selectedIndex;
  var octave2index = document.flute.octave2.selectedIndex;
  var note3index = document.flute.note3.selectedIndex;
  var sharp3index = document.flute.sharp3.selectedIndex;
  var octave3index = document.flute.octave3.selectedIndex;

  var goodinput = true;

  var note;
  var sharp;
  var octave;

  var page;

  var note1 = "";
  var note2 = "";
  var note3 = "";

  var num_notes = 0;
  var note_string = "";

  if((note1index != -1 || sharp1index != -1 || octave1index != -1) && goodinput) {
    if(note1index == -1) {
      goodinput = false;
    } else {
      note = document.flute.note.options[note1index].value;
    }
    if(sharp1index == -1) {
      sharp = "";
    } else {
      sharp = document.flute.sharp.options[sharp1index].value;
    }
    if(octave1index == -1) {
      goodinput = false;
    } else {
      octave = document.flute.octave.options[octave1index].value;
    }
    if((sharp1index == 1) && (note1index == 2 || note1index == 6)) {
      goodinput = false;
    }
    if(goodinput) {
      note1 = note + sharp + octave;
      num_notes++;
      if(num_notes > 1)
        note_string = note_string + ";";
      note_string = note_string + note1;
    }
  }

  if((note2index != -1 || sharp2index != -1 || octave2index != -1) && goodinput) {
    if(note2index == -1) {
      goodinput = false;
    } else {
      note = document.flute.note.options[note2index].value;
    }
    if(sharp2index == -1) {
      sharp = "";
    } else {
      sharp = document.flute.sharp.options[sharp2index].value;
    }
    if(octave2index == -1) {
      goodinput = false;
    } else {
      octave = document.flute.octave.options[octave2index].value;
    }
    if((sharp2index == 1) && (note2index == 2 || note2index == 6)) {
      goodinput = false;
    }
    if(goodinput) {
      note2 = note + sharp + octave;
      if(note2 == note1)
        goodinput = false;
      num_notes++;
      if(num_notes > 1)
        note_string = note_string + ";";
      note_string = note_string + note2;
    }
  }

  if((note3index != -1 || sharp3index != -1 || octave3index != -1) && goodinput) {
    if(note3index == -1) {
      goodinput = false;
    } else {
      note = document.flute.note.options[note3index].value;
    }
    if(sharp3index == -1) {
      sharp = "";
    } else {
      sharp = document.flute.sharp.options[sharp3index].value;
    }
    if(octave3index == -1) {
      goodinput = false;
    } else {
      octave = document.flute.octave.options[octave3index].value;
    }
    if((sharp3index == 1) && (note3index == 2 || note3index == 6)) {
      goodinput = false;
    }
    if(goodinput) {
      note3 = note + sharp + octave;
      if(note3 == note2 || note3 == note1)
        goodinput = false;
      num_notes++;
      if(num_notes > 1)
        note_string = note_string + ";";
      note_string = note_string + note3;
    }
  }

  if(num_notes < 1)
    goodinput = false;

  if(goodinput) {
    storeCookie("multiphonics");
    if(num_notes == 1)
      location = "selectmultiphonic.php?notes=" + escape(note_string)
                  + "&foot=" + nmFootString(document.flute.multiphonicsfoot) + "&splitE="
                    + nmSplitEString(document.flute.multiphonicssplitE) + "&unconventional="
                      + nmUnconventionalString(document.flute.multiphonicsunconventional);
    else
      location = "multiphonics.php?notes=" + escape(note_string)
                  + "&foot=" + nmFootString(document.flute.multiphonicsfoot) + "&splitE="
                    + nmSplitEString(document.flute.multiphonicssplitE) + "&unconventional="
                      + nmUnconventionalString(document.flute.multiphonicsunconventional) + "&index=0";
  } else {
    document.images["multiphonicbadinput"].src = badinput.src;
  }
}


// changeMultiphonic() removes the bad input image when
// the user clicks the note select menus again.

function changeMultiphonic() {
  document.images["multiphonicbadinput"].src = no_badinput.src;
}


// keyboardOutput() sets the keyboardoutput text field to the current
// fingering string if the field exists.

function keyboardOutput() {
  if(document.flute.keyboardoutput != null) {
    var ko;
    ko = fingeringString(fingeringCode());
    ko = ko + " (" + fingeringFootString() + " foot, ";
    if(fingeringSplitEString() == "1")
      ko = ko + "split E";
    else
      ko = ko + "no split E";
    ko = ko + ")";
    document.flute.keyboardoutput.value = ko;
  }
}

