// Each systems class

package temp;

import java.io.PrintStream;
import java.util.Vector;

public class Sim_System {
	String sys_name; // systems name
	Vector<Block> block_array; // array with all the blocks of the system
	Vector<Line> line_array; // array with all the connections of the system
	Assist assist; // assistant class of each system
	int m; // helping variable used for the printing of the connections
	boolean is_sub;	// boolean variable displaying if the system is a subsystem of the top level
	double s_time; 
	int type;		// type of the system
	int et_flag;	// 
	boolean reset;

	public Sim_System(String name) {
		this.reset=false;
		this.et_flag = 0;
		this.is_sub = false;
		this.sys_name = name;
		this.block_array = new Vector<Block>();
		this.line_array = new Vector<Line>();
		this.assist = new Assist();
		// this.collection= new Vector<SubSystem>();
		this.m = 0;
		// type deefines the type of the subsystem:
		// 0 => periodic
		// 1 => triggered
		// 2 => enabled
		this.type = 0;
		this.s_time = -1;
	}

	// Adding a block in the block array - defining of the types of certain blocks and adding 
	// period transition blocks in the inputs of the subsystems
	public void addBlock(Block block) {
		int i = 0;
		SubSystem sub = null;
		PeriodTransition pt = null;
		InPort in=null;
		OutPort out=null;

		if (block.getClass() == new TriggerPort().getClass()) 
		{
			type = 1;
		} 
		else if (block.getClass() == new EnablePort().getClass()) 
		{
			type = 2;
		}
		else if (block.getClass() == new InPort().getClass()) 
		{
			in = (InPort) block;
			assist.input.add(in.port - 1, in);
		}
		else if (block.getClass() == new OutPort().getClass()) 
		{
			out = (OutPort) block;
			assist.output.add(out.port - 1, out);
		}
		if (block.getClass() == new SubSystem().getClass())
			assist.sub_syst.add(block.block_name);

		// in case of triggered/enabled subsystems we add the period transition blocks for the inputs of the subsystem
		if (block.getClass() == new SubSystem().getClass()) 
		{
			sub = (SubSystem) block;
			if (sub.s_system.type != 0) 
			{
				for (i = sub.ports.get(0); i > 0; i = i - 1) {
					pt = new PeriodTransition();
					pt.block_name = sub.block_name + "_STA_in" + i;
					pt.sub_syst = sub.s_system.sys_name;
					pt.system=sub;
					block_array.add(pt);
					pt = null;
				}
			}
			System.out.println("PORTS: " + sub.ports);
			this.block_array.add(block);
		} else
			this.block_array.add(block);
	}

