// CLASSES THAT WILL HANDLE MODULES, GROUPS AND THEIR MANAGEMENT
// COPYRIGHT Cristian Vrabie @ DDNet - 29.March.2007
var EVENT_PAGELOAD = 1; //impropper named! marks when module is loading for first time
var EVENT_REFRESH = 2; //marks when module is refreshing
var EVENT_INPUT = 3; //marks when module is recontruncting having received some input from user

var HTML_REPLACE = 0; //replace curent html in area with new one
var HTML_APP_HEAD = 1; //append new html at the beginning of the html in area
var HTML_APP_TAIL = 2; //append new html at the end of the html in area

var MM_ACTIVE_MODULES=0; //the number of total active modules
var MM_LOADED_MODULES=0; //the number of total loaded modules
var MM_ACTIVE_MODULES_CONTINUE_INCREMENT=1; //flag that permits incrementation of the MM_ACTIVE_MODULES variable


/**************************************************************************/

// MODULE entity
function MODULE( _name, _pars, _gpars, _css, _isRefreshing, _rtime, _isActive, _word  )
{
	this.name = _name;
	this.pars = _pars;
	this.gpars = _gpars;
	this.css = _css;
	this.isRefreshing = _isRefreshing;
	this.rtime = _rtime;
	this.isActive = false;
	this.fullname = _name;
	this.lastjson = null;
	this.lastupdate = null;
	if( _gpars != null)
		this.fullname += '-' + _gpars;
	this.word = _word;
}

//changes a parametere
function M_changeParam( name, val )
{
	for( i=0; i<this.pars.length; i++)
		if(this.pars[i].name == name)
		{
			this.pars[i].val = val;
			return true;
		}
	return false;
}
MODULE.prototype.changeParam = M_changeParam;

function M_setContent( data )
{
	if(data.area == null)
		data.area = this.fullname;

	if( data != null )
	{	this.lastjson = data;
		node = dojo.byId( data.area );
		if( node==null )
			return false;

		//if we received a string (proabably from an error message)
		if( dojo.lang.isString( data ) )
		{
			//just dump the string
			node.innerHTML = data ;
		}
		//we received an json object
		else
		{
			//if something has changed
			if(data.change == true)
			{
				if( data.mode == null )
					data.mode = HTML_REPLACE;

				switch(data.mode)
				{
					case HTML_APP_HEAD:
						node.innerHTML = data.html + node.innerHTML;
						break;

					case HTML_APP_TAIL:
						node.innerHTML = node.innerHTML + data.html;
						break;

					//case HTML_REPLACE:
					default:
						node.innerHTML = data.html;
				}
			}
			//else = nothing has changed don't update anything
		}

		//if reloadpage flag vas set to true, reloads the page

		if( data.script != null )
			eval( data.script );

		if( data.reloadpage )
			location.reload( true );

		return true;
	}
	else
	{
		return false;
	}
}
MODULE.prototype.setContent = M_setContent;

/**************************************************************************/

//attaches the css stylesheet of this module to the dom tree
function M_getCSS( )
{
	/*headNode = dojo.byId("head");
	newNode = dojo.doc().createElement("link");
	newNode.setAttribute("type", "text/css" );
	newNode.setAttribute("rel", "stylesheet" );
	newNode.setAttribute("href", this.css );
	dojo.dom.prependChild(newNode,headNode);
	*/
	if( dojo.html.insertCssFile( this.css, document, true ) )
		return true;
	else
		return false;

}
MODULE.prototype.getCSS = M_getCSS;

/**************************************************************************/

//attaches the css stylesheet of this module to the dom tree
function M_renderPreloader( lastHeight )
{
	var st = "";
	if(lastHeight!=null)
	{
		st = ' style="height:'+lastHeight+'px;"';
		//alert(st);
	}
	this.setContent({change:true,html:'<div class="preloader"'+st+'>&nbsp;</div>',area:null,mode:null,reloadpage:null,script:null});
}
MODULE.prototype.renderPreloader = M_renderPreloader;

/**************************************************************************/

