// Copyright Neil Ramsden 2004-2006. All rights reserved.

// View scripts
// Neil Ramsden
// View.js
// 5 Jan 06 -> 27 Feb 06 
//	Uses customised.interaction to distinguish prompts.
//	Allows for nested slideset for frames within table.
//	Advice message is bracketed by <div> for styling.
// 16 Jul 04 -> 27 Aug 04
//
// Uses: customised.interaction to distinguish prompts.

//---------------------------------------------------------------------------

/* Local Constants
*/

//main prompts
//  note: clients should set customised.interaction to a recognised prompt property name

var _shared_clear_prompt = 'click here to clear selections below';
var _clear_prompt = {
  can_back_track: _shared_clear_prompt,
  deterministic: _shared_clear_prompt
};

var _select_prompt = {
  can_back_track: 'either click on the best match below or back-track',
  deterministic: 'click on the first true statement below'
};

//---------------------------------------------------------------------------

/* Global Helpers and Constants
*/

//string helpers and constants

function spelling(s)
//Simple letter-string formatting function
//  s -- string to be formatted in document
//  return -> HTML+angle barckets for input string
{
  return '<span class="letter-string">&lt;' + s + '&gt;</span>';
}

var /*const*/ c_and = ' <strong>AND</strong> ';
var /*const*/ c_not = ' <em>not</em> ';

var /*const*/ c_ordinary = 'no special changes are needed';
var /*const*/ c_unspecial = 'isn\'t special in any of the following ways';


var /*const*/ c_suspect = '<i>you suspect that</i> ';

var /*const*/ c_stumped = 'you\'ve no idea what to do!';

var /*const*/ c_explore = 
  '<p>Don\'t worry.' +
  ' If you\'re unsure, you can just investigate any of the possible choices.</p>' +
  '<p>As you step through a set of choices, you may find none of them fit.</p>' +
  '<p>If so, just back-track to an earlier choice;' +
  ' or go back to the start and try a different route.</p>';


//---------------------------------------------------------------------------

/* Helper Functions
*/

function writeHTMLPrologue(document, title)
//write markup for HTML head section plus body tag
//  document -- target window or frame document
{
  //start cleanly
  document.close();
  document.write();

  //write markup
  var prologue =
'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' +
'<html>' +
  '<head>' +
  '  <meta http-equiv="content-type"' +
  '     content="text/html; charset=ISO-8859-1">' +
  '  <title>' + title + '</title>' +
  '  <meta http-equiv="Content-Script-Type" content="text/javascript">' +
  '  <link href="../shared/common.css" rel="stylesheet" type="text/css">' +
  '  <link href="pane.css" rel="stylesheet" type="text/css">' +
  '</head>' +
  '<body>';
  document.write(prologue);
}

function writeHTMLEpilogue(document)
//write final HTML markup including end body tag
//  document -- target window or frame document
{
  var epilogue =
  '</body>' +
'</html>';
  document.write(epilogue);
  document.close();
}


//---------------------------------------------------------------------------

/* View - displays on a window or frame document

Each View knows its successor, so it can pass on actions to it.
Method displayOn(document) temporarily links the view to document. Generally, 
links are managed by a presentation object.
Use method refresh() to re-write to the current document, eg. after a user 
action.
*/

function clearView()
//clear view; and clear and remove its dependants
//after: this._document == null
//       this.nextView == null
{
  //clear dependants
  if (this.nextView)
    this.nextView.clear();
  this.nextView == null;

  //clear self
  if (this._document)
  {
    this._document.close();
    this._document.write();
    this._document.close();
  }
  this._document = null;
}

function displayViewOn(document)
//display view on document and remember document
//  document -- target window or frame document
//after: this._document == document
{
  this._document = document;
  this.refresh();
}

function refreshView()
//refresh view on current document
{
  if (this._document)
  {
    this._writePrologue(this._document);
    this._writeBody(this._document);
    this._writeEpilogue(this._document);
  }
}

