/*
 *  Methods supporting loading/creation of the model
 *
 *  2004 - 2011 Frantisek Zboril jr.
 *  Faculty of Information Technology
 *  zborilf@fit.vutbr.cz
 *  http://www.fit.vutbr.cz/~zborilf
 *
 * (C) Brno University of Technology
 * Freeware licence VUT v Brně
 * https://wis.fit.vutbr.cz/FIT/db/dir.php/dr/VZ2007/externiInformace/softwareNaWebu/Priloha2_rozh23.pdf

 */

package jTMass.core.jLoaders;

import java.util.Hashtable;
import java.util.TreeSet;
import java.util.Iterator;
import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.TokenRewriteStream;
import jTMass.TMass;
import jTMass.core.jTMassModel.TModel;
import jTMass.core.jTMassModel.TModelElement;
import jTMass.core.jTMassPlatform.TPlatform;
import jTMass.core.jTMassEnvironment.TMulticast;
import jTMass.core.jALLL.jTObjects.*;
import jTMass.core.jALLL.ALLLLexer;
import jTMass.core.jALLL.ALLLParser;
import jTMass.core.jLoaders.jTMassML.tMassMLLexer;
import jTMass.core.jLoaders.jTMassML.tMassMLParser;
import jTMass.core.jAMass.TAgent;
import java.io.File;
import java.lang.reflect.Constructor;

public class TModelLoader {

    TokenRewriteStream PTokenStream;
    TModel PModel;
    String PFileName;
    Hashtable<String,TAgent> PAgentPopulation;
    Hashtable<String,TPlatform> PPlatformSet;
    public static String _PFilePath;
    public static String _ServicesPath="jTMass.core.jTMassPlatform.jTServices.";

    // ===== READER, WRITER =====

    public TModel getModel(){
	return(PModel);
    }
	
    public void setModelName(String s){
    	PModel.setModelName(s);
    }

    //================== CONNECTING ELEMENTS =====================

    public void connectElements(String outElementName, String inElementName){

        TModelElement outElement=PModel.getElementByName(outElementName);

        if(outElement==null){
            TMass._Terminal.reportError("Output element "+outElementName+" does not exist!");
            return;
        }
        TModelElement inElement=PModel.getElementByName(inElementName);

        if(inElement==null){
            TMass._Terminal.reportError("Input element "+inElementName+" does not exist!");
            return;
        }

        outElement.connectElement(inElement);
        return;
    }

    public void relationsMultiply(String outElementName, TreeSet<Integer> outParams,
                            String inElementName, TreeSet<Integer> inParams){

        if((outParams==null)){
            outParams=new TreeSet();
            outParams.add(new Integer(-1));
        }

        if((inParams==null)){
            inParams=new TreeSet();
            inParams.add(new Integer(-1));
        }

        String inElementNameI="", outElementNameI="";
        for(Integer i:inParams)
            for(Integer j:outParams){
                if (i!=-1)
                    inElementNameI=inElementName+i;
                else
                    inElementNameI=inElementName; // no index append
                if (j!=-1)
                    outElementNameI=outElementName+j;
                else
                    outElementNameI=outElementName;

                connectElements(outElementNameI,inElementNameI);
            }

        return;
    }

    public void relationsOneToOne(String outElementName, TreeSet<Integer> outParams,
                            String inElementName, TreeSet<Integer> inParams){

        Integer j;

        if(outParams==null){
            outParams=new TreeSet();
            outParams.add(new Integer(-1));
        }
        if(inParams==null){
            inParams=new TreeSet();
            inParams.add(new Integer(-1));
        }

        Iterator outIt=outParams.iterator();
            
        for(Integer i:inParams)
            if(outIt.hasNext()){
                String inElementNameI="", outElementNameI="";
                j=(Integer)outIt.next();
                if (i!=-1)
                    inElementNameI=inElementName+i;
                else
                    inElementNameI=inElementName;

                if (j!=-1)
                    outElementNameI=outElementName+j;
                else
                    outElementNameI=outElementName;

                TMass._Terminal.printlnSystemInfo("Connecting: "+outElementNameI+" |->| "+inElementNameI);
                    connectElements(outElementNameI,inElementNameI);
            }

        return;
    }

    // ===== ENVIRONMENTS =====

    public boolean addMulticastToModel(String multicastName, int count){
        TMass._Terminal.printlnSystemInfo(("New multicast: "+multicastName+" ( "+count+" elements )"));
        try{
             TMulticast multicast;
             multicast=new TMulticast(multicastName,count,true);
             PModel.addElement(multicast);
             
         }
         catch(Exception e){
            TMass._Terminal.reportError("Adding multicast to Model");
            return(false);
         }
         return(true);
    }