//destructs the module
function M_destroy()
{
	//destroys the events inside the modules so IE won't leak memory
	node = dojo.byId( this.fullname );
	if( node == null )
		return false;

	//purge( node ); ///TODO: NEED TO FIX. THIS IS CAUSING SOMETIMES ERRORS. DON'T KNOW WHY

	//dojo.lfx.html.wipeOut( node , 800, null, null ).play();////////////////////////////////////////////////////////

	//destroys the module div
	dojo.dom.destroyNode(node);



	//deactivates the module (if is active, otherwise nothing to do)
	if( this.isActive )
		if( this.deactivate( ) )
			return true;
		else
			return false;

	return true;
}
MODULE.prototype.destroy = M_destroy;

/**************************************************************************/

//activates a ghost module
function M_activate( lastHeight )
{
	if (MM_ACTIVE_MODULES_CONTINUE_INCREMENT) MM_ACTIVE_MODULES++;
	//if module is already active  nothing to do
	if( this.isActive )
		return false;

	//sets that this is active
	this.isActive = true;

	//loading stylesheet for this module
	if(this.css!=null)
		this.getCSS();

	//if this module is refreshing then adds a new refresher
	if(this.isRefreshing)
		REFM.addRefresher( this.fullname, this.rtime );

	//render the preloared

	// TODO: make a way so this preloader won't remove the whole module
	//this.renderPreloader();

	//renders the module
	if( this.render( EVENT_PAGELOAD, null, lastHeight ) )
		return true;
	else
		return false;
}
MODULE.prototype.activate = M_activate;

/**************************************************************************/

//deactivates a module and makes it ghost
function M_deactivate()
{
	//if this is already deactivated returns
	if( !this.isActive )
		return false;



	//destroys the adiacent refresher
	if( this.isActive && this.isRefreshing )
		REFM.removeRefresher( this.fullname );

	//margking this as a deactivated module
	this.isActive = false;

	return true;
}
MODULE.prototype.deactivate = M_deactivate;

/**************************************************************************/

//refreshes the module with it's construct parameters
function M_refresh( )
{
	this.render( EVENT_REFRESH, null );
}
MODULE.prototype.refresh = M_refresh;

//refreshes the module and passes the provided parameters (used
function M_request( p )
{
	var n = dojo.byId( this.fullname );
	var bb = dojo.html.getContentBox( n );
	lastHeight = bb.height-12;

	if( p == null )
		this.render(EVENT_REFRESH, null, lastHeight);
	else
		this.render(EVENT_INPUT, p, lastHeight);
}
MODULE.prototype.request = M_request;


//refreshes the module and passes the provided parameters (used
function M_requestPOST( p )
{
	var n = dojo.byId( this.fullname );
	var bb = dojo.html.getContentBox( n );
	lastHeight = bb.height-12;

	if( p == null )
		this.renderPOST(EVENT_REFRESH, null, lastHeight);
	else
		this.renderPOST(EVENT_INPUT, p, lastHeight);
}
MODULE.prototype.requestPOST = M_requestPOST;


//sets a variable (parameter) for this module
function M_setVar( index, value )
{
	this.pars[index] = value;
}
MODULE.prototype.setVar = M_setVar;

/////////////////////////////

function M_serializeParameters( pa )
{
	params = "";
	if(pa == null)
		p = this.pars;
	else
		p = pa;

	var sp = new Object();

	if(p != null)
	{
		//evaluates js objects in parameters
		for(i=0; i<p.length; i++)
		{
			if(p[i].isjs)
				p[i].val = eval( p[i].val ).substring(0,512);

			//clears unnecesary data. leaves only name and value
			if(p[i].name.indexOf('_')!=0)
				sp[p[i].name] = p[i].val;
		}

		return dojo.json.serialize(sp);
	}

	return params;
}
MODULE.prototype.serializeParameters = M_serializeParameters;

////////////////
function M_serializeParametersPOST( pa )
{
	params = "";
	if(pa == null)
		p = this.pars;
	else
		p = pa;

	var sp = new Object();

	if(p != null)
	{
		//evaluates js objects in parameters
		for(i=0; i<p.length; i++)
		{
			if(p[i].isjs)
				p[i].val = eval( p[i].val ).substring(0,65000);

			//clears unnecesary data. leaves only name and value
			if(p[i].name.indexOf('_')!=0)
				sp[p[i].name] = p[i].val;
		}

		return dojo.json.serialize(sp);
	}

	return params;
}
MODULE.prototype.serializeParametersPOST = M_serializeParametersPOST;

