/*
 *  Grammar of metalevel language for model creation
 *
 *  (C) 2004 - 2011 Frantisek Zboril jr.
 *  Faculty of Information Technology
 *  Brno University of Technology
 *  zborilf@fit.vutbr.cz
 *  http://www.fit.vutbr.cz/~zborilf
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation. This program is distributed in the hope
 *  that it will be useful, but WITHOUT ANY WARRANTY; without even the
 *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details.
 */


grammar tMassML;

tokens{
	ID;
	FILE;
}

@header{
	package jTMass.core.jLoaders.jTMassML;
	import jTMass.TMass;
	import jTMass.core.jLoaders.TModelLoader;
	import jTMass.core.jALLL.jTObjects.*;
	import jTMass.core.jAMass.TAgent;
	import jTMass.core.jTMassModel.TModel;
	import jTMass.core.jTMassPlatform.TPlatform;
	import java.util.LinkedList;
	import java.util.TreeSet;	

}

@lexer::header{
	package jTMass.core.jLoaders.jTMassML;
}

tMassML [TModelLoader loader] returns[LinkedList<TAgent> agentPopulation]

@init{
	TMass._Terminal.printlnSystemInfo("==================================================================");
	TMass._Terminal.printlnSystemInfo("T-Mass Meta Language loader. The system model will be created now.");
	TMass._Terminal.printlnSystemInfo("==================================================================");
}
	:
	(model_name [loader] (('sources' '{' element_sources [loader] '}'';')|('elements' '{' element_specs [loader]'}'';') |
		('relations' '{' relation_specs [loader] '}' ';'))+)
	;

model_name [TModelLoader loader]
	:	( 'model:' ID  ';'  
		{
			loader.setModelName($ID.text);
			TMass._Terminal.printlnSystemInfo("Model name:"+$ID.text);
		}
		)?
	;
	
element_sources [TModelLoader loader]   // agent, platform, element, com_channel
	: ('agents' ':' agent_sources [loader]| 'platforms' ':' platform_sources [loader] | 'environments' ':' environments [loader])+
	{
	
	}
	// interaction je element ktery navrch jiz pri konstrukci spoji mnozinu elementu (podsystem)?
	;
	
agent_sources [TModelLoader loader]

	:	( 'file'':'  FILE ID';'
			{
			 loader.loadAgent($ID.text,$FILE.text);
			 /*agent=null;*/})*;

platform_sources [TModelLoader loader]
	:
	( 'file'':'  FILE ';'
			{
			 loader.loadPlatform($FILE.text);
			 /*agent=null;*/}
			 |
	  'platform' ':' '{' (load_platform [loader]) '}'';'
	  )*
	;			 

// ================ PLATFORM SPECS PARSER ====================

integer returns [Integer result]
	: NUMBER
	{result= Integer.parseInt($NUMBER.getText());}
	;

item	returns [TAtom atom]
	:
	 ID  {atom= new TAtom($ID.getText());}
	 | number=integer {atom= new TAtom(number);}
	;

generalListItem returns [TObject result]
	: 
	iResult=item {result=iResult;}| gResult=generalList {result=gResult;}
	;

generalList returns [TList list]
	: 
	{
	TMass._Terminal.printlnDebug("General list: ");
	list=new TList(TConstants._GeneralList);}
	'(' mItem=generalListItem 
	{list.add(mItem);}
	(',' mItem=generalListItem
	{list.add(mItem);} 
	)* ')'
	;

load_platform [TModelLoader loader]
	:
	{int noESlotsI=1; int noASlotsI=1;}
	'name'':'  name=ID ';'
	('slots' ':' 'environments' '=' noESlots=NUMBER ',' 'agents' '=' noASlots=NUMBER ';'
	{
		if((new Integer($noESlots.text)<1)||(new Integer($noESlots.text)>TPlatform._MaxSlots)) {
			// TMass._Terminal ... reportError ...
			noESlotsI=1;
			}
			else
			noESlotsI=new Integer($noESlots.text);
		if((new Integer($noASlots.text)<1)||(new Integer($noASlots.text)>TPlatform._MaxSlots)) {
			// TMass._Terminal .... 
			noASlotsI=1;
			}
			else
			noASlotsI=new Integer($noASlots.text);
			TMass._Terminal.printlnSystemInfo("Platform source: name="+$name.text+", environment slots="+$noESlots.text+", agent slots="+$noASlots.text);
		// chtelo by to mit moznost importovat cele adresare!!
	}	)?

	{
	TPlatform platform;platform=new TPlatform($name.text, noESlotsI, noASlotsI, true);
	loader.addToPlatformSet(platform);
	}
	
	('services' ':' ('[' svcName=ID svcClass=ID ']'
	{TMass._Terminal.printlnSystemInfo("Adding service '"+$svcName.text+"' of class "+$svcClass.text);
		loader.addServiceToPlatform(platform,$svcName.text,$svcClass.text);
	}
	)+ ';')?
	
	('variables' ':' ( varName=ID
	{TObject value=null;TMass._Terminal.printlnSystemInfo("Adding variable "+$varName.text);}  
	('=' varValue=generalList)?
	
	{
	loader.addVariableToPlatform(platform, $varName.text, varValue);
	}
	)+)?
	;
	

