/* Raul Parolari, October 2007  */

/* Some notations helpers to write html strings */

var al = function() { alert('hi from tutor') }

var str = {
     span_class:  "<span class='blue'>initialize</span>",
     cls_meth :   "<span class='red'>log</span>",
     cls_bb:      '<span style="font-weight: bold; color:blue">',
     cls_br:     '<span style="font-weight: bold; color:red">',
     span_em_yl: '<span style="font-style: italic; color: maroon">',
     end: null
 };

function gen_span(class_name, color) {
   if (! color) color = burgundy;

   str=' <span style="color: ' + color + '">' + class_name + '</span>';
   
   return str;
}

/* for a line of text that begins without space */
function gen_span_nl(class_name, color) {
   if (! color) color = 'black';

   str= '<span style="color: ' + color + '">' + class_name + '</span>';
   
   return str;
}

var nl = ' \n';

// link to tutorial on class_inherit_attr, to embed in innnerHTML

call_open_win = function() { 
	                          lib_open_win("/Rails/class_inheritable", "large"); 
                           }

var anchor_to_class_inherit = '(seen <a href="javascript: void(0)" \
                        onclick="call_open_win(); return false">before).</a>';

// note begin and note end
var note_b = '<span style="font-size: 14px">[';
var note_e = '</span>]';

var burgundy = '#800000';

/*  End of notation helpers */