//function that checks whether this request requires authentification
function M_requireConfirmation( p )
{
	if(p != null)
	{
		msg = "#";

		for(i=0; i<p.length; i++)
			if(p[i].name == "_requireconfirm")
			{
				msg = p[i].val;
				break;
			}
		if(msg!="#")
			return confirm( msg );
		else
			return true;
	}
	else
		return true;
}
MODULE.prototype.requireConfirmation = M_requireConfirmation;


//function that checks whether this request requires authentification
function M_checkFlood( p )
{
	if(p != null)
	{
		msg = "#";
		val = null;

		for(i=0; i<p.length; i++)
			if(p[i].name == "_flood_interval")
			{
				val = p[i].val;
			}
			else if(p[i].name == "_flood_message")
			{
				msg = p[i].val;
			}

		if(val!=null)
		{
			var thisdate = new Date();
			if( thisdate.getTime() - this.lastupdate < parseInt(val)*1000 )
			{
				alert(msg);
				return true;
			}
		}
		else
		{
			return false;
		}
	}
	else
		return false;
}
MODULE.prototype.checkFlood = M_checkFlood;

//renders the module
function M_render( event , p, lastHeight )
{
	//check for name, event and parameter integrity is done on server side
	//constructs a list of parameters

	//if this action requires confirmation
	if( this.requireConfirmation( p ) == false )
		return false;

	//if this module has a check for flood
	if( event == EVENT_INPUT )
		if( this.checkFlood( p ) == true )
			return false;

	params = this.serializeParameters( p );

	//marks the second when this module was updated (refreshes are excluded)
	if(event != EVENT_REFRESH)
	{
		var thisdate = new Date();
		this.lastupdate = thisdate.getTime();
	}

	//renders preloader (not for refresh tho. it would be v annoying for chat for example)
	if(event != EVENT_REFRESH)
		this.renderPreloader( lastHeight );

	//makes an asyncronus call for the content of the module
	dojo.io.bind({
		pivot: this,
		url: "/fetchmodule.php", //data provider for modules
		method: "GET", //request is get
		transport: "XMLHTTPTransport", //method od transport is the xhttp object
		mimetype: "application/json", //receives data as json object
		timeoutSeconds: 30, //this will timeout in 30 sec

		content: {
			//data in revers order because get parameters will be constructed in reverse
			get: MM.GET, //pages get variables
			params: params, //sends the parameters for the module
			fname: this.fullname, //sends the fullname (with index id)
			event: event, //sends the generator event
			name: this.name //sends the module name
		},

		//what happens when the request for module content times out (30 sec)
		timeout: function(type, data, evt){
			this.pivot.setContent('<div class="warning">Server did not responded for 30 seconds.</div>');
		},

		//what happens when error occurs
		error: function(type, data, evt){
			//alert(.url);
			this.pivot.setContent('<div class="warning">The following error occured: <em>' + data + '</em></div>');
		},

		//handling of received data
		load: function(type, data, evt){
			MM_LOADED_MODULES++;

			this.pivot.setContent( data );

			/*
			if (MM_LOADED_MODULES==MM_ACTIVE_MODULES)
				{
				dojo.io.bind(
					{
					url: "/timelogger.php?m=1&i="+TIMELOGGER_ID+"&modules="+MM_LOADED_MODULES+"&browser="+(navigator.userAgent || navigator.appVersion)+"&resolution="+screen.width+" x "+screen.height+"&colordepth="+screen.colorDepth,
					load: function(type, data, evt){},
					error: function(type, error) {},
					content: {},
					method: "post",
					mimetype: "text/plain"
					});
				}
			*/

			//dojo.lfx.html.wipeIn( dojo.byId(this.content.fname) , 500 ).play();//////////////////////////////////////////////////////
		}
	});

	return true;
}
MODULE.prototype.render = M_render;


/**************************************************************************/

