/* mod_lib.js
 * A collection of javascript functions that are shared by all worker modules.
 * Names of objects are all prefaced by lib_
 * 'module' variable is a global in the calling module. It specifies the name of the module.
 */

function lib_set_mod_state (message, modparent, synthScript, wkrthrottle) {
/* This constructor creates an object to store the components of the module's incoming messages.
 * It specifies the standard form of the API of synthesis module. 
 * Outgoing messages which expect a reply should also take this form.
 * 
 * A mod_var variable maintains module state for the duration of a transaction.
 * Transaction starts at either module initialisation or a valid incoming calling message.
 * Transaction ends at program completion.
 * 
 * To prevent having to always message all state, including variables such as 
 *  the large synthScript, reuse static state (which never needs to change after module initialisation).
 */
	return { 
	init : {parent : modparent, synthScript : synthScript, wkrthrottle : wkrthrottle},
	cu : message.body[0].cu,
	sy : message.body[0].sy,	// synthesis module
	me : message.body[0].me,	// meiosis module
	ak : message.body[0].ak,	// akin module
	se : message.body[0].se,	// settings module
	ba : message.body[0].ba,	// batch module
	from : 	{
			ID 		: message.sender,
			module 	: message.body[0].from.module,
			action 	: message.body[0].from.action,
			status 	: message.body[0].from.status,
			message : message.body[0].from.message
		},	
	dest : message.body[0].dest	
	}
};

function lib_set_binding (version, breadth, depth, synth_flag, bv_type, bnd_val, mos_breadth, min_entropy, def_bind_parent, steps, sywID){
	// This function is only called from the foreground, but it is also suitable for background worker use.	
	return { // a superset of binding attributes used in akin, meiosis and synthesis modules. could be more efficient 
		binding_id: null, // autoincrement by db
		description: null, // set at point of use
		xpar: 0, // 0 indicates no parent
		version: version, // Version of Akinity
		breadth: breadth,
		depth: depth,
		synth_flag: synth_flag, // 0=meiotic. 1=synthetic
		id1_reversal: null, // 0= same polarity as ID=1. 1= reverse polarity
		bv_type: bv_type || 'text', // "text" or "URI"
		act_flag: 0, // 0 is inactive
		bnd_val: bnd_val,
		create_dt: new Date().getTime(),
		conts: null, // array of text zeros and ones
		offset: null,
		mos_breadth: mos_breadth, // Method of Synthesis breadth, set by Akinity (v.0.1 = 8)
		min_entropy: min_entropy,
		def_bind_parent: def_bind_parent,
		syw_base_lot: 0, // lot where a synth worker is to start (synth being recursive). 
		skip_to_lot: 0, // for expansion to avoid recalculating extant lots
		lot: 0, // current lot
		steps: steps, // number of breadth steps that synthesis will need to process
		oos: null, // object of synthesis (organelle)
		sywID: sywID // worker is specific to a lot. can supercede the ba.sywID 
	}
};

function lib_debug(batch, action, status, msg) {
	try {	// comment: Request debug record by Db module worker  
		var wp 			= google.gears.workerPool; 	
		var mv = {
			ba : {
				id 		: batch.id },
			from : {
				module 	: module,
				action 	: action,
				status 	: status	},
			dest : {
				module 	: 'db',
				action 	: 'insert_debug',
				message : msg	}
		};
		wp.sendMessage([mv], batch.dbwID);
	}
	catch(e){
	}
};

function lib_caller (mvl, msg, status, dest_ID){
// pass state between modules 

	Object.prototype.clone = function() {
	  var newObj = (this instanceof Array) ? [] : {};
	  for (i in this) {
	    if (i == 'clone') continue;
	    if (this[i] && typeof this[i] == "object") {
	      newObj[i] = this[i].clone();
	    } else newObj[i] = this[i]
	  } return newObj;
	};

	var wp 			= google.gears.workerPool; 	
	var mv 			= mvl.clone();
 	mv.from.module 	= module; 
	mv.from.status 	= status || mv.from.status || 'success'
	mv.from.message = msg;

	wp.sendMessage([mv], dest_ID);
	lib_debug (mv.ba, mv.from.action, mv.from.status, 'called '+mv.dest.module+'.'+mv.from.module+'.'+mv.from.action+'.'+mv.from.status+'.'+dest_ID);		
	
	delete wp, mv;
};	 