	// adding a line in the line_array of the system
	// - adding period transition blocks for the outputs of a subsystem
	// - creating lines for the connections of period transitions and the subsystems
	public void addLine(Line line) {
		int i = 0;
		int j = 0;
		SubSystem sub = null;
		Line l = null;
		Line dest=null;
		PeriodTransition pt = null;
		
		if (line.src.getClass() == new SubSystem().getClass()) 
		{
			// adding period transition blocks in the outputs of the triggered enabled subsystems
			sub=(SubSystem)line.src;
			if(sub.s_system.type!=0)
			{
				while(true)
				{
					pt=new PeriodTransition();
					pt.block_name=sub.block_name+"_STA_"+"out"+line.src_port+"_"+line.dst.get(i).block_name;
					pt.sub_syst=sub.s_system.sys_name;
					pt.system=sub;
					block_array.add(pt);
					
					if(i==line.dst.size()-1)
						break;				
					i++;
				}
			}
			i=0;
			j=0;
			while(true)
			{			
				// creating connections for the output period transition blocks.
				while(true)
				{
					if(block_array.get(i).block_name.matches(sub.block_name+"_STA_"+"out"+line.src_port+"_"+line.dst.get(j).block_name))
					{
						pt=(PeriodTransition)block_array.get(i);
						if(sub.s_system.assist.output.get(line.src_port-1).disable.matches("reset"))
						{
							pt.reset=true;
							pt.initial=sub.s_system.assist.output.get(line.src_port-1).initial;
						}
						l=new Line();
						l.src=block_array.get(i);
						l.src_port=1;
						l.dst.add(line.dst.get(j));
						l.d_port.add(line.d_port.get(j));
						l.dst_port=line.d_port.get(j);
						line.dst.set(j, block_array.get(i));
						line.dst_port="1";
						line.d_port.set(j,"1");
						line_array.add(l);
						break;
					}
					if(i==block_array.size()-1)
						break;
					i++;
				}
				if(j==line.dst.size()-1)
					break;
				j++;				
			}
			
						
			sub = (SubSystem) line.src;
			while (true) 
			{
				if (block_array.get(j).getClass() == new PeriodTransition().getClass()) 
				{
					pt = (PeriodTransition) block_array.get(j);
					if (block_array.get(j).block_name.matches(sub.block_name+ "_STA_out" + line.src_port)) 
					{
						pt.sample_time = sub.sample_time;
						l = new Line();
						l.src = sub;
						l.src_port = line.src_port;
						l.dst.add(pt);
						l.d_port.add("1");
						l.dst_port = "1";
						line.src = pt;
						line.src_port = 1;
						this.line_array.add(l);
						l = null;
						pt = null;
						break;
					}
				}
				if (block_array.get(j) == block_array.lastElement())
					break;
				j++;
			}
		} 
		else
			while (true) 
			{
				if (line.dst.get(i).getClass() == new SubSystem().getClass()) 
				{
					sub = (SubSystem) line.dst.get(i);
					while (true) 
					{
						if (block_array.get(j).getClass() == new PeriodTransition().getClass()) 
						{
							if (block_array.get(j).block_name.matches(sub.block_name + "_STA_in"+ line.d_port.get(i))) 
							{
								pt = (PeriodTransition) block_array.get(j);
								pt.sample_time = sub.sample_time;
								l = new Line();

								l.dst.add(line.dst.get(i));
								l.d_port.add(line.d_port.get(i));
								l.dst_port = line.d_port.get(i);
								line.dst.remove(i);
								line.dst.add(i, pt);
								l.src = pt;
								line.d_port.remove(i);
								line.d_port.add(i, "1");

								this.line_array.add(l);
								l = null;

								break;
							}
						}
						if (block_array.get(j) == block_array.lastElement())
							break;
						j++;
					}
				}
				if (line.dst.get(i) == line.dst.lastElement())
					break;
				i++;
			}

		this.line_array.add(line);
	}

	// removing period transition blocks that are unnecessary (special occasion where we have a triggerred subsystem
	// followed by another triggered subsystem without any blocks between them.
	public void remove_STA()
	{
		int i=0;
		int j=0;
		String name=null;
		boolean flag=false;
				
		while(true)
		{
			if(block_array.get(i).block_name.contains("STA_in"))
			{
				name=block_array.get(i).block_name;
				while(true)
				{
					if(line_array.get(j).src.block_name.matches(name))
					{
						flag=true;
						break;
					}
					if(j==line_array.size()-1)
						break;
					j++;
				}
				if(!flag)
				{
					block_array.remove(i);
					i--;
				}
				flag=false;
				j=0;				
			}
			if(i==block_array.size()-1)
				break;
			i++;
			
		}
	}

	// returns the systems of all the subsystems of a model into a vector
	public Vector<Sim_System> find(SubSystem sub) {
		int i = 0;
		int j = 0;
		Vector<Sim_System> collect = new Vector<Sim_System>();
		SubSystem temp = null;
		sub.s_system.is_sub = true;

		while (true) {
			if (sub.s_system.block_array.get(i).getClass() == new SubSystem().getClass()) 
			{
				temp = (SubSystem) sub.s_system.block_array.get(i);
				collect.add(0, temp.s_system);
				collect.addAll(0, this.find(temp));
			}
			if (sub.s_system.block_array.get(i) == sub.s_system.block_array.lastElement())
				break;
			i++;
			temp = null;
		}
		return collect;
	}

	// returns the subsystem with a specific name
	public SubSystem find(String name) {
		int i = 0;
		SubSystem sub = null;

		while (true) {
			if (block_array.get(i).getClass() == new SubSystem().getClass()) {
				if (block_array.get(i).block_name.matches(name)) {
					sub = (SubSystem) block_array.get(i);
					break;
				}
			}
			if (i == block_array.size() - 1)
				break;
			i++;
		}
		return sub;
	}