//renders the module
function M_renderPOST( event , p, lastHeight )
{
	//check for name, event and parameter integrity is done on server side
	//constructs a list of parameters

	//if this action requires confirmation
	if( this.requireConfirmation( p ) == false )
		return false;

	//if this module has a check for flood
	if( event == EVENT_INPUT )
		if( this.checkFlood( p ) == true )
			return false;

	params = this.serializeParametersPOST( p );

	//marks the second when this module was updated (refreshes are excluded)
	if(event != EVENT_REFRESH)
	{
		var thisdate = new Date();
		this.lastupdate = thisdate.getTime();
	}

	//renders preloader (not for refresh tho. it would be v annoying for chat for example)
	if(event != EVENT_REFRESH)
		this.renderPreloader( lastHeight );

	//makes an asyncronus call for the content of the module
	dojo.io.bind({
		pivot: this,
		url: "/fetchmodule_post.php", //data provider for modules
		method: "POST", //request is get
		transport: "XMLHTTPTransport", //method od transport is the xhttp object
		mimetype: "application/json", //receives data as json object
		timeoutSeconds: 30, //this will timeout in 30 sec

		content: {
			//data in revers order because get parameters will be constructed in reverse
			get: MM.GET, //pages get variables
			params: params, //sends the parameters for the module
			fname: this.fullname, //sends the fullname (with index id)
			event: event, //sends the generator event
			name: this.name //sends the module name
		},

		//what happens when the request for module content times out (30 sec)
		timeout: function(type, data, evt){
			this.pivot.setContent('<div class="warning">Server did not responded for 30 seconds.</div>');
		},

		//what happens when error occurs
		error: function(type, data, evt){
			//alert(.url);
			this.pivot.setContent('<div class="warning">The following error occured: <em>' + data + '</em></div>');
		},

		//handling of received data
		load: function(type, data, evt){
			this.pivot.setContent( data );
			//dojo.lfx.html.wipeIn( dojo.byId(this.content.fname) , 500 ).play();//////////////////////////////////////////////////////
		}
	});

	return true;
}
MODULE.prototype.renderPOST = M_renderPOST;


/**************************************************************************/
/**************************************************************************/


//the group wrapper. creates a new group
function GROUP( _id, _isTabbed, _column, _isSticky, _activenr )
{
	this.id = _id;
	this.isTabbed = _isTabbed;
	this.modules =  new Array();
	this.active = null;
	this.lastchange = (new Date()).getTime();
	this.isSticky = _isSticky;
	this.activenr = _activenr;
}

/**************************************************************************/
/**************************************************************************/
//object used to change scope of event calling. uses closures so carefull at memory leaks
function tabHandler(_gid, _module, _gparams)
{
	this.gid = _gid;
	this.module = _module;
	this.gparams = _gparams;
	this.fullname = _module;
	if( _gparams!=null )
		this.fullname += '-'+_gparams;
}

/**************************************************************************/

function tabHandlerCall()
{
	if( MM.groups[ this.gid ].active == this.fullname )
		return false;

	//don't allow changing of module if at least 1 second has passed
	//since the last module change in this group
	newt = (new Date()).getTime();
	if( newt - MM.groups[ this.gid ].lastcall < 1000)
		return false;
	MM.groups[ this.gid ].lastcall = newt;

	//find tabs that need to be changed
	ctab = "tab-"+this.fullname;
	atab = "tab-"+MM.groups[ this.gid ].active;

	if(this.params != null)
		ctab += '-'+this.params;

	n1 = dojo.byId(ctab);
	n2 = dojo.byId(atab);

	if(n1==null || n2== null)
		return false;

	//recoloring the tabs to show wich one is active
	dojo.html.setClass( n1 , "active");
	dojo.html.removeClass( n2 , "active", false );

	//activates the requested module
	MM.groups[ this.gid ].activateModule( this.fullname );

	return true;
}

tabHandler.prototype.call = tabHandlerCall;
/**************************************************************************/
/**************************************************************************/