var phases = 
[

   // 1a
   [
      [ 1 ],
                                  /* | up to character 38 */
note_b + 'ActionController is abbreviated => AC' + note_e +nl+
nl+
'At startup, class AC::Base is loaded'
		
   ],

   // 1b
   [
      [ 1 ],
                            /* max 48 characters */
note_b + 'ActionController is abbreviated => AC' + note_e +nl+
nl+
'At startup, class AC::Base is loaded' +nl+
nl+
'AC::Base includes module' + gen_span('AC::Helpers') +'.'

   ],

   // 1c
   [
      [ 1 ],
                            /* max 48 characters */
note_b + 'ActionController is abbreviated => AC' + note_e +nl+
nl+
'At startup, class AC::Base is loaded'+nl+
nl+
'AC::Base includes module' + gen_span('AC::Helpers') + '.' +nl+
nl+
'This module defines an' + gen_span('included') +nl+
'callback.'

   ],

   // 2.0
   [
      [ 1 ],
                           /* | max 48 characters */
      nl
   ],


   // Phase 2a: begin explanation of 'included'
   [  
      [ 1 ],    

'Actions of' + gen_span('included')  + ' callback (on' + nl +
'behalf of class AC::Base) are:'  + nl +
nl +
'-instantiates an Anonymous Module'  + nl +
' referred by'+ gen_span('master_helper_module')

   ],

   // Phase 2b: makes AC::Base extend module ClassMethods
   [  
      [ 1 ],    

'Actions of' + gen_span('included')  + ' callback (on' + nl +
'behalf of class AC::Base) are:'  + nl +
nl +
'-instantiates an Anonymous Module'  + nl +
' referred by'+ gen_span('master_helper_module') + nl +
nl +
'-extends module' + gen_span('ClassMethods') +' and' +nl+
' installs mthd' + gen_span('inherited_with_helper') +nl+
' (called when controller subclassed)'

   ],


   // Phase 3.0: blank
   [  
      [ 1 ],    

      nl
   ],

   // Phase 3a
   [
      [1 ],

'On Request arrival, ApplicController' +nl+
'is subclassed.'

   ],

   // Phase 3b
   [
      [1 ],

'On Request arrival, ApplicController' +nl+
'is subclassed.' +nl+
nl+
gen_span_nl('inherited_with_helper', burgundy) + ' is triggered:' +nl+
'-instantiates an Anonymous Module'

   ],


   // Phase 3c
   [
      [1 ],

'On Request arrival, ApplicController' +nl+
'is subclassed.' +nl+
nl+
gen_span_nl('inherited_with_helper', burgundy) + ' is triggered:' +nl+
'-instantiates an Anonymous Module' +nl+
nl+
gen_span_nl('-includes', burgundy) + ' into it previous Anon Mod'


   ],

   // Phase 3d
   [
      [1 ],

'On Request arrival, ApplicController' +nl+
'is subclassed.' +nl+
nl+
gen_span_nl('inherited_with_helper', burgundy) + ' is triggered:' +nl+
'-instantiates an Anonymous Module' +nl+
nl+
gen_span_nl('-includes', burgundy) + ' into it previous Anon Mod' +nl+
nl+ '-then finds and includes module' +nl+
gen_span('ApplicationHelper')

   ],

   // Phase 3e
   [
      [1 ],

'On Request arrival, ApplicController' +nl+
'is subclassed.' +nl+
nl+
gen_span_nl('inherited_with_helper', burgundy) + ' is triggered:' +nl+
'-instantiates an Anonymous Module' +nl+
nl+
gen_span_nl('-includes', burgundy) + ' into it previous Anon Mod' +nl+
nl+ '-then finds and includes module' +nl+
gen_span('ApplicationHelper') + gen_span('    # end', 'black')

   ],

   // Phase 7e
   [
      [1 ],

       null,

'Method inherited_with_helper proceeds to:' +nl+
nl+
'a)instantiate an Anonym Module (<em>another</em> one!)' +nl+
' storing its ref in a new master_helper_mod var' +nl+
'b)makes this module include previous Anonym Mod!' +nl+
'c)as well as the ApplicationHelper!' +nl+
nl+
" Let us think at the purpose of all this..."

   ],

   // Phase 8
   [
      [2 ],

      nl
   ],


   // Phase 8a
   [
      [2 ],

' Clearly, a <em>chain of modules</em> is being built on behalf of somebody. The beneficiaries' +nl+
' cannot be Controllers, as they only reference (but do not include) these modules;' +nl+
' they can only be the Views.'

   ],

   // Phase 8b
   [
      [2 ],

' Clearly, a <em>chain of modules</em> is being built on behalf of somebody. The beneficiaries' +nl+
' cannot be Controllers, as they only reference (but do not include) these modules;' +nl+
' they can only be the Views.' +nl+
nl+
' Of course, we have to see how the module chain will be linked to the View; but we' +nl+
' get the idea.'

   ],

   // Phase 8c
   [
      [2 ],


' Clearly, a <em>chain of modules</em> is being built on behalf of somebody. The beneficiaries' +nl+
' cannot be Controllers, as they only reference (but do not include) these modules;' +nl+
' they can only be the Views.' +nl+
nl+
' Of course, we have to see how the module chain will be linked to the View; but we' +nl+
' got the idea.' +nl+
nl+
" Time to return to the Mongrel: it had loaded the ApplicationCntroller..."

   ],

   // Phase 9.0
   [
      [1 ],

      nl,   // blank 1st window

      null
   ],

   // Phase 9a
   [
      [1 ],

'At request arrival, the' + gen_span('Mongrel') +':' +nl+
nl+
'1)requests the' + gen_span('CGI') + ' class for a cgi object, and' +nl+
'  processes it with CgiRequest & CgiResponse' +nl+
nl+
'2)loads' + gen_span('ApplicationController') + ' (< AC::Base);' +nl+
'  inherited_with_helper does its scaffolding.',

       null
   ],


   // Phase 10a: 2nd window opens with one line
   [
      [1 ],

      null, 

nl+
'3)asks Routing to recognize controller [eg:User].'

   ],

   // Phase 10b: Routing recognizes and loads UserController
   [
      [1 ],

      null, 

nl+
'3)asks Routing to recognize controller [eg:User].' +nl+
'  Routing recognizes and loads UserController;'

   ],

   // Phase 10c: inherited_w_h includes UserHelper
   [
      [1 ],

      null, 
nl+
'3)asks Routing to recognize controller [eg:User].'  +nl+
'  Routing recognizes and loads UserController;'    +nl+
'  inherited_w_h includes' + gen_span('UserHelper') + ' in Anon chain'

   ],

   // Phase 10d: mongrel gets controller from Routing
   [
      [1 ],

      null, 

nl+
'3)asks Routing to recognize controller [eg:User].'  +nl+
'  Routing recognizes and loads UserController;'    +nl+
'  inherited_w_h includes' + gen_span('UserHelper') + ' in Anon chain' +nl+
nl+ 
'4)Mongrel gets the controller class name'

   ],

   // Phase 10e: mongrel invokes controller
   [
      [1 ],

      null, 

nl+
'3)asks Routing to recognize controller [eg:User].'  +nl+
'  Routing recognizes and loads UserController;'    +nl+
'  inherited_w_h includes' + gen_span('UserHelper') + ' in Anon chain' +nl+
nl+ 
'4)Mongrel gets the controller class name' +nl+
'  and invokes it:' + gen_span('controller.process(req, resp)') +nl

   ],

   // Phase 11.0: 
   [
      [1 ],

      nl
   ],

   // Phase 11a: class method process is inherited
   [
      [1 ],

'The class method' + gen_span('process') + ' is inherited from' +nl+
'AC::Base by UserController; its actions are:'
   ],

   // Phase 11b: class process creates instance and calls homonymous instance
   [
      [1 ],

'The class method' + gen_span('process') + ' is inherited from' +nl+
'AC::Base by UserController; its actions are:' +nl+
nl+
'1)creates an instance and calls a homonymous' +nl+
'instance method:' + gen_span('new.process(request, response)')
   ],

   // Phase 11c: instance process creates Anon View
   [
      [1 ],

'The class method' + gen_span('process') + ' is inherited from' +nl+
'AC::Base by UserController; its actions are:' +nl+
nl+
'1)creates an instance and calls a homonymous' +nl+
' instance method:' + gen_span('new.process(request, response)') +nl+
nl+
'2)creates Anon class (superclass ActionView::Base)' +nl+
' ' + gen_span('@view_class= Class.new(ActionView::Base)')
   ],

   // Phase 12.0: add blank 2nd window
   [
      [1 ],

      null, nl
   ],

   // Phase 12.a: asks the Class to include the Helpers chain
   [
      [1 ],

      null,
'2)asks the Class to include the Helpers chain:' +nl+
' ' + gen_span('@view_class.send(:include, master_helper_module')

   ],

   // Phase 12.b: instantiates view: @view_class.new
   [
      [1 ],

      null,

'3)asks the Class to include the Helpers chain:' +nl+
' ' + gen_span('@view_class.send(:include, master_helper_module') +nl+
nl+
'4)instantiates view:' + gen_span('@view_class.new(path, {}, self') +nl+
note_b + 'real code differs as it concatenates steps' + note_e

   ],

   // Phase 12.c: bye
   [
      [1 ],

      null,

'2)asks the Class to include the Helpers chain:' +nl+
' ' + gen_span('@view_class.send(:include, master_helper_module') +nl+
nl+
'3)instantiates view:' + gen_span('@view_class.new(path,{},self)') +nl+
' ' + note_b + 'real code differs as it concatenates method calls' + note_e +nl+
nl+
'see how Anon V is connected via proxies to' +nl+
'ActiveView::Base... <em>the end for now</em>'
   ],


/*

@view_class.new(path, {}, self)
'response.template = self.class.view_class.new(self.class.view_root, {}, self)'
'2)tells the Class to include the Anon Module'    +nl+
'  at the start of the list (master_helper_module).'  +nl+
'Therefore, all the helper modules in the Anon' +nl+
'chain are now available to the Anon View Class!'

   // Phase 
   [
      [1 ],

       null,
'Now we can begin to understand the reason for' +nl+
'the Anon modules (&master_helper_module refs):' +nl+
nl+
'a <em>chain of modules</em> is being built for injection' +nl+
'later into the View (as we will see)!' +nl+
nl+
'Time to go back... where were we? ah, yes, the' +nl+
'Mongrel has loaded ApplicCntrlr, and now...'
   ],
*/

   [ // should not get here: 
     [ 1 ],
 
     'end of demo: au revoir!',
  
     null
   ]
   
];  // end phases