function View(presentation)
//create a new view within presentation
//  presentation -- presentation object linking view to a pane
{
  //fixed fields
  this.presentation = presentation;
  this.nextView = null;

  //updateable fields

  //methods
  this.clear = clearView;
  this.displayOn = displayViewOn;
  this.refresh = refreshView;
  this._writeBody = function(document) { /*override*/ };
  this._writeEpilogue = function(document) { /*override*/ };
  this._writePrologue = function(document) { /*override*/ };
}


//---------------------------------------------------------------------------

/* AdviceView - displays advice on a window or frame document
*/

function writeAdvice(document)
//write advice to document
//  document -- target window or frame document
{
  //write pre-amble
  var begin_view =
    '<p class="pane-header">' +
      'Do this' +
    '</p>';
  document.write(begin_view);

  //write advice
  var markup = 
    '<div class="advice">' +
      this.advice.message +
    '</div>';
  document.write(markup);

  //write conclusion
  var end_view =
    '';
  document.write(end_view);
}

function AdviceView(presentation, advice)
//create a new advice view 
//  presentation -- presentation object linking view to a pane
//  advice -- advice object
{
  //inheritance
  this.base = View;
  this.base(presentation);

  //fixed fields
  this.advice = advice;

  //methods
  this._writeBody = writeAdvice;
  this._writeEpilogue = function(document) { /*override*/ };
  this._writePrologue = function(document) { /*override*/ };
}
AdviceView.prototype = new View;

//advice constants

var /*const*/ holdingAdvice = new Advice('to be completed!');


//---------------------------------------------------------------------------

/* ChoiceView - displays option choices on a window or frame document

Each ChoiceView knows its successor, so it can pass on actions to it.
*/

function clearChoiceView()
//clear view; and clear and remove its dependants
//after: this._document == null
//       this.nextView == null
{
  //forget current option
  this.choice.setActiveValue(null);

  //do base clear operations
  this.baseClear();
}

function doSelect(index)
//respond to option in list
//  index -- index of option in choice options list
{
  //clear dependant views
  if (this.nextView)
  {
    this.nextView.clear();
  }

  //update active choice
  this.choice.setActiveValue(index);
  this.refresh();

  //update next view
  if (index == null)
  {
    this.nextView = null;  
  }
  else
  {
    this.nextView = this.choice.active().makeView(this.presentation);
    this.presentation.displayView(this.nextView);
  }
}

function writeOption(document, condition, value, selected)
//write option to document
//  document -- target window or frame document
//  condition -- text for option
//  value -- pointer to action object to be invoked when selected
//  selected -- true if option is selected
{
  //add option markup
  var check_markup = ' class="plain-option"';
  if (selected)
    check_markup = ' class="active-option"';
  var markup = 
    '<p><a' +
      ' href="javascript:top.checker.processOption(window.name,' + value + ');void(0);"' +
      ' title="click to select"' +
      check_markup +
      '>' +
      condition +
    '</a></p>';
  document.write(markup);
}

function writeOptions(document)
//write a sequence of options to document
//  document -- target window or frame document
{
  //write pre-amble
  var begin_view =
    '<p class="pane-header">' +
      'Select' +
    '</p>';
  document.write(begin_view);

  //write top clear option
  var is_to_clear = !!this.choice.active();
  if (is_to_clear)
    this._writeOption(document, _clear_prompt[customised.interaction],
      null, false);
  else
    this._writeOption(document, _select_prompt[customised.interaction], 
      null, true);

  //write options
  var options = this.choice.options;
  for (var i=0; i<options.length; ++i)
  {
    var is_active = (i==this.choice.activeIndex());
    this._writeOption(document, options[i].text, i, is_active);
  }

  //write conclusion
  var end_view =
      '';
  document.write(end_view);
}

function ChoiceView(presentation, choice)
//create a new choice View 
//  presentation -- presentation object linking views and windows
//  choice -- choice object
{
  //inheritance
  this.base = View;
  this.base(presentation);

  //fixed fields
  this.choice = choice;

  //methods
  this.clear = clearChoiceView;
  this.baseClear = clearView;
  this.doSelect = doSelect;
  this._writeOption = writeOption;
  this._writeBody = writeOptions;
  this._writeEpilogue = function(document) { /*override*/ };
  this._writePrologue = function(document) { /*override*/ };
}
ChoiceView.prototype = new View;