//adds ands a new module and attaches events that need to be attached
function G_addModule(_name, /*array*/_pars, /*string*/_gpars, _css, /*bool*/_isRefreshing,
					 /*int*/_rtime, /*bool*/_active, _word )
{
	//construct fullname
	fullname = _name;
	if( _gpars != null )
		fullname += '-' + _gpars;

	//if the specified module already exists nothing to do
	if( typeof this.modules[fullname] != "undefined" )
		return;

	//created a new module
	this.modules[ fullname ] = new MODULE( _name, _pars, _gpars, _css, _isRefreshing, _rtime, _active, _word );
	MM.fms [ fullname ] = this.id;
	MM.aim++;

	//if this module is tabbed attaches events to the link representing this module
	if( this.isTabbed )
	{
		//construnts linkname (name of link)
		linkname = "taba-"+_name;
		if( _gpars != null )
			linkname += '-' + _gpars;

		//creating handler by closures
		th = new tabHandler( this.id, _name, _gpars );

		//getting dom elements
		node = dojo.byId( linkname );

		//if no such node exists
		if( node == null )
			return false;

		//attaching event
		dojo.event.connect( node , "onclick", th, "call" );
	}

	//if this is the active module activates the module
	if( _active )
		if( this.activateModule( fullname ) )
			return true;
		else
			return false;
	else
		return true;
}
GROUP.prototype.addModule = G_addModule;

/**************************************************************************/

//removes a client and purges the memory that needs to be purged
/*function G_removeModule( _name )
{
	//if the specified module does not exist nothing to do
	if( typeof this.modules[_name] == "undefined" )
		return;

	//purges is done by module itself when this is needed

	//calls the modules self destruct function
	this.modules[ _name ].destroy( );
	//erases from the module vector
	this.modules[ _name ] = null;
	//if this was the only module destroys the group
	//BUG? this ever empties or just keeps the records as null?
	if( this.modules.length == 0 )
		this.destroy();
}
GROUP.prototype.removeModule = G_removeModule;*/

/**************************************************************************/

//sets one of the modules active
function G_activateModule( _fullname )
{

	//if the specified module does not exist nothing to do
	if( typeof this.modules[ _fullname ] == "undefined" )
		return false;

	//if this module is already active nothing to do
	if(this.active == _fullname)
		return false;


	var lastHeight = null;
	//deactivates the current module
	if( this.active != null)
	{
		var n = dojo.byId( this.modules[ this.active].fullname );
		var bb = dojo.html.getContentBox( n );
		lastHeight = bb.height-12;

		if( !this.deactivateModule() )
			return false; //should return false but tries to overide
	}

	//remembers the current module as active
	this.active = _fullname;

	//active module should be the last element in group
	node = dojo.byId(this.id);
	if(node==null)
		return false;

	//creating div with the id of the module and placing it at the tail of the group wrapper
	newNode = dojo.doc().createElement("div");
	newNode.setAttribute("id", _fullname );
	newNode.setAttribute("class", "module" );
	//newNode.setAttribute("class", this.modules[ _fullname ].name );
	lastNode = dojo.dom.lastElement( node );

	if(lastNode != null)
		dojo.dom.insertAfter(newNode,lastNode);
	else
		dojo.dom.prependChild(newNode,node);

	//calls the module activation mechanism
	this.modules[ _fullname ].activate( lastHeight );

	return true;
}
GROUP.prototype.activateModule = G_activateModule;

/**************************************************************************/

//deactivates the active module
function G_deactivateModule( )
{
	//if no module is active return
	if(this.active == null)
		return false;

	//calls modules self destruction mechanism
	if( !this.modules[ this.active ].destroy( ) )
		return false;

	//marks that there is no active node no more
	this.active = null;

	return true;
}
GROUP.prototype.deactivateModule = G_deactivateModule;

/**************************************************************************/

//destroys the group
function G_destroy()
{
	//geting groups node from dom
	var myNode = dojo.byId( this.id );
	if(myNode==null)
		return false;

	//detaching any events from it
	  ////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//purging all event references in case the are still any
	//purge( myNode );
	//removes the node from dom

	this.modules[ this.active ].deactivate();

	if( !dojo.dom.destroyNode( myNode.parentNode ) )
		return false;
	//remove adiacent spacer
	  /////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	return true;
}
GROUP.prototype.destroy = G_destroy;



/**************************************************************************/
/**************************************************************************/
/**************************************************************************/