/* Coordinates which depend from values in other libraries? perhaps the main page
   should centralize this interdependency. Right now, ugly solution: read 
   X_FIRST_CLASS_BOX var from module that is loaded before this.

   Naming question: we used to call the height 'real height', to indicate the area 
   usable (the 'payload' or 'effective cargo area' of the div as opposed to the
   total height visible which INCLUDES padding and border size); of course, coming
   back months later (and having forgotten a bit about all this) we thought that
   'real' meant the total 'visible' height from border to border! 
   Funny how what a name means to the 'programmer' is the opposite of what it
   means to the 'user' (even when they are the same person).
   Conclusion: we call it now 'inner height' (perhaps it should be css height!).

*/
var X_TUTOR  = 430;  

/*  Recalling Css declaration for cl_tutor:

    div#content .cl_tutor      { border: solid black 1px; background: white;
                                padding: 5px 5px; font-size: 15px; }
*/

  var SIZE_NULL   = 0;
  var SIZE_SINGLE = 1;
  var SIZE_DOUBLE = 2;
  var SIZE_TRIPLE = 3;

var tutor = {

   debug : 0,
   
   set_debug_on: function() { this.debug = 1 },

   box_conf:  {  x       : X_TUTOR,   // x of first box:
                 y       :   5,
                 inner_w : 330,  
                 inner_h : 160,  // 160px = 10+ lines of text at font-size 15px

                 /* we need to know pad_x because when we draw a double box, 
                    we want it to overlap exactly 2 small boxes (to draw well
	                the 3rd box). Perhaps we should have written a different 
					css class for the double box, and avoid this ugly hardcoding.
				 */
                 pad_x   :   5,    
                 sep     :  15, 

                 dbl_box_w: function() { return 760 },
   /* dbl_box_w: function() { return (2 * (this.inner_w + this.pad_x) + this.sep ); }, */
                 

                 end: null
              },

   // keep inner_h multiple of 20pixels (see note on PPF in lib_draw_incl_meth)

   max_nr_boxes: 1,

   phase: 0,     // init phase: represented in msgs with empty array 

   dscrs: [ ],

   /* Each tutorial window is drawn the 1st time it appears in the canvas, and
      it has associated a descriptor; the central attribute of the descriptor 
      is the DOM element of the window. Each time content must be updated, the
      function 'speak' retrieves via this routine the descriptor, and updates
      innerHTML of its element (dscr.elem.innerHTML).
   */
                                // size_type is 0, 1 (normal size), 2 (double)
   crt_box_dscr: function(box_nr) {
	
      var info = 'tutor.crt_box_dscr: box_nr=' + box_nr + ': ';
      //alert(info);
      var conf = this.box_conf;

      var dscr = {
                  x :  conf.x + box_nr * (conf.inner_w + conf.sep + conf.pad_x),
                  y :  conf.y,
                  w :  conf.inner_w, 
                  h :  conf.inner_h,

                  cssClass: 'cl_tutor',
                  id      : 'id_tutor_box' + box_nr, // id_tutor_box_(0|1|2)

                  content :  null, 
                  elem    :  null   // element
                  };

      // at start, SIZE_NULL
      dscr.w = 0; 
	  dscr.h = 0;

      // alert("crt_box_dscr: box_nr=" + box_nr + ', size_type=' + size_type +
      //     ', dscr.w=' + dscr.w + ', dscr.h=' + dscr.h);
      dscr.elem  = drawing.box(dscr);    // DOM element created, stored in dscr
      dscr.elem.style.visibility="hidden";

      // alert(info + dscr.elem.style.width);
      tutor.dscrs[box_nr] = dscr;
      return dscr;
   }, // crt_box_dscr


   update_box_dscr: function(box_nr, size_type, box_text) {
	  var info = 'update_box_dscr: box_nr=' + box_nr + 
	             ', size_type=' + size_type + ': ';
	  //alert(info);
	  var dscr     = tutor.dscrs[box_nr];
	  var conf     = this.box_conf;
	  var had_size = (dscr.elem.width == 0)? false : true;
	  
	  if (size_type == SIZE_NULL)   { 
	     dscr.elem.style.width  = 0; 
		 dscr.elem.style.height = 0;
		 dscr.elem.style.visibility="hidden";
      }
      else {  // size not null
	     if (had_size && box_text == null) { 
			 /* 
			    it had size, still has size, but text null: do nothing as we
			    keep same text as before. With this trick, we avoid having
			    to rewrite text that has to remain constant.
			 */
			 ;
	     }
		 else if (size_type == SIZE_SINGLE)  { 
			 dscr.elem.style.width = conf.inner_w + 'px'; 
		 	 dscr.elem.style.height = conf.inner_h + 'px';
		     dscr.elem.innerHTML = '<pre>' + box_text + '</pre>';
		     dscr.elem.style.visibility="visible";
	
		     //alert(info + 'display=' + dscr.elem.style.visibility);
		  }
	      else if (size_type == SIZE_DOUBLE)  { 
		     dscr.elem.style.width  = conf.dbl_box_w() + 'px';
			 dscr.elem.style.height = conf.inner_h + 'px';
			 dscr.elem.innerHTML = '<pre>' + box_text + '</pre>';
		     dscr.elem.style.visibility="visible";
		     //alert(info + 'display=' + dscr.elem.style.visibility);
		  }
		  else { 
			alert(info + "wrong size=" + size_type + " for box_nr(0..n)=" + box_nr); 
		  }
	  }
   }, // update_box_dscr


   update_winConf_for_newPhase: function() {
      var info = 'update_winConf_for_newPhase: ';
      info += 'phase=' + this.phase + ': ';

      if (this.phase >= phases.length) { 
	     alert("attempt to speak in phase=" + this.phase +
	           ">= nr configured phases=" + phases.length);
	     return;
	  }  // did not implement them yet

      if (this.debug) { alert(info)};

      var phase_dscr   = phases[this.phase];
      var box_conf_arr = phase_dscr[0];
      var arr_length   = box_conf_arr.length;

      if (arr_length != this.max_nr_boxes) {
	     alert(info + 'wrong nr of boxes=' + arr_length + ", expects " + max_nr_boxes);
      }

      var offset  = 1;  // text for box 0 is entry 1..
      for (var box_nr=0; box_nr < arr_length; box_nr++) {
         box_size = box_conf_arr[box_nr];
         box_text = phase_dscr[box_nr + offset];

         debug = 0;
         tutor.update_box_dscr(box_nr, box_size, box_text);
         if (debug) { alert(info + "updated box_nr_(0 based)=" + box_nr 
                                   + ", text=\n" + "'" + box_text + "'") }
      }

      this.phase++;
   }, // update_winConf_for_newPhase
      

   speak: function() { 
      var info='tutor.speak: ';

      this.update_winConf_for_newPhase();
   },  // speak


   // called from main page
   reinitialize: function() {
      //alert("tutor_reinitialize entered");
      tutor.phase = 0;
      tutor.dscrs = [];

      // create the 3 descriptors, each null size 
      // if they do not need to appear, we will set width, height=0
      for (var box_nr=0; box_nr < this.max_nr_boxes; box_nr++) {
	     this.crt_box_dscr(box_nr, 0);
      }
   },

   end: null
}; // end tutor