	// defining the sample times of all the blocks of a system.
	public boolean defineSampleTime() {
		int i = 0;
		int j = 0;
		SubSystem sub = null;
		TriggerPort trig = null;
		EnablePort enab = null;
		boolean flag = false;

		while (true) {
			if (line_array.get(i).src.sample_time == -1)
				flag = true;
			while (true) {
				// give the sample time from the source to the destination of a connection
				if (line_array.get(i).dst.get(j).sample_time == -1 & line_array.get(i).dst.get(j).getClass() != new TriggerPort().getClass() & line_array.get(i).dst.get(j).getClass() != new PeriodTransition().getClass() & line_array.get(i).dst.get(j).getClass() != new EnablePort().getClass()) 
				{
					line_array.get(i).dst.get(j).sample_time = line_array.get(i).src.sample_time;
				}
				// initialization of sample times in trigger port
				else if (line_array.get(i).dst.get(j).getClass() == new TriggerPort().getClass()) 
				{
					trig = (TriggerPort) line_array.get(i).dst.get(j);
					trig.src_stime = line_array.get(i).src.sample_time;
					sub = find(trig.syst_name);
					sub.sample_time = trig.sample_time;
					sub.trig_sample_time = trig.src_stime;
				} 
				// initialization of sample times in enable port
				else if (line_array.get(i).dst.get(j).getClass() == new EnablePort().getClass()) 
				{
					enab = (EnablePort) line_array.get(i).dst.get(j);
					enab.src_stime = line_array.get(i).src.sample_time;
					sub = find(enab.syst_name);
					enab.sample_time = line_array.get(i).src.sample_time;
					sub.sample_time = enab.sample_time;
					sub.trig_sample_time = enab.src_stime;
				} 
				// initialization of sample time in period transition blocks
				else if (line_array.get(i).dst.get(j).getClass() == new PeriodTransition().getClass()) 
				{

					if (line_array.get(i).src.getClass() == new SubSystem().getClass()) 
					{
						sub = (SubSystem) line_array.get(i).src;
						if (sub.s_system.type == 1)
							line_array.get(i).dst.get(j).sample_time = sub.trig_sample_time;
						else if (sub.s_system.type == 0) 
						{
							line_array.get(i).dst.get(j).sample_time = sub.getSampleTime(line_array.get(i).src_port,1);
							sub.sample_time = line_array.get(i).dst.get(j).sample_time;
						}
						else 
						{
							line_array.get(i).dst.get(j).sample_time = conv(sub.getSampleTime(line_array.get(i).src_port,1),this,sub.s_system);//-sub.getSampleTime(line_array.get(i).src_port,1);//+ sub.s_system.et_flag;
							sub.sample_time = line_array.get(i).dst.get(j).sample_time;
						}

					} else
						line_array.get(i).dst.get(j).sample_time = line_array.get(i).src.sample_time;
				}
				if (j == line_array.get(i).dst.size() - 1)
					break;
				j++;
			}
			j = 0;
			if (i == line_array.size() - 1)
				break;
			i++;
		}
		return flag;

	}
	
	// generic translation of enable blocks.
	public void translateEnable(PrintStream ps)
	{
		int i=0;
		int j=0;
		EnablePort enab=null;
		
		while(true)
		{
			if(block_array.get(i).getClass()== new EnablePort().getClass())
			{
				enab=(EnablePort)block_array.get(i);
				ps.println("modal type "+block_array.get(i).block_name+"_comp");
				ps.println("\ndata float c=1.0 \ndata float cold=1.0 " +
						"\nexport port simulinkLib.FloatPort in1(c)=in1" +
						"\nexport port simulinkLib.ActPort act=act" +
						"\nexport port simulinkLib.ActPort res=res");
			
				j=0;

				// depending on how many different sample times are inside the enabled subsystem
				// we have the same number of enab and act ports.
				while(true)
				{
					ps.println("export port simulinkLib.ActPort enab"+j+"=enab"+j);
					ps.println("export port simulinkLib.ActPort act"+j+"=act"+j);
					if(j==enab.e_times.size()-1)
						break;
					j++;
				}
				ps.println("on act \ndo { cold=c; }");
				j=0;
				while(true)
				{
					ps.println("on act"+j);
					if(j==enab.e_times.size()-1)
						break;
					j++;
				}
				ps.println("on in1 <= act");
				j=0;
				while(true)
				{
					ps.println("on enab"+j+" <- act"+j);
					if(j==enab.e_times.size()-1)
						break;
					j++;
				}
				j=0;
				
				ps.println("on res <-- in1 provided (cold>c && c<=0.0)");
				while(true)
				{
					ps.println("on enab"+j+" <-- in1 provided (c>0.0)");
					if(j==enab.e_times.size()-1)
						break;
					j++;
				}
				ps.println("end\n");
			
			}
			if(i==block_array.size()-1)
				break;
			i++;
		}
		ps.println();
		
	}