//MODULE MANAGER (ACTUALLY A GROUP MANAGER)
function MODULE_MANAGER( )
{
	this.groups = new Array();
	this.fms = new Array(); //fast module search - for each module name saves its the group id
	this.last = null; //saves refference to last added group
	this.GET = null; //page, get variables
	this.aig = 0;
	this.aim = 0;
	this.page = null;
}

/**************************************************************************/

//adds ands a new group
function MM_addColumn( _column )
{
	//gets the node for this column
	node = dojo.byId( _column );
	if( node==null )
		return false;

	//makes this column a drop target
	new ModDropTarget( node, ["*"]);

	return true;
}

MODULE_MANAGER.prototype.addColumn = MM_addColumn;


function closingHandler( _gid )
{
	this.gid = _gid;
}

function chcall()
{	//alert(MM.groups[ this.gid ].isSticky);
	if( !MM.groups[ this.gid ].isSticky )
		MM.removeGroup( this.gid );
}
closingHandler.prototype.call = chcall;

/**************************************************************************/

//adds ands a new group
function MM_addGroup( _gid , _isTabbed , _column, _isSticky, _activenr)
{
	//if the specified group already exist nothing to do
	if( typeof this.groups[_gid] != "undefined" )
		return false;

	//gets the node for this group
	node = dojo.byId( _gid );
	if( node==null )
		return false;

	//adds the group to the group list
	this.groups[ _gid ] =  new GROUP( _gid, _isTabbed, _column, _isSticky, _activenr );
	this.aig++;

	//makes a shortcut to the last added groups
	this.last = this.groups[ _gid ];

	//makes this div a drag object
	drs = dojo.html.getElementsByClass( "tabs",node );
	if(drs.length == 0)
		return false;

	ds = new ModDragSource( drs[0] , "*");


	//adds the exit action
	var nv = dojo.byId("exitb-"+_gid);
	if(nv == null)
		return true;
	//alert("exitb-"+_gid+" = "+nv);

	var th = new closingHandler(_gid);
	dojo.event.connect( nv , "onclick", th, "call" );

	return true;
}
MODULE_MANAGER.prototype.addGroup = MM_addGroup;

/**************************************************************************/

//removes a group
function MM_removeGroup( _gid )
{
	//if the specified group does not exist nothing to do
	if( typeof this.groups[_gid] == "undefined" )
		return;

	var newgroups = new Array();
	for (var g in this.groups)
	{
	  if (g != _gid)
	  	newgroups[g] = this.groups[g];
	}

	var newfms = new Array();
	for (var m in this.fms)
	{
	  if (this.fms[m] != _gid)
	  	newfms[m] = this.fms[m];
	}

	this.groups[ _gid ].destroy( );

	this.groups = newgroups;
	this.fms = newfms;
}
MODULE_MANAGER.prototype.removeGroup = MM_removeGroup;

/**************************************************************************/
//gets the group in wich the specified module is found
function MM_getGroup( _fullname )
{
	return this.fms[ _fullname ];
}
MODULE_MANAGER.prototype.getGroup = MM_getGroup;

/**************************************************************************/
//makes a request to fetch a module with the EVENT_INPUT generator and some parameters
function MM_userRequest( _fullname, _pars )
{
	//locates the module using the Fast Module Search array and calls its request method
	this.groups[ this.getGroup( _fullname ) ].modules[ _fullname ].request( _pars );
	//alert(this.groups[ this.getGroup( _fullname ) ]);
}
MODULE_MANAGER.prototype.userRequest = MM_userRequest;

/**************************************************************************/
//makes a request to fetch a module with the EVENT_INPUT generator and some parameters
function MM_userRequestPOST( _fullname, _pars )
{
	//locates the module using the Fast Module Search array and calls its request method
	this.groups[ this.getGroup( _fullname ) ].modules[ _fullname ].requestPOST( _pars );
	//alert(this.groups[ this.getGroup( _fullname ) ]);
}
MODULE_MANAGER.prototype.userRequestPOST = MM_userRequestPOST;

/**************************************************************************/
//makes a request to fetch a module with the EVENT_INPUT generator and some parameters
function MM_userRefresh( _fullname  )
{
	//locates the module using the Fast Module Search array and calls its request method
	this.groups[ this.getGroup( _fullname ) ].modules[ _fullname ].refresh( );
	//alert(this.groups[ this.getGroup( _fullname ) ]);
}
MODULE_MANAGER.prototype.userRefresh = MM_userRefresh;

