function ReadControl(id, title)
{
  var _infoData = null;
  var _bookmark = null;

  var _onTextSizeChanged = null;
  var _onFlowChanged = null;
  var _onLayoutChanged = null;
  var _onNotesEnabledChanged = null;
  var _onParagraphsEnabledChanged = null;

  var _onPreviousBook = null;
  var _onPreviousChapter = null;
  var _onNextChapter = null;
  var _onNextBook = null;

  var _element = $(document.createElement("div"));
  var _header = $(document.createElement("div"));
  var _info = $(document.createElement("div"));
  var _text = $(document.createElement("div"));
  var _nav = $(document.createElement("ol"));
  var _prevBook = $(document.createElement("li"));
  var _prevChapter = $(document.createElement("li"));
  var _nextChapter = $(document.createElement("li"));
  var _nextBook = $(document.createElement("li"));

  var _heading = $(document.createElement("h1"));
  var _resize = $(document.createElement("ol"));
  var _resizeSmall = $(document.createElement("li"));
  var _resizeMedium = $(document.createElement("li"));
  var _resizeLarge = $(document.createElement("li"));

  var _paragraphs = $(document.createElement("ol"));
  var _paragraphsSwitch = $(document.createElement("li"));

  var _notes = $(document.createElement("ol"));
  var _notesSwitch = $(document.createElement("li"));

  var _layout = $(document.createElement("ol"));
  var _layoutNone = $(document.createElement("li"));
  var _layoutInline = $(document.createElement("li"));
  var _layoutOverline = $(document.createElement("li"));

  var _flow = $(document.createElement("ol"));
  var _flowVertical = $(document.createElement("li"));
  var _flowHorizontal = $(document.createElement("li"));

  _element.attr('id', id);
  _element.addClass('pane');
  _header.addClass('header');
  _info.addClass('info');
  _text.addClass('text');
  _nav.addClass('navigation');
  _heading.text(title);
  _resize.addClass('resize');
  _resize.attr('title', 'Choose a text size');
  _resize.data('SelectedSize', 'medium');
  _resizeSmall.addClass('small');
  _resizeSmall.data('Size','small');
  _resizeSmall.attr('title', 'Click to set the text size to small');
  _resizeMedium.addClass('medium active');
  _resizeMedium.data('Size','medium');
  _resizeMedium.attr('title', 'Click to set the text size to medium');
  _resizeLarge.addClass('large');
  _resizeLarge.data('Size','large');
  _resizeLarge.attr('title', 'Click to set the text size to large');
  _paragraphs.addClass('paragraphs');
  _paragraphs.attr('title', 'Click to toggle paragraph breaks');
  _paragraphsSwitch.addClass('switch active');
  _paragraphsSwitch.attr('title', 'Click to toggle paragraph breaks');
  _notes.addClass('notes');
  _notes.attr('title', 'Click to toggle verse notes');
  _notesSwitch.addClass('switch active');
  _notesSwitch.attr('title', 'Click to toggle verse notes');
  _layout.addClass('layout');
  _layout.attr('title', 'Choose a lexical layout mode');
  _layout.data('SelectedLayout', 'inline');
  _layoutNone.addClass('none');
  _layoutNone.data('Layout','none');
  _layoutNone.attr('title', 'Click to hide lexical information');
  _layoutInline.addClass('inline active');
  _layoutInline.data('Layout','inline');
  _layoutInline.attr('title', 'Click to use inline layout for lexical information');
  _layoutOverline.addClass('overline');
  _layoutOverline.data('Layout','overline');
  _layoutOverline.attr('title', 'Click to use overline layout for lexical information');
  _flow.addClass('flow');
  _flow.attr('title', 'Choose a direction for text flow');
  _flow.data('SelectedFlow', 'horizontal');
  _flowVertical.addClass('vertical active');
  _flowVertical.data('Flow','vertical');
  _flowVertical.attr('title', 'Click to make text flow vertically');
  _flowHorizontal.addClass('horizontal');
  _flowHorizontal.data('Flow','horizontal');
  _flowHorizontal.attr('title', 'Click to make text flow horizontally (where supported)');
  _prevBook.addClass('previousBook');
  _prevBook.attr('title', 'Go to the previous book');
  _prevBook.bind('click', function (e) { if (_onPreviousBook != null) { _onPreviousBook(BibleBookmark.FromBookId(_bookmark.bookId() - 1)); } return false; } );
  _prevBook.bind('dblclick', function (e) { return false; } );
  _prevChapter.addClass('previousChapter');
  _prevChapter.attr('title', 'Go to the previous chapter');
  _prevChapter.bind('click', function (e) { if (_onPreviousChapter != null) { _onPreviousChapter(BibleBookmark.FromChapterId(_bookmark.chapterId() - 1)); } return false; } );
  _prevChapter.bind('dblclick', function (e) { return false; } );
  _nextBook.addClass('nextBook');
  _nextBook.attr('title', 'Go to the next book');
  _nextBook.bind('click', function (e) { if (_onNextBook != null) { _onNextBook(BibleBookmark.FromBookId(_bookmark.bookId() + 1)); } return false; } );
  _nextBook.bind('dblclick', function (e) { return false; } );
  _nextChapter.addClass('nextChapter');
  _nextChapter.attr('title', 'Go to the next chapter');
  _nextChapter.bind('click', function (e) { if (_onNextChapter != null) { _onNextChapter(BibleBookmark.FromChapterId(_bookmark.chapterId() + 1)); } return false; } );
  _nextChapter.bind('dblclick', function (e) { return false; } );

  _paragraphs.append(_paragraphsSwitch);
  _notes.append(_notesSwitch);
  _nav.append(_prevBook, _prevChapter, _nextChapter, _nextBook);
  _resize.append(_resizeSmall, _resizeMedium, _resizeLarge);
  _layout.append(_layoutNone, _layoutInline, _layoutOverline);
  _flow.append(_flowVertical, _flowHorizontal);
  _header.append(_resize, _paragraphs, _notes, _flow, _layout, _nav, _heading, _info);
  _element.append(_header, _text);

  _resize.children('li').bind('click', function(e)
      {
        var currentNode = $(this);
        var textSize = currentNode.data('Size');
        if (currentNode.hasClass('active') && _text.hasClass(textSize)) { return; }
        var textClass = 'small medium large'.replace(textSize, '');
        currentNode.siblings('.active').removeClass('active');
        currentNode.addClass('active');
        _text.removeClass(textClass);
        _text.addClass(textSize);
        _resize.data('SelectedSize', textSize);
        if (_onTextSizeChanged != null)
        {
          _onTextSizeChanged(textSize);
        }
      }
    );

  _layout.children('li').bind('click', function(e)
      {
        var currentNode = $(this);
        var layoutMode = currentNode.data('Layout');
        if (currentNode.hasClass('active') && _text.hasClass(layoutMode)) { return; }
        var layoutClass = 'none inline overline'.replace(layoutMode, '');
        currentNode.siblings('.active').removeClass('active');
        currentNode.addClass('active');
        _text.removeClass(layoutClass);
        _text.addClass(layoutMode);
        _resize.data('SelectedLayout', layoutMode);
        if (_onLayoutChanged != null)
        {
          _onLayoutChanged(layoutMode);
        }
      }
    );

  _flow.children('li').bind('click', function(e)
      {
        var currentNode = $(this);
        var flowMode = currentNode.data('Flow');
        if (currentNode.hasClass('active') && _text.hasClass(flowMode)) { return; }
        var flowClass = 'vertical horizontal'.replace(flowMode, '');
        currentNode.siblings('.active').removeClass('active');
        currentNode.addClass('active');
        _text.removeClass(flowClass);
        _text.addClass(flowMode);
        _flow.data('SelectedFlow', flowMode);
        if (_onFlowChanged != null)
        {
          _onFlowChanged(flowMode);
        }
      }
    );

  _notesSwitch.bind('click', function(e)
      {
        var currentNode = $(this);
        var off = !_text.hasClass('hidenotes');

        if (off) { currentNode.removeClass('active'); _text.addClass('hidenotes'); }
        else { currentNode.addClass('active'); _text.removeClass('hidenotes'); }

        if (_onNotesEnabledChanged != null)
        {
          _onNotesEnabledChanged(!off);
        }
      }
    );

  _paragraphsSwitch.bind('click', function(e)
      {
        var currentNode = $(this);
        var off = !_text.hasClass('hideparagraphs');
        if (off) { currentNode.removeClass('active'); _text.addClass('hideparagraphs'); }
        else { currentNode.addClass('active'); _text.removeClass('hideparagraphs'); }

        if (_onParagraphsEnabledChanged != null)
        {
          _onParagraphsEnabledChanged(!off);
        }
      }
    );

  this.getNode = function() { return _element[0]; }
  this.getContentNode = function() { return _text[0]; }

  this.bookmark = function()
  {
    return _bookmark;
  }

  this.content = function(content)
  {
    _text[0].innerHTML = content.html;
    _bookmark = content.bookmark;
    if (content.info != null)
    {
      _info.empty();
      for (var i=0; i<content.info.length; i++)
      {
        var infoSection = $(document.createElement('span'));
        infoSection.html(content.info[i].content);
        infoSection.addClass(content.info[i].css);
        infoSection.attr('title', content.info[i].title);
        if (content.info[i].click) { infoSection.bind('click', content.info[i].click); }
        _info.append(infoSection);
      }
    }
    _heading.text(_bookmark.text());
    _heading.attr('title', _bookmark.text());
  }

  this.textSize = function(size)
  {
    if (size == null) { return _resize.data('SelectedSize'); }
    else { $(_resize).children('.' + size).trigger('click'); }
  }

  this.layoutMode = function(mode)
  {
    if (mode == null) { return _layout.data('SelectedLayout'); }
    else { $(_layout).children('.' + mode).trigger('click'); }
  }

  this.flowMode = function(mode)
  {
    if (mode == null) { return _flow.data('SelectedFlow'); }
    else { $(_flow).children('.' + mode).trigger('click'); }
  }

  this.notesEnabled = function(flag)
  {
    var disabled = _text.hasClass('hidenotes');
    if (flag == null) { return !disabled; }
    else { if (disabled.toString() == flag.toString()) { _notesSwitch.trigger('click'); } }
  }

  this.paragraphsEnabled = function(flag)
  {
    var disabled = _text.hasClass('hideparagraphs');
    if (flag == null) { return !disabled; }
    else { if (disabled.toString() == flag.toString()) { _paragraphsSwitch.trigger('click'); } }
  }

  this.onTextSizeChanged = function(callback)          { _onTextSizeChanged = callback; }
  this.onFlowChanged = function(callback)              { _onFlowChanged = callback; }
  this.onLayoutChanged = function(callback)            { _onLayoutChanged = callback; }
  this.onNotesEnabledChanged = function(callback)      { _onNotesEnabledChanged = callback; }
  this.onParagraphsEnabledChanged = function(callback) { _onParagraphsEnabledChanged = callback; }
  this.onPreviousBook = function(callback)             { _onPreviousBook = callback; }
  this.onPreviousChapter = function(callback)          { _onPreviousChapter = callback; }
  this.onNextChapter = function(callback)              { _onNextChapter = callback; }
  this.onNextBook = function(callback)                 { _onNextBook = callback; }
}