	// main translate function of the system. In this function the blocks, the
	// lines and the acts are
	// inserted in the bip model
	public void translate(PrintStream ps) {
		int i = 0;
		int j = 0;
		int k = 0;
		Vector<ActClass> act_conn = new Vector<ActClass>();
		ActClass temp = null;
		ActClass act = null;
		boolean flag = false;
		UnitDelay ud = null;
		ZeroOrderHold zoh = null;
		TransferFcn tf=null;
		Vector<String> export_act = new Vector<String>();
		Vector<ActClass> export_system_act = new Vector<ActClass>();

		if (is_sub)
			ps.println("compound type " + sys_name + "_sub");
		else
			ps.println("compound type " + sys_name);
		ps.println();

		// determine if unit delay blocks are reset or not and translate the blocks into components
		while (true) 
		{
			if (this.block_array.get(i).getClass() == new UnitDelay().getClass()) 
			{
				ud = (UnitDelay) this.block_array.get(i);
				if(reset)
					ud.reset=true;
				
			}

			if (this.block_array.get(i).getClass() == new TransferFcn().getClass())
			{
				tf=(TransferFcn) block_array.get(i);
				if(reset)
					tf.reset=true;
			}

			this.block_array.get(i).translate(ps, assist);
			if (this.block_array.get(i) == this.block_array.lastElement())
				break;
			i++;
		}
		i = 0;
		j = 0;
		ps.println();
		
		// translate the lines of the block array into connections 
		while (true) {
			this.line_array.get(j).translate(ps, this.block_array, assist,this);
			if (this.line_array.get(j) == this.line_array.lastElement())
				break;
			j++;
		}
		j = 0;
		ps.println();

		i = 0;
		j = 0;
		System.out.println("\n\n");

		while (true) 
		{
			//System.out.println("->" + this.assist.actlist.get(i).act + " "+ this.assist.actlist.get(i).sample_time);
			if (this.assist.actlist.get(i) == this.assist.actlist.lastElement())
				break;
			i++;
		}
		i = 0;
		
		// add reset activation events of the blocks in assist.actlist
		if(reset)
		{
			if(!handleReset().act.isEmpty())
				assist.actlist.add(handleReset());
		}
		boolean flag2=false;
		
		// translation of the act-list of the components
		while (true) 
		{
			this.m++;
			temp = new ActClass();
			temp.act.add(0, this.translateAct(ps,this.assist.actlist.get(i).act));
				
			if(assist.actlist.get(i).act.size()==1)
				flag2=true;
			temp.sample_time = this.assist.actlist.get(i).sample_time;
			System.out.println(temp.act + " " + temp.sample_time);
			
			while (true) 
			{
				if (act_conn.isEmpty()) 
				{
					if (temp.sample_time >= -1 & temp.sample_time<200)
						act_conn.add(temp);
					break;
				}
				if (act_conn.get(j).sample_time == temp.sample_time	| temp.sample_time == -1 | temp.sample_time == 0) 
				{
					act_conn.get(j).act.addAll(temp.act);
					flag2=false;
					flag = true;
					break;
				}
				if (act_conn.get(j) == act_conn.lastElement())
					break;
				j++;
			}
			if (!flag) {
				act_conn.add(temp);
			}
			
			// export activation events of non triggered subsystems 
			if (is_sub & temp.sample_time>-55) 
			{
				if(!flag2)
					export_act.add(k, "export port simulinkLib.ActPort act" + k+ " is " + temp.act.get(0) + ".act");// +" "+temp.sample_time);
				else
					export_act.add(k, "export port simulinkLib.ActPort act" + k+ " is " + temp.act.get(0));// +" "+temp.sample_time);
				act = new ActClass();
				if (type == 1) 
				{
					System.out.println("EEE " + s_time);
					act.sample_time = s_time;
				} 
				else
					act.sample_time = temp.sample_time;
				act.act.add("act" + k);
				assist.periodic_act.add(act);
				k++;
				if((type==2 | type==0) & ((temp.sample_time-et_flag)<0 | (temp.sample_time-et_flag)>200))
				{
					System.out.println(export_act.lastElement());
					export_act.remove(export_act.lastElement());
					k--;
					assist.periodic_act.remove(assist.periodic_act.lastElement());
				}
			}

			if (this.assist.actlist.get(i) == this.assist.actlist.lastElement())
				break;
			i++;
		}
		j = 0;
		while (true) 
		{
			this.m++;
			this.translateAct(ps, act_conn.get(j).act);
			if (act_conn.get(j) == act_conn.lastElement())
				break;
			j++;
		}
		i = 0;
		j = 0;
		int diff = 0;
		flag = false;
		
		// create export ports of activation events of subsystems
		if (is_sub) 
		{
			diff = assist.periodic_act.size();
			while (true) 
			{
				if (block_array.get(i).getClass() == new SubSystem().getClass()) 
				{
					flag = assist.periodic_act.addAll(retrieveAct((SubSystem) block_array.get(i),assist.periodic_act));
				}
				if (i == block_array.size() - 1)
					break;
				i++;
			}

			if (diff != assist.periodic_act.size())
				flag = true;
			i = k;

			if (flag)
				while (true) 
				{
					export_act.add(k, "export port simulinkLib.ActPort act" + k	+ " is " + assist.periodic_act.get(i).act.get(1)+ "\n");// +" "+assist.periodic_act.get(i).sample_time+"\n");
					assist.periodic_act.get(i).act.remove(0);
					assist.periodic_act.get(i).act.add(0, "act" + k);
					if (i == assist.periodic_act.size() - 1)
						break;
					i++;
					k++;
				}
		}
		i = 0;

		ps.println();

		i = 0;
		
		// export acts of the root system that do not belong to other triggered subsystems (sample times < -55 or > 200)
		while (true) 
		{
			if (act_conn.get(i).sample_time > 0	& !export_system_act.contains(act_conn.get(i)) & act_conn.get(i).sample_time<200)
				export_system_act.add(act_conn.get(i));
			if (i == act_conn.size() - 1)
				break;
			i++;
		}
		i = 0;

		// export data flow ports of a system
		if (!assist.input.isEmpty()) {
			while (true) {
				ps.println("export port simulinkLib.FloatPort in"
						+ assist.input.get(i).port + " is "
						+ assist.input.get(i).block_name + ".in1");
				if (assist.input.get(i) == assist.input.lastElement())
					break;
				i++;
			}
		}
		i = 0;
		if (!assist.output.isEmpty()) {
			while (true) {
				ps.println("export port simulinkLib.FloatPort out"+ assist.output.get(i).port + " is "+ assist.output.get(i).block_name + ".out");
				if (assist.output.get(i) == assist.output.lastElement())
					break;
				i++;
			}
		}
		i = 0;

		if (is_sub) 
		{
			ps.println();
			while (true) 
			{
				ps.println(export_act.get(i));
				if (i == export_act.size() - 1)
					break;
				i++;
			}
		}
		i = 0;

		Vector<ActClass> system_act = new Vector<ActClass>();
		if (!is_sub)
			while (true) 
			{
				temp = new ActClass();
				temp.act.add("act" + i);
				temp.sample_time = export_system_act.get(i).sample_time;
				system_act.add(temp);
				if(!export_system_act.get(i).act.get(0).contains("."))
					ps.println("export port simulinkLib.ActPort act" + i + " is "+ export_system_act.get(i).act.get(0) + ".act");
				else
					ps.println("export port simulinkLib.ActPort act" + i + " is "+ export_system_act.get(i).act.get(0));
				if (i == export_system_act.size() - 1)
					break;
				i++;
			}

		ps.println();
		ps.println("end\n");
		if (!is_sub)
			translateClocks(ps, system_act);

	}
	