/**************************************************************************/
//makes a request to fetch a module with the EVENT_INPUT generator and some parameters
function MM_setModuleVar( _fullname , _index, _varvalue )
{
	//locates the module using the Fast Module Search array and calls its request method
	this.groups[ this.getGroup( _fullname ) ].modules[ _fullname ].setVar( _index, _varvalue );
	//alert(this.groups[ this.getGroup( _fullname ) ]);
}
MODULE_MANAGER.prototype.setModuleVar = MM_setModuleVar;

/**************************************************************************/
//activates a module (if is already added to a group) or attaches it to a group and activates it
function MM_isOnStage( _name )
{
	//searches to see if this module is already on the stage
	for( key in this.fms )
		if( dojo.string.startsWith( key, _name ) )
			return key;
	return null;
}
MODULE_MANAGER.prototype.isOnStage = MM_isOnStage;

/**************************************************************************/
//activates a module (if is already added to a group) or attaches it to a group and activates it
function MM_activateModule( _name )
{
	module = _name;
	if( dojo.string.startsWith( module, "module:", true) )
		module = module.substr(7);

	mo = this.isOnStage( module );
	if(mo == null)
	{
		MM.getNewContext(module);

		//TODO: scroll to the new module
		//alert( "This module is not implemented!" ); //TODO attach to stage the module
		return;
	}

	ctab = "tab-"+mo;
	atab = "tab-"+this.groups[ this.fms[ mo ] ].active;

	if( ctab == atab )
	{
		//scroll to this module
		goinpage( this.groups[ this.fms[ mo ] ].id );
		return;
	}

	n1 = dojo.byId(ctab);
	n2 = dojo.byId(atab);
	if(n1==null || n2== null)
		return false;

	//recoloring the tabs to show wich one is active
	dojo.html.setClass( n1 , "active");
	dojo.html.removeClass( n2 , "active", false );

	this.groups[ this.getGroup( mo ) ].activateModule( mo );

	//scroll page to group with the module that was activated
	goinpage( this.groups[ this.fms[ mo ] ].id );
}
MODULE_MANAGER.prototype.activateModule = MM_activateModule;

/**************************************************************************/
//fetches context for a module
function MM_getNewContext( _name )
{
	var nrm = this.aim;
	var nrg = this.aig;

	//makes an asyncronus call for the content of the module
	dojo.io.bind({
		url: "/fetchmodulecontext.php", //data provider for modules
		method: "GET", //request is get
		transport: "XMLHTTPTransport", //method od transport is the xhttp object
		mimetype: "application/json", //receives data as json object
		timeoutSeconds: 5, //this will timeout in 30 sec

		content: {
			name: _name,
			nrmods: nrm,
			nrgroups: nrg
		},

		//what happens when the request for module content times out (30 sec)
		timeout: function(type, data, evt){
			;
		},

		//what happens when error occurs
		error: function(type, data, evt){
			//alert(.url);
			;
		},

		//handling of received data
		load: function(type, data, evt){
			MM.addNewGroupModuleToStage( data, this.content.name );
		}
	});
}
MODULE_MANAGER.prototype.getNewContext = MM_getNewContext;

/**************************************************************************/
//attaches the new module to stage
function MM_addNewGroupModuleToStage( data, mname )
{
	this.aig++;
	var col = dojo.byId(data.column);
	var newcontainer = document.createElement("div");
	col.appendChild(newcontainer);
	newcontainer.innerHTML += data.context;
	eval(data.addjs);
	goinpage(data.gname);
}
MODULE_MANAGER.prototype.addNewGroupModuleToStage = MM_addNewGroupModuleToStage;

function GroupTracker( _x, _y, _t, _a, _s )
{
	this.x = _x;
	this.y = _y;
	this.tabbed = _t;
	this.active = _a;
	this.sticky = _s;
	this.modules = new Array();
	this.params = new Array();
	this.words = new Array();
}