function BibleNavigator(host, src)
{
  var _dragging = false;
  var _bookmarks = new Array();
  var _bookmarkPositions = new Array();
  var _markerPosition = 0;

  var _onClick = null;
  var _onTextRequested = null;
  var _onPositionChanged = null;

  var _element = $(host);
  var _marker = $(document.createElement("button"));
  _marker.addClass("bookmark marker");

  var _tooltip = $(document.createElement("span"));
  _tooltip.addClass("tooltip");

  if (src)
  {
    var _image = $(document.createElement('img'));
    _image.attr("src", src);
  }

  for (var i=0;i<6;i++)
  {
    _bookmarks.push($(document.createElement("button")));
    _bookmarks[i].addClass("bookmark mark" + (i+1).toString());
    _bookmarks[i].hide();
    _element.append(_bookmarks[i]);
    _bookmarkPositions.push(0);
  }

  var updateMarker = function(position)
  {
    _markerPosition = position;
    _marker.css("left", _markerPosition.toString() + "%");
  }

  var updateBookmark = function(index, position, visible)
  {
    _bookmarkPositions[index] = position;
    _bookmarks[index].css("left", _bookmarkPositions[index].toString() + "%");
    if (visible) { _bookmarks[index].show(); }
    else { _bookmarks[index].hide(); }
  }

  _element.bind("selectstart", function(e) { return false; } );
  _element.bind("mousedown", function(e)
      {
        var button = 0;
        if (typeof(e.which) == "number") { button = e.which; }
        else if(typeof(e.button) == "number") { e = e.button; }
        _dragging = (button == 1);
        return false;
      }
    );

  _element.bind("mousemove", function(e)
      {
        var navigator = _element;
        var position = (100.0 / navigator.innerWidth()) * parseInt(e.pageX);

        if (_onTextRequested)
        {
          _tooltip.text(_onTextRequested(position));
        }
        else
        {
          _tooltip.text(position.toString());
        }
        var offset = -(_tooltip.outerWidth() / 100.0) * position;

        _tooltip.css('top', e.pageY + 'px');
        _tooltip.css('left', e.pageX + 'px');
        _tooltip.css('margin-left', offset);

        if (_dragging)
        {
          updateMarker(position);
        }

        return false;
      }
    );

  _element.bind("mouseup", function(e)
      {
        var navigator = _element;
        var position = (100.0 / navigator.innerWidth()) * parseInt(e.pageX);

        updateMarker(position);
        if (_onPositionChanged) { _onPositionChanged(BibleBookmark.FromPosition(position)); }

        _dragging = false;
        return true;
      }
    );

  _element.append(_marker);
  _element.append(_tooltip);
    _element.append(_image);
  this.onTextRequested = function(callback)
  {
    _onTextRequested = callback;
  }

  this.onPositionChanged = function(callback)
  {
    _onPositionChanged = callback;
  }

  this.marker = function(position)
  {
    if (position == null) { return _markerPosition; }
    else { updateMarker(position); }
  }

  this.bookmark = function(index, position, visible)
  {
    if (index == null) { throw "Fail"; }
    if (index != null && position == null) { return _bookmarkPositions[index]; }
    else { updateBookmark(index, position, visible); }
  }
}