	// return reset activation event of the unit delay blocks and transfer functions of a system
	public ActClass handleReset()
	{
		int i=0;
		ActClass res_act=new ActClass();
		res_act.sample_time=et_flag;
		//System.out.println("{}{}{} "+res_act.sample_time);
		while(true)
		{
			if(block_array.get(i).getClass()== new UnitDelay().getClass() | block_array.get(i).getClass()== new TransferFcn().getClass())
			{
				res_act.act.add(block_array.get(i).block_name+".res");
			}
			if(i==block_array.size()-1)
				break;
			i++;
		}
		return res_act;
	}

	// clock generator function
	public void translateClocks(PrintStream ps, Vector<ActClass> act) {
		Vector<Double> sample_times = new Vector<Double>();
		Vector<Double> clks = new Vector<Double>();
		ActClass insert = null;
		double multiple = 0;
		boolean flag = false;

		int k = 0;
		int i = 0;
		int j = 0;
		double time_unit = 0;
		
		// Sorting of sample times of the model
		
		while (i != act.size()) {
			if (sample_times.isEmpty())
				sample_times.add(act.get(i).sample_time);
			else if (act.get(i).sample_time < sample_times.get(0))
				sample_times.add(0, act.get(i).sample_time);
			else {
				while (true) {
					if (j == sample_times.size()) {
						sample_times.add(act.get(i).sample_time);
						break;
					}
					if (sample_times.get(j) < act.get(i).sample_time)
						j++;
					else if (sample_times.get(j) > act.get(i).sample_time) {
						sample_times.add((j), act.get(i).sample_time);
						break;
					}
				}
				j = 0;
			}
			i++;
		}
		System.out.println("** "+sample_times);
		i = 0;
		
		Vector<ActClass> sort = new Vector<ActClass>();		
		
		while(true)
		{
			insert=new ActClass();
			insert.sample_time=sample_times.get(i);
			insert.act.add("clk"+i);
			sort.add(insert);
			if(i==sample_times.size()-1)
				break;
			i++;
		}
		
		i=0;
		j=0;
		flag=true;
		
		// calculation of the dependencies between the activation events
		while(true)
		{
			while(j!=i)
			{
				if(sort.get(i).sample_time%sort.get(j).sample_time==0)
				{					
					k=j+1;
					while(true)
					{
						if(k==i)
							break;
						if(sort.get(k).sample_time%sort.get(j).sample_time==0 & sort.get(i).sample_time%sort.get(k).sample_time==0)
						{
							flag=true;
							break;
						}
						
						k++;
					}
					k=0;
					if(!flag)
						sort.get(i).act.add(sort.get(j).act.get(0));					
				}			
				flag=false;
				j++;
			}
			j=0;
			if(i==sort.size()-1)
				break;
			i++;
		}
		
		j=0;
		i=0;
		k=0;
		
				
		while(true)
		{
			System.out.println("## "+sort.get(i).act+" "+sort.get(i).sample_time);
			if(i==sort.size()-1)
				break;
			i++;
		}
		i=0;
		
		flag=false;
		ActClass reset=new ActClass();
		String res_act=null;
		
		while(true)
		{
			res_act=sort.get(i).act.get(0);
			while(true)
			{
				if(sort.get(j).act.contains(res_act) & j!=i)
				{
					flag=false;
					break;
				}
				if(j==sort.size()-1)
				{
					flag=true;
					break;
				}
				j++;
			}
			j=0;
			if(flag)
				reset.act.add(res_act);
			flag=false;
			if(i==sort.size()-1)
				break;
			i++;
		}
				
		// calculation of the time unit of the model
		if (sample_times.size() > 1)
			time_unit = gcd(sample_times.get(0), sample_times.get(1));
		else
			time_unit = sample_times.get(0);
		i = 2;
		if (i < sample_times.size())
			while (true) 
			{
				time_unit = gcd(time_unit, sample_times.get(i));
				i++;
				if (i == sample_times.size())
					break;
			}

		System.out.println();

		ps.println("modal type ClockGenerator\n");
		ps.println("data float x="+(-time_unit));

		i = 0;
		j = 0;

		while (true) {
			ps.println("data int g" + i + "=0");
			ps.println("data int g" + i + "_i=0");
			if (i == sort.size() - 1)
				break;
			i++;
		}
		i = 0;
		flag = false;

		i = 0;
		j = 0;

		ps.println();
		
		// creating activation events for the clocks and connecting the clock events
		// with the activation events of the root system
		while (true) 
		{
			ps.println("export port simulinkLib.ActPort clk" + i);
			while (true) 
			{
				if (act.get(j).sample_time == sort.get(i).sample_time) 
				{
					act.get(j).act.add("clk" + i);
					break;
				}
				if (j == act.size() - 1)
					break;
				j++;
			}
			j = 0;
			if (i == sort.size() - 1)
				break;
			i++;
		}

		ps.println("port simulinkLib.ActPort tic");
		ps.println("port simulinkLib.ActPort reset\n");
		ps.println("on tic");
		ps.println("do { x=x+" + time_unit + ";");

		i = 0;

		while (true) {
			ps.println("g" + i + "_i=x/" + sort.get(i).sample_time + ";");
			ps.println("g" + i + "=x-(g" + i + "_i)*" + sort.get(i).sample_time + ";");
			if (i == sort.size() - 1)
				break;
			i++;
		}

		ps.println("}");

		i = 0;
		while (i != act.size()) 
		{
			System.out.println("&& "+act.get(i).act + " " + act.get(i).sample_time);
			i++;
		}
		i = 0;
		j = 0;
		k=0;
		int l=0;
		ActClass sec_act=null;
		flag=false;
		sec_act=new ActClass();
		sec_act.sample_time=Double.NaN;

		// printing the dependencies of the events
		while(true)
		{
			ps.print("on " + sort.get(i).act.get(0) + "<-");
			j=1;
			while(true)
			{				
				if(sort.get(i).act.size()==1)
				{
					ps.print("tic ");
					break;
				}
				else
				{
					ps.print(sort.get(i).act.get(j)+" ");
				}
				if(j==sort.get(i).act.size()-1)
					break;
				j++;
			}
			j=0;
			ps.print(" provided(g"+ sort.get(i).act.get(0).substring(3)+ "==0)\n");
			if(i==sort.size()-1)
				break;
			i++;
		}
		i=0;
		j=0;
		k = 0;
		
		multiple = sort.get(0).sample_time;

		//if (sort.size() == 2)
		//	multiple = lcm(sort.get(0).sample_time,	sort.get(1).sample_time);
		//else if (sort.size() >= 3)
		if(sort.size()>1)
		{
			i = 1;
			while (true) 
			{
				multiple = lcm(multiple,sort.get(i).sample_time);
				if (i == sort.size() - 1)
					break;
				i++;
			}
		}
		i = 0;
		ps.println();
		ps.print("on reset <--");
		while (true) 
		{
			ps.print(reset.act.get(i) + " ");
			if (i == reset.act.size() - 1)
				break;
			i++;
		}

		i = 0;

		// creation of clock generator and model instance and connection between them
		if (sort.size() > 1)
			ps.print("provided (x==" + multiple + ")");
		else
			ps.print("provided (x==" + (time_unit * 2) + ")");
		
		ps.println("\ndo { x=0.0; }");
		ps.println();
		ps.println("end");
		ps.println();
		ps.println("compound type " + sys_name + "_topLevel\n");
		ps.println("component " + sys_name + " " + sys_name + "_instance");
		ps.println("component ClockGenerator clock\n");

		while (true) {
			ps.println("connector simulinkLib.act2 clkConn" + i + "("
					+ sys_name + "_instance." + act.get(i).act.get(0)
					+ ",clock." + act.get(i).act.get(1) + ")");
			if (i == act.size() - 1)
				break;
			i++;
		}

		ps.println("end");

	}