    public boolean addMulticastToModel(String name){
       	int count;
       	count=PModel.getnoElements(); // broadcast for every existing elements
       	return(this.addMulticastToModel(name,count));
    }
       
    // ===== AGENTS =====

    public boolean addAgentToModel(String elementName, String sourceName, Integer index){
        try{
            TAgent agent;
            if(index>0)
                elementName=elementName+index;
            agent=PAgentPopulation.get(sourceName);

            if(agent==null){
		TMass._Terminal.reportError("Agent source ''"+sourceName+"'' not found.");
		return(false);
            }

            TAgent newAgent=agent.cloneAgent(elementName);
            PModel.addElement(newAgent);
            TMass._Terminal.printlnSystemInfo("New agent: "+elementName+" (source :"+sourceName+")");
            return(true);
	}
	catch(Exception e){
            TMass._Terminal.reportError("Adding agent to model");
            return(false);
	}
    }
	
    // ===== PLATFORMS =====

    public void addServiceToPlatform(TPlatform platform, String objectName, String className){
        try{
            Class functionClass=Class.forName(_ServicesPath+className);
            Class[] params=new Class[1];
            params[0]=platform.getClass();
            Constructor function=functionClass.getConstructor((java.lang.Class[])params);
            platform.registerService(objectName, function);
	}
	catch(Exception e){
            TMass._Terminal.reportError("Wrong service class");
        }
        return;
    }

    public void addVariableToPlatform(TPlatform platform, String variableName, TObject value){
        platform.addVariable(variableName, value);
	return;
    }
	
    public boolean addPlatformToModel(String platformName, String sourceName, Integer index){
	try{
            TPlatform platform;
            if(index>0)
                platformName=platformName+index;
            platform=PPlatformSet.get(sourceName);

            if(platform==null){
                TMass._Terminal.reportError("Platform "+sourceName+" not found.");
                return(false);
            }

            TPlatform newPlatform=platform.clonePlatform(platformName);
            PModel.addElement(newPlatform);
            TMass._Terminal.printlnSystemInfo("New platform: "+platformName+" (source :"+sourceName+")");
            return(true);
        }
        catch(Exception e){
            TMass._Terminal.reportError("Adding platform to model "+e.toString());
            return(false);
	}	
    }

    // ===== OBJECT LOADERS =====
	
    public boolean loadAgent(String name, String fileName){
        try{
            String fname=new File(fileName).getName();
            if(fileName.equalsIgnoreCase(fname))
                fileName=_PFilePath.concat(fileName);
                CharStream stream=new ANTLRFileStream(fileName);
		ALLLLexer lexer=new ALLLLexer(stream);
		TokenRewriteStream tokenstream=new TokenRewriteStream(lexer);
		ALLLParser parser=new ALLLParser(tokenstream);
		TAgent newagent=parser.agent_loader(name,false);
		PAgentPopulation.put(name, newagent);
            }catch(Exception e){
                TMass._Terminal.reportError("Load agent / parser error");
                return(false);
            }
	return(true);
    }
	
    public boolean loadPlatform(String fileName){
        try{
            String fname=new File(fileName).getName();
            if(fileName.equalsIgnoreCase(fname))
                fileName=_PFilePath.concat(fileName);
                CharStream stream=new ANTLRFileStream(fileName);
                tMassMLLexer lexer=new tMassMLLexer(stream);
                TokenRewriteStream tokenStream=new TokenRewriteStream(lexer);
                tMassMLParser parser=new tMassMLParser(tokenStream);
                parser.load_platform(this);
             }catch(Exception e){
                 TMass._Terminal.reportError("Load platform / parser error");
		 return(false);
             }
        return(true);
    }

    public void addToPlatformSet(TPlatform platform){
	PPlatformSet.put(platform.getElementName(), platform);
	return;
    }
	
    public boolean loadModel(String fileName){
	try{
            String filePath=new File(fileName).getAbsolutePath();
            String fileOName=new File(fileName).getName();
            _PFilePath=filePath.replaceAll(fileOName, "");
            CharStream stream=new ANTLRFileStream(fileName);
            PAgentPopulation=new Hashtable<String,TAgent> ();
            PPlatformSet=new Hashtable<String,TPlatform> ();
            PModel=new TModel();
            tMassMLLexer lexer=new tMassMLLexer(stream);
            PTokenStream=new TokenRewriteStream(lexer);
            tMassMLParser parser=new tMassMLParser(PTokenStream);
            parser.tMassML(this);
        }catch(Exception e){
            TMass._Terminal.reportError("Load Model / parser error");
            return(false);
        }
	return(true);
    }

    // ===== CONSTRUCTOR =====
	
    public TModelLoader(String fileName){
	this.loadModel(fileName);
    };

}