function lib_activate_binding (mv, act_flag) {
/* activate or de-activate a binding according to the state's act_flag.
 * Also set the id1_reversal flag, which indicates polarity relative to the first binding in the culture
*/
	var db 			= google.gears.factory.create('beta.database');
	var rsa1, rsa2;

	try {	
		var binding;
		if (module === 'synthesis') binding = mv.sy; 
		else if (module === 'meiosis') binding = mv.me.Z;
			else throw ('invalid module');
		binding.act_flag = act_flag ?  '1' :  '0';
		lib_caller ( mv, null, null, mv.ba.dbwID);
		
		if (binding.binding_id !== 1) {	// Skip for the first cTag in the culture.
			db.open	(mv.cu.name);
				rsa1 = db.execute('select count(*) from id_id1 where id = ?',[binding.binding_id]);					
				rsa2 = db.execute('select count(*) from id_id1 where id = (?) and bit = bit1' ,[binding.binding_id]);	// count # pos in common and having same value
				binding.id1_reversal = (rsa2.field(0) < rsa1.field(0) / 2) ? 1  : 0;
				lib_debug (mv.ba, 'all: '+rsa1.field(0)+'. match: '+rsa2.field(0));
			db.close;
		}

		mv.dest.module 	= 'db';
		mv.dest.action 	= 'activate_binding';
		lib_caller (mv, null, null, mv.ba.dbwID);	// comment: Request activate binding by Db module worker 
	}
	catch (e) { lib_debug (mv.ba, 'activate', 'exception', e.message|| e); }
};

function lib_insert_binding (mv){
/* Request db worker to insert a binding record
 * Upon completion, db will report back to the calling module as 'insert_binding'
*/
	try {
		var binding;
		if (module === 'synthesis'){
			binding 			= mv.sy;
			binding.synth_flag 	= '1'; 
			binding.act_flag	= '0'; 
			binding.syw_base_lot= 0;
			binding.depth		= 0;
			}
		else if (module === 'meiosis'){
			binding 			= mv.me.Z;
			binding.synth_flag 	= '0'; 
			binding.act_flag	= '0'; 
			binding.xpar		= mv.me.X.binding_id; 	
			binding.create_dt	= new Date().getTime();	
		} 	else throw('invalid module');
		
		mv.dest.module 		= 'db';
		mv.dest.action		= 'insert_binding';
lib_debug (mv.ba, 'lib_insert_binding', 'success', 'calling '+mv.dest.module+' '+mv.ba.dbwID);
		lib_caller ( mv, null, null, mv.ba.dbwID);
	} 
	catch (e) { lib_debug (mv.ba, 'lib_insert_binding', 'exception', e); }
};

function lib_insert_conts(mv) {

	try {	// comment: Request insert contents by db module worker  
	lib_debug (mv.ba, 'lib_insert_conts ', 'success', 'lib_insert_conts '+module);
		var binding;
		if (module === 'synthesis'){
			binding 			= mv.sy;
			binding.offset		= [];					// always null for synth. (defaults to 0 on insert).
			}
		else if (module === 'meiosis'){
			binding 			= mv.me.Z;
			binding.lot			= 0;					// insert from the first ...
			binding.mos_breadth	= binding.breadth; 		//  to the last pos in one whole lot.
		} 	else throw('invalid module');

		mv.dest.module 		= 'db';
		mv.dest.action 		= 'insert_conts';
		mv.from.action 		= 'insert_conts';
		lib_caller (mv, null, null, mv.ba.dbwID);
		lib_debug (mv.ba, mv.from.action, mv.from.status, 'skip_to_lot:'+binding.skip_to_lot+' mos_breadth:'+binding.mos_breadth+' lot:'+binding.lot+'.'+mv.ba.dbwID)
	}
	catch (e) { lib_debug (mv.ba, 'lib_insert_conts', 'exception', e); }
};

function lib_include(url, callback) {  
	var req = google.gears.factory.create("beta.httprequest", "1.0");  
	req.onreadystatechange = function() {  
	if (req.readyState == 4) {  
  	  wp_include.callback = callback;  
    // Hack to workaround the fact that global.eval() doesn't work in IE.  
  	  google.gears.factory.create("beta.timer", "1.0").setTimeout(  
      req.responseText + "\nwp_include.callback()", 0);  
 	  }  
 	}  
 	req.open("GET", url);  
 	req.send(null);  
 }  
 
 