	// least common multiple function
	public double lcm(double a, double b) {
		return (Math.abs(a * b) / gcd(a, b));
	}

	// greater common divisor function
	public double gcd(double a, double b) {
		if (b == 0)
			return a;
		else
			return gcd(b, a % b);
	}

	// retrieve activation events from a subsystem that do not belong to the periodic act of the main system. 
	public Vector<ActClass> retrieveAct(SubSystem sub, Vector<ActClass> periodic) {
		ActClass act = null;
		int i = 0, j = 0;
		boolean flag = false;
		Vector<ActClass> ret = new Vector<ActClass>();

		while (true) 
		{
			while (true) 
			{
				if (periodic.get(i).sample_time == sub.s_system.assist.periodic_act.get(j).sample_time & sub.s_system.assist.periodic_act.get(j).sample_time!= sub.s_system.et_flag)
				{
					break;
				}
				if (i == periodic.size() - 1) 
				{
					flag = true;
					break;
				}
				i++;
			}
			if (flag & sub.s_system.type==0)//.assist.periodic_act.get(j).sample_time>-55) 
			{
				act = new ActClass();
				act.act.add(0, "");
				act.act.add(1, sub.block_name + "."	+ sub.s_system.assist.periodic_act.get(j).act.get(0));
				act.sample_time = sub.s_system.assist.periodic_act.get(j).sample_time;
				 System.out.println("\nTO SYSTEM EINAI "+sub.block_name+sub.s_system.assist.periodic_act.get(j).act.get(0)+"\n");
				// act.act.add(0,)
				ret.add(act);
				flag = false;
			}
			if (j == sub.s_system.assist.periodic_act.size() - 1)
				break;
			j++;
			i = 0;
		}
		return ret;
	}