// ================== ELEMENT SPECS ============================
	
element_specs [TModelLoader loader]
	:('agents' ':' agent_specs [loader]| 'platforms' ':' platform_specs [loader]| 'environments' ':' environments [loader])*
	;	
	
environments [TModelLoader loader]
	: (name=ID '(' multicast [loader,$name.text] ';')*
	;

multicast [TModelLoader loader, String name]
	: 'multicast' ')'
	{
		loader.addMulticastToModel(name);
	}
	;
			 			 
agent_specs [TModelLoader loader]
	: ({ts=new TreeSet<Integer>(); ts.add(-1);}
	 name=ID '(' source=ID ')' (ts= params)?';'
	 	{
	 	for(Integer i:ts){
	  		loader.addAgentToModel($name.text,$source.text,i);
	 		}
	 	}
	 )+
	;

		 
platform_specs [TModelLoader loader]
	:({ts=new TreeSet<Integer>(); ts.add(-1);}
	   name=ID '(' source=ID ')' (ts= params)?';'
	 	{
	 	for(Integer i:ts){
	  		loader.addPlatformToModel($name.text,$source.text,i);
	 	}
	  }
	 )+
	;

relation_specs [TModelLoader loader]
	: 
	({elpm=null;}
	elm=ID (elpm=params)? (relation_mul [loader,$elm.text,elpm]| relation_oto[loader,$elm.text,elpm]| relation_btb[loader,$elm.text,elpm]))+
	;

relation_mul [TModelLoader loader, String oelm, TreeSet<Integer> oelpm]
	: {ielpm=null;}
	'#' (ielm=ID (ielpm=params)? ';' )
	{
		loader.relationsMultiply(oelm,oelpm,$ielm.text,ielpm);
		loader.relationsMultiply($ielm.text,ielpm, oelm,oelpm);

	}
	;


relation_oto [TModelLoader loader, String oelm, TreeSet<Integer> oelpm]
	: {ielpm=null;}
	'->' (ielm=ID (ielpm=params)? ';' )
	{
		loader.relationsOneToOne(oelm,oelpm,$ielm.text,ielpm);
	}
	;	

relation_btb [TModelLoader loader, String oelm, TreeSet<Integer> oelpm]
	: {ielpm=null;}
	'=' (ielm=ID (ielpm=params)? ';' )
	{
		loader.relationsOneToOne(oelm,oelpm,$ielm.text,ielpm);
		loader.relationsOneToOne($ielm.text,ielpm,oelm,oelpm);
	}
	;	

	
params returns [TreeSet<Integer> ts]
	// parametry u poli, tj bud cislo, pak 1..cislo, interval, nebo vycet
	// vysledkem by mel byt seznam indexu (?)
	:  { ts=new TreeSet();}
	     '[' intervals[ts] (',' intervals[ts])* ']'
		;  
	
intervals [TreeSet<Integer> ts]
	: n1=NUMBER  (':' n2=NUMBER)? 
	{ if ($n2!=null)
		{
		for(int i=new Integer($n1.text);i<=new Integer($n2.text);i++)
			ts.add(new Integer(i));
		}
		else
			ts.add(new Integer($n1.text));
		}
	;
		
	
	
//========================= PLATFORM LOADER ===========================//

	
/*		
model_elements
	:
		(element_spec (nig=no_gates ',' nog=no_gates)?)*	
	;
	
element_spec
	:
		(('agent:' agent_spec)|('platform:' platform_spec)|('environment:' environment_spec)) 
	;
*/
//no_gates	: Number;


//FILE	: (('\u005c'|'a'..'z'|'A'..'Z'|'0'..'9'|'_'|':')+ '.' ('a'..'z'|'A'..'Z'|'0'..'9')+);

fragment
DRIVER
	:	('a'..'z'|'A'..'Z');
	
fragment
BACKSLASH	: '\u005c';
	
FILE	:	(( ( DRIVER ':') BACKSLASH)?  ID (BACKSLASH ID)* '.' ID);


//FILE	: (FILEPATH ID '.' ID);

NUMBER 	:	(('0')|('1'..'9')('0'..'9')*);

ID	: (('a'..'z'|'A'..'Z'|NUMBER|'_'|'-'))+;



//Number	: ('0'..'9') ('0'..'9')*;

WS
	: (' ' | '\t' | '\r' | '\n' | '\u000C' )+
		{ $channel=HIDDEN;}	;