with (classes) {
//
with (OCP) {
//
OCP.Book = function ()
{
 // with (dom.events.EventListener) call(this);

 with (Common.Observable) call(this);
// with (GUI.Common.Alignable) call(this, AlignClient);
 // with (XHTML.events) call(this, click);

 with (Book)
 {
  // Event handlers

  this[XHTML.events.click + "ed"] = click;
  this[XHTML.events.mouseover] =
  this[XHTML.events.mouseout] = mouseMoved;

  this.handleEvent = handleEvent;

  // Methods

  this.open = open;
  this.close = close;
  this.showVariantUnitDivisions = showVariantUnitDivisions;
  this.showDivision = showDivision;
  this.showFragment = showFragment;
  this.showManuscript = showManuscript;
  this.showReading = showReading;
  this.showText = showText;
  this.get_name = get_name;
  this.getUnit_Element = getUnit_Element;

  // Member variables

  this.The_Heading =
  this.the_text =

  this.The_XPathEvaluator =
  this.The_LSParser = // !!
  this.The_Document =
  this.Text_XSLTProcessor = null;

  this.Text_Element =

  this.the_manuscript =

  this.the_name =
  this.the_textStructure = null;

  with (this)
  {
   with (ownerDocument)
   {
    The_Heading = Heading.construct(getElementById(id + ".The_Heading"));
    the_text = getElementById(id + ".the_text");
   }

   The_XPathEvaluator = new dom.xpath.XPathEvaluator;

   with (dom.ls.DOMImplementationLS) The_LSParser = createLSParser(MODE_ASYNCHRONOUS); // !!

   The_LSParser.addEventListener("load", this, false); // !!

//   The_Document = Application.contentDocument.implementation.createDocument(null, null, null);
//   The_Document.async = false;
/*
   var TextStylesheet_Document = Application.contentDocument.implementation.createDocument(null, null, null);

   with (TextStylesheet_Document) { async = false; load(text_stylesheet); }
*/
   var TextStylesheet_Document = Application.The_LSParser.parseURI(text_stylesheet);

   (Text_XSLTProcessor = new XML.XSLTProcessor).importStylesheet(TextStylesheet_Document);

   addObserver(this);
  }
 }

 return this;
}
//
Book.name = String;
// Book.fragment = Number;
Book.number = String; // Number
Book.manuscript = String;
Book.textStructure = String;
Book.unit = Number;
// Book.division = dom.Element;
// Book.unitDivision = dom.html2.HTMLSpanElement
//
Book.criticalApparatus_textStructure = "criticalApparatus";
Book.fragmented_textStructure = "fragmented";
//
Book.default_manuscript = "Default"; //  // IE doesn't support getParameter, therefore cannot determine default value
//
Book.text_stylesheet = "classes/OCP/Book/text.xsl";
//
Book.Events =
{
 opened : "OCP_Book_opened",
 closed : "OCP_Book_closed",
 textShown : "OCP_Book_textShown",
 unitSelected : "OCP_Book_unitSelected"
}
//
Book.construct = function (The_HTMLDivElement) { with (Book) { return call(The_HTMLDivElement); }}
//
Book.click = function (The_MouseEvent) { with (Book) with (this)
{
 with (The_MouseEvent.target) switch (tagName.toLowerCase())
 {
  case "span": if (className.indexOf("variant") + 1 || className.indexOf("dagger") + 1)
  {
   broadcastAsync(Events.unitSelected, unit(id));
  }
   break;
  default:;
 }
}}
//
Book.mouseMoved = function (The_MouseEvent) { with (Book) with (this)
{
 with (The_MouseEvent.target) switch (tagName.toLowerCase())
 {
  case "span": if (className.indexOf("unit") + 1 || className.indexOf("variant") + 1)
  {
   if (The_MouseEvent.type == XHTML.events.mouseover) className += '-' + XHTML.events.mouseover;
   else className = className.replace('-' + XHTML.events.mouseover, "");
  }
   break;
  default:;
 }
}}
//
//
Book.handleEvent = function (evt) { with (Book) with (this)
{
 switch (evt.type)
 {
  case "load":
  {
   The_Document = evt.newDocument;

   if (! the_name) the_name = The_Document.documentElement.getAttribute("filename");

   var title_text = The_Document.documentElement.getAttribute("title");

   The_Heading.setTitle(title_text);
   The_Heading.setManuscript(default_manuscript); // setReading(the_manuscript = default_manuscript);

   the_textStructure = The_Document.documentElement.getAttribute("textStructure");

   broadcastAsync(Events.opened, The_Document);
  }
   break;
  default:;
 }
}}
//
Book.open = function (book_name) { with (Book) with (this)
{
 if (The_LSParser.busy) return; // !!

 The_LSParser.parseURI(Application.book_path + book_name + ".xml");
}}
/*
Book.open = function (book_name) { with (Book) with (this)
{
 The_Document = Application.The_LSParser.parseURI(Application.book_path + book_name + ".xml");

 if (! the_name) the_name = The_Document.documentElement.getAttribute("filename");

 var title_text = The_Document.documentElement.getAttribute("title");

 The_Heading.setTitle(title_text);
 The_Heading.setManuscript(default_manuscript); // setReading(the_manuscript = default_manuscript);

 the_textStructure = The_Document.documentElement.getAttribute("textStructure");

 broadcastAsync(Events.opened, The_Document);
}}
*/
Book.close = function () { with (Book) with (this)
{
 the_name = Text_Element = null;

 Text_XSLTProcessor.removeParameter(null, "the_manuscript");
 Text_XSLTProcessor.removeParameter(null, "showVariantUnitDivisions");

 if (the_text) with (the_text) while (lastChild) removeChild(lastChild); // Free up some memory

 broadcast(Events.closed);
}}
//
Book.showVariantUnitDivisions = function (show) { with (Book) with (this)
{
 Text_XSLTProcessor.setParameter(null, "showVariantUnitDivisions", show? true : ""); // : false // Safari workaround

 if (Text_Element) showText();
}}
//
Book.showDivision = function (division_number) { with (Book) with (this)
{
 var division_expression = "/book/version/text/div";

 division_expression += division_number? ("[@number = '" + division_number + "']") : "[position() = 1]";

 Text_Element = The_XPathEvaluator.evaluate(division_expression, The_Document.documentElement, null, dom.xpath.XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

 if (! Text_Element) return; // !!

 if (! division_number) division_number = Text_Element.getAttribute("number");

 // Safari workaround
 var div_position = division_number? 1 + The_XPathEvaluator.evaluate("count(preceding-sibling::div)", Text_Element, null, dom.xpath.XPathResult.NUMBER_TYPE, null).numberValue : 1;

 with (Text_XSLTProcessor)
 {
  setParameter(null, "from_positions", div_position);
  setParameter(null, "to_positions", div_position);

  removeParameter(null, "fragment_number");
 }

 // End Safari workaround
 showText();

 The_Heading.setReading(Text_Element.parentNode, div_position, div_position); // Safari workaround
}}
//
Book.showFragment = function (fragment_number) { with (Book) with (this)
{
 var text_expression = "/book/version/text";

 Text_Element = The_XPathEvaluator.evaluate(text_expression, The_Document.documentElement, null, dom.xpath.XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

 if (! Text_Element) return; // !!

 with (Text_XSLTProcessor)
 {
  setParameter(null, "fragment_number", fragment_number);

  removeParameter(null, "from_positions");
  removeParameter(null, "to_positions");
 }

 showText();

 The_Heading.setFragment(Text_Element.parentNode, fragment_number); // Safari workaround
}}
//
Book.showManuscript = function (this_manuscript) { with (Book) with (this)
{
 Text_XSLTProcessor.setParameter(null, "the_manuscript", the_manuscript = this_manuscript);

 if (Text_Element) showText();

 The_Heading.setManuscript(the_manuscript);
}}
//
Book.showReading = function (from_positions, to_positions) { with (Book) with (this)
{
 with (Text_XSLTProcessor)
 {
  setParameter(null, "from_positions", from_positions.toString());

  if (to_positions) setParameter(null, "to_positions", to_positions.toString());
  else removeParameter(null, "to_positions");
 }

 var text_expression = "/book/version/text"; // This will change to factor in multiple versions

 Text_Element = The_XPathEvaluator.evaluate(text_expression, The_Document.documentElement, null, dom.xpath.XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

 if (! Text_Element) return; // !! throw

 showText();

 The_Heading.setReading(Text_Element, from_positions, to_positions);
}}
//
Book.showText = function (The_Element) { with (Book) with (this)
{
 if (! The_Element) The_Element = Text_Element;

 if (The_Element) // try
 {
  var Text_Document = Text_XSLTProcessor.transformToDocument(The_Element.ownerDocument.documentElement); // The_Element // Safari workaround

                     // IE doesn't support importNode
  var rendered_text = Application.contentDocument.importNode(Text_Document.documentElement, true);

  replaceChild(rendered_text, the_text); the_text = rendered_text;

  with (XHTML.events) call(the_text, click, mouseover, mouseout);

  the_text.addObserver(this);
 }
// catch (e) {}

 broadcast(Events.textShown);
}}
//
Book.get_name = function () { with (Book) with (this) { return the_name; }}
//
Book.getUnit_Element = function (this_unit) { with (Book) with (this)
{
 var unit_expression = "/book/version/text//unit[@id = " + this_unit + "]";

 var Unit_Element = The_XPathEvaluator.evaluate(unit_expression, The_Document.documentElement, null, dom.xpath.XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

 return Unit_Element;
}}
//
}
//
}