/*
	'What does inherited() do? it hires a new Anonymous' +nl+
	'module for the subclass, and makes this module' + nl+
	'include the one of the parent class!'

	'  thus, although its code is in ClassMethods, it' +nl+
	'  is logically present in the AC::Base meta' +nl+

	' - class AC::Base includes:
	'     module ' + gen_span('ActionController::Helpers', 'maroon')  + nl +
nl + 
' - the Metaclass* of class AC::Base includes:' + nl +
	nl +
	'  - module ' + gen_span('ActionController::ClassMethods', 'maroon') +nl+
	nl +
	note_b + '* module methods will be available (as name' + nl +
	'  suggests) as class methods' + note_e,
*/

/*
'def self.included(base)' + nl +
'  base.class_inheritable_accessor :master_helper_module' + nl +
'  base.master_helper_module = Module.new' + nl +
'  base.extend(ClassMethods)' + nl +
'  base.class_eval do' + nl +
'    class << self' + nl +
'        alias_method_chain :inherited, :helper' + nl +
'    end' + nl +
'  end' + nl +
'end' + nl
*/
/*
   <a class="new_win small" href="/Rails/class_inheritable">this page</a>
   did not open a new window; because those links are processed when the page 
   loads. Thus we need an explicit call to handler.

'  inherited_with_helper includes ApplicHelper' + nl+
'  along the Anonym Module chain.',
*/