/**************************************************************************/
//saves the layout
function MM_saveLayout()
{
	var grps = new Array();
	var nr = 0;
	var uc = dojo.byId( "usercontent" );

	for(var i in this.groups)
	{
		var gn = dojo.byId( this.groups[ i ].id );
		if( !dojo.dom.isDescendantOf(gn, uc) )
			continue; //only saves from user content

		var ap = dojo.html.getAbsolutePosition( gn, true );
		grps[ nr ] = new GroupTracker( ap.x, ap.y, this.groups[ i ].isTabbed,  this.groups[ i ].activenr, this.groups[ i ].isSticky);

		for( var j in this.groups[ i ].modules )
		{
			grps[ nr ].modules[ grps[ nr ].modules.length ] = this.groups[i].modules[j].name;
			grps[ nr ].params[ grps[ nr ].params.length ] = this.groups[i].modules[j].pars;
			grps[ nr ].words[ grps[ nr ].words.length ] = this.groups[i].modules[j].word;
		}

		nr++;
	}


	pag = this.page;


	dojo.io.bind({
		url: "/savelayout.php", //data provider for modules
		method: "POST", //request is get
		transport: "XMLHTTPTransport", //method od transport is the xhttp object
		mimetype: "application/json", //receives data as json object
		timeoutSeconds: 5, //this will timeout in 30 sec

		content: {
			page: pag,
			layout: dojo.json.serialize(grps)
		},

		//what happens when the request for module content times out (30 sec)
		timeout: function(type, data, evt){
			;
		},

		//what happens when error occurs
		error: function(type, data, evt){
			;
		},

		//handling of received data
		load: function(type, data, evt){
			alert("Saved!"); //TODO: language dependant
		}
	});
	//alert("A");
}
MODULE_MANAGER.prototype.saveLayout = MM_saveLayout;

//saves the layout
function MM_resetLayout()
{
	dojo.io.bind({
		url: "/resetlayout.php", //data provider for modules
		method: "GET", //request is get
		transport: "XMLHTTPTransport", //method od transport is the xhttp object
		mimetype: "application/json", //receives data as json object
		timeoutSeconds: 5, //this will timeout in 30 sec

		content: {
			reset:true
		},

		//what happens when the request for module content times out (30 sec)
		timeout: function(type, data, evt){
			;
		},

		//what happens when error occurs
		error: function(type, data, evt){
			;
		},

		//handling of received data
		load: function(type, data, evt){
			location.reload( true );
		}
	});
}
MODULE_MANAGER.prototype.resetLayout = MM_resetLayout;

/***********************************************************************************/
//get list of modules with a given name
function MM_getModulesByName( sname )
{
	var mods = new Array();
	var k = 0;

	var i;
	for( i in this.groups )
	{

		var j;
		for( j in this.groups[i].modules )
		{
			if( this.groups[i].modules[j].name == sname )
			{
				mods[ k ] = this.groups[i].modules[j].fullname;
				k++;
			}
		}
	}

	if(k == 0)
		return null;
	else
		return mods;
}
MODULE_MANAGER.prototype.getModulesByName = MM_getModulesByName;

/***********************************************************************************/
//get the modules that are city dependant
function MM_getCityDependantModules( )
{
	var list = new Array('weather','banners','bannerss','news','htmlpage');
	var nrl = list.length;
	var mods = new Array();
	var k = 0;

	for( var i=0; i<nrl; i++)
	{
		var mo = this.getModulesByName( list[i] );
		if( mo == null )
			continue;

		var nrm = mo.length;
		for( var j=0; j<nrm; j++ )
		{
			mods[ k ]=mo[j];
			k++;
		}
	}

	if(k == 0)
		return null;
	else
		return mods;
}
MODULE_MANAGER.prototype.getCityDependantModules = MM_getCityDependantModules;

/***********************************************************************************/
//refresh city dependant modules
function MM_refreshCityDependantModules( )
{
	var mods = this.getCityDependantModules();
	if(mods == null)
		return;
	var nrm = mods.length;

	for(var i=0; i<nrm; i++)
	{
		var gr = this.groups[ this.fms[ mods[i] ] ];
		var am = gr.active;

		if(mods[i] == am)
		{
			gr.modules[am].refresh();
		}
	}
}
MODULE_MANAGER.prototype.refreshCityDependantModules = MM_refreshCityDependantModules;