	// find the act from the periodic act of the system with the defined sample time and return it
	public ActClass findAct(double sampleTime) {
		int i = 0;
		ActClass act = null;
		while (true) {
			System.out.println("&& " + assist.periodic_act.get(i).sample_time+" "+sampleTime);
			if (assist.periodic_act.get(i).sample_time == sampleTime)
				act = assist.periodic_act.get(i);
			if (i == assist.periodic_act.size() - 1)
				break;
			i++;
		}
		return act;

	}

	// creating activation event connections for 2, 4 and 8 activation events.
	public String printAct2(String act1, String act2, int count) {
		String print = null;

		print = "connector simulinkLib.act2 actConn" + this.m + "_" + count
				+ "(" + act1 + ", " + act2 + ")";

		return print;

	}

	public String printAct4(String act1, String act2, String act3, String act4,
			int count) {
		String print = null;

		print = "connector simulinkLib.act4 actConn" + this.m + "_" + count
				+ "(" + act1 + ", " + act2 + ", " + act3 + ", " + act4 + ")";

		return print;

	}

	public String printAct8(String act1, String act2, String act3, String act4,
			String act5, String act6, String act7, String act8, int count) {
		String print = null;

		print = "connector simulinkLib.act8 actConn" + this.m + "_" + count
				+ "(" + act1 + ", " + act2 + ", " + act3 + ", " + act4 + ", "
				+ act5 + ", " + act6 + ", " + act7 + ", " + act8 + ")";

		return print;

	}

	// translation of activation events m is the global counter for activation events with different sample times
	// so actConn1_2 and actConn1_3, will have the same sample time and will be connected between them
	// where actConn1_2 and actConn2_1 will have different sample times.
	public String translateAct(PrintStream ps, Vector<String> comp) {
		int numb = comp.size();
		int i = 0;
		int j = 0;
		int k = 0;
		int l = 1;
		String name = "actConn" + m + "_";
		String act_line = null;

		if (numb <= 4) {
			if (numb == 2) {
				ps.println(this.printAct2(comp.get(0), comp.get(1), 1));
				act_line = name + "1";
			} else if (numb == 3) {
				ps.println(this.printAct2(comp.get(0), comp.get(1), 1));
				ps.println(this.printAct2(name + "1", comp.get(2), 2));
				act_line = name + "2";
			} else if (numb == 4) {
				ps.println(this.printAct4(comp.get(0), comp.get(1),
						comp.get(2), comp.get(3), 1));
				act_line = name + "1";
			}
		}
		if (8 >= numb & numb > 4) {
			if (numb == 5) {
				ps.println(this.printAct4(comp.get(0), comp.get(1),
						comp.get(2), comp.get(3), 1));
				ps.println(this.printAct2(name + "1", comp.get(4), 2));
				act_line = name + "2";
			} else if (numb == 6) {
				ps.println(this.printAct4(comp.get(0), comp.get(1),
						comp.get(2), comp.get(3), 1));
				ps.println(this.printAct2(name + "1", comp.get(4), 2));
				ps.println(this.printAct2(name + "2", comp.get(5), 3));
				act_line = name + "3";
			} else if (numb == 7) {
				ps.println(this.printAct4(comp.get(0), comp.get(1),
						comp.get(2), comp.get(3), 1));
				ps.println(this.printAct4(name + "1", comp.get(4), comp.get(5),
						comp.get(6), 2));
				act_line = name + "2";
			} else if (numb == 8) {
				ps.println(this.printAct8(comp.get(0), comp.get(1),
						comp.get(2), comp.get(3), comp.get(4), comp.get(5),
						comp.get(6), comp.get(7), 1));
				act_line = name + "1";
			}
		} else if (numb > 8) {
			ps.println(this.printAct8(comp.get(0), comp.get(1), comp.get(2),
					comp.get(3), comp.get(4), comp.get(5), comp.get(6), comp
							.get(7), 1));
			for (i = 1; i < (numb / 8); i++)
				ps.println(this.printAct8(name + i, comp.get(0 + (i * 8)), comp
						.get(1 + (i * 8)), comp.get(2 + (i * 8)), comp
						.get(3 + (i * 8)), comp.get(4 + (i * 8)), comp
						.get(5 + (i * 8)), comp.get(6 + (i * 8)), (i + 1)));
			for (j = 1; j < (numb / 8); j++)
				ps.println(this.printAct2(name + (j + i - 1), comp
						.get(7 + (j * 8)), (j + i)));
			if (numb % 8 != 0) {
				for (k = j + i; k < (j + i + (numb % 8)); k++, l++)
					ps.println(this.printAct2(name + (k - 1), comp.get(comp
							.size()
							- (l)), k));
				act_line = name + (k - 1);
			} 
			else
				act_line = name + (j + i - 1);
		}
		
		if(comp.size()==1)
			act_line=comp.get(0);
		return act_line;

	}

	// return the sample time of a block of "out" system, so the "in" system would understand it. 
	public double conv(double stime,Sim_System in,Sim_System out)
	{
		return (stime-out.et_flag)+in.et_flag;
	}
}