import java.util.ArrayList;
import java.lang.annotation.*;
import java.applet.Applet;
import java.awt.Graphics;
import java.util.ArrayList;
import java.awt.Color;
import java.awt.*;
import java.awt.event.*;

public class JaDEN_Automata extends JaDEN implements emDependent{
	@EDEN_DESCRIPTION(definition = "new Tape(\"aaabbb\")")
	private emTape tape = new emTape(new Tape("aaabbb"));
	private MachineStates states = new emMachineStates(new MachineStates()).item;
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public void init(){
		super.init();
		picture.add(tape);
		states.add(new emState(new State(1)));
		states.add(new emState(new State(2)));

	}

	public JaDEN_Automata(){
		super();

	
		super.emAddDependent(this);
		Evaluator.addInstance(this);
}	


	public JaDEN_Automata registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("mouseX")){}
		else if(property.equals("mouseY")){}
		else if(property.equals("mouseClickX")){}
		else if(property.equals("mouseClickY")){}
		else if(property.equals("mousePressed")){}
		else if(property.equals("picture")){}
		emTriggerUpdateJaDEN_Automata(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateJaDEN_Automata(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticJaDEN_Automata(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	private void em_updateTape(){
		try{
			emTape new_tape = new emTape(new Tape("aaabbb"));
			setTape(new_tape.item);
		}catch(Exception e){
			tape.item = null;
		}
	}
	public void setTape(Tape em_tape){
		if(tape.item == null || !tape.item.equals(em_tape)){
			tape.item = em_tape;
			emTriggerUpdateJaDEN_Automata("tape");
			emTriggerUpdateJaDEN_Automata("JaDEN_Automata.tape");
		}
	}
	public Tape getTape(){
		return tape.item;
	}

}
class Tape extends Group implements emDependent{
	public char[] tape = " ".toCharArray();
	public int headPosition = 0;
	@EDEN_DESCRIPTION(definition = "new Text(20, 20, String.valueOf(tape))")
	private emText output = new emText(new Text(20, 20, String.valueOf(tape)));
	@EDEN_DESCRIPTION(definition = "new Text(20, 30, (\"Current Symbol: \" + tape[headPosition]))")
	private emText currentSymbol = new emText(new Text(20, 30, ("Current Symbol: " + tape[headPosition])));
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public Tape(){
		super();

	
		Evaluator.addInstance(this);
}	

	public Tape(String str){
		super();
		setTape(str.toCharArray());
		picture.add(output);
		picture.add(currentSymbol);

	
		Evaluator.addInstance(this);
}	

	public char readHead(){
		return tape[headPosition];

	}

	public void writeHead(char c){
		tape[headPosition] = c;setArrayTape();

	}


	public Tape registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		emTriggerUpdateTape(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateTape(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticTape(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	public void setTape(char[] em_tape){
		if(tape == null || !tape.equals(em_tape)){
			tape = em_tape;
			em_updateOutput();
			em_updateCurrentSymbol();
			emTriggerUpdateTape("tape");
			emTriggerUpdateTape("Tape.tape");
		}
	}
	public void setArrayTape(){
			em_updateOutput();
			em_updateCurrentSymbol();
			emTriggerUpdateTape("tape");
			emTriggerUpdateTape("Tape.tape");
	}
	public char[] getTape(){
		return tape;
	}
	public void setHeadPosition(int em_headPosition){
		if(headPosition != em_headPosition){
			headPosition = em_headPosition;
			emTriggerUpdateTape("headPosition");
			emTriggerUpdateTape("Tape.headPosition");
		}
	}
	public int getHeadPosition(){
		return headPosition;
	}
	private void em_updateOutput(){
		try{
			emText new_output = new emText(new Text(20, 20, String.valueOf(tape)));
			setOutput(new_output.item);
		}catch(Exception e){
			output.item = null;
		}
	}
	public void setOutput(Text em_output){
		if(output.item == null || !output.item.equals(em_output)){
			output.item = em_output;
			emTriggerUpdateTape("output");
			emTriggerUpdateTape("Tape.output");
		}
	}
	public Text getOutput(){
		return output.item;
	}
	private void em_updateCurrentSymbol(){
		try{
			emText new_currentSymbol = new emText(new Text(20, 30, ("Current Symbol: " + tape[headPosition])));
			setCurrentSymbol(new_currentSymbol.item);
		}catch(Exception e){
			currentSymbol.item = null;
		}
	}
	public void setCurrentSymbol(Text em_currentSymbol){
		if(currentSymbol.item == null || !currentSymbol.item.equals(em_currentSymbol)){
			currentSymbol.item = em_currentSymbol;
			emTriggerUpdateTape("currentSymbol");
			emTriggerUpdateTape("Tape.currentSymbol");
		}
	}
	public Text getCurrentSymbol(){
		return currentSymbol.item;
	}

}
class MachineStates extends Group implements emDependent{
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public void add(emState a){
		picture.add(a);

	}

	public MachineStates(){
		super();

	
		Evaluator.addInstance(this);
}	


	public MachineStates registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		emTriggerUpdateMachineStates(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateMachineStates(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticMachineStates(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}

}
class Link extends Group implements emDependent{
	private int posX = 0;
	private int posY = 0;
	private int size = 50;
	@EDEN_DESCRIPTION(definition = "(posX * size)")
	private int offsetX = (posX * size);
	@EDEN_DESCRIPTION(definition = "(posY * size)")
	private int offsetY = (posY * size);
	private State from = null;
	private State to = null;
	@EDEN_DESCRIPTION(definition = "null")
	private emLine l1 = new emLine(null);
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public Link(){
		super();

	
		Evaluator.addInstance(this);
}	

	public Link(State a, State b){
		super();
		from = a;
		to = b;

	
		Evaluator.addInstance(this);
}	


	public Link registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		emTriggerUpdateLink(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateLink(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticLink(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	private void setPosX(int em_posX){
		if(posX != em_posX){
			posX = em_posX;
			em_updateOffsetX();
			emTriggerUpdateLink("posX");
			emTriggerUpdateLink("Link.posX");
		}
	}
	private void setPosY(int em_posY){
		if(posY != em_posY){
			posY = em_posY;
			em_updateOffsetY();
			emTriggerUpdateLink("posY");
			emTriggerUpdateLink("Link.posY");
		}
	}
	private void setSize(int em_size){
		if(size != em_size){
			size = em_size;
			em_updateOffsetX();
			em_updateOffsetY();
			emTriggerUpdateLink("size");
			emTriggerUpdateLink("Link.size");
		}
	}
	private void em_updateOffsetX(){
		try{
			int new_offsetX = (posX * size);
			setOffsetX(new_offsetX);
		}catch(Exception e){
			offsetX = 0;
		}
	}
	private void setOffsetX(int em_offsetX){
		if(offsetX != em_offsetX){
			offsetX = em_offsetX;
			emTriggerUpdateLink("offsetX");
			emTriggerUpdateLink("Link.offsetX");
		}
	}
	private void em_updateOffsetY(){
		try{
			int new_offsetY = (posY * size);
			setOffsetY(new_offsetY);
		}catch(Exception e){
			offsetY = 0;
		}
	}
	private void setOffsetY(int em_offsetY){
		if(offsetY != em_offsetY){
			offsetY = em_offsetY;
			emTriggerUpdateLink("offsetY");
			emTriggerUpdateLink("Link.offsetY");
		}
	}
	private void em_updateL1(){
		try{
			emLine new_l1 = new emLine(null);
			setL1(new_l1.item);
		}catch(Exception e){
			l1.item = null;
		}
	}
	private void setL1(Line em_l1){
		if(l1.item == null || !l1.item.equals(em_l1)){
			l1.item = em_l1;
			emTriggerUpdateLink("l1");
			emTriggerUpdateLink("Link.l1");
		}
	}

}
class State extends Group implements emDependent{
	private int id = (0 - 1);
	private int size = 50;
	@EDEN_DESCRIPTION(definition = "((id * size) * 2)")
	private int x = ((id * size) * 2);
	@EDEN_DESCRIPTION(definition = "(((int) (Math.floor(((id * size) / 200)))) + size)")
	private int y = (((int) (Math.floor(((id * size) / 200)))) + size);
	@EDEN_DESCRIPTION(definition = "new Arc(x, y, size, size, 0, 360)")
	private emArc a1 = new emArc(new Arc(x, y, size, size, 0, 360));
	@EDEN_DESCRIPTION(definition = "new Text((x + (size / 2)), (y + (size / 2)), toString())")
	private emText t1 = new emText(new Text((x + (size / 2)), (y + (size / 2)), toString()));
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public State(){
		super();

	
		Evaluator.addInstance(this);
}	

	public State(int i){
		super();
		picture.add(a1);
		picture.add(t1);
		setId(i);

	
		Evaluator.addInstance(this);
}	

	public String toString(){
		return String.valueOf(id);

	}


	public State registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		emTriggerUpdateState(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateState(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticState(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	private void setId(int em_id){
		if(id != em_id){
			id = em_id;
			em_updateX();
			em_updateY();
			emTriggerUpdateState("id");
			emTriggerUpdateState("State.id");
		}
	}
	private void setSize(int em_size){
		if(size != em_size){
			size = em_size;
			em_updateX();
			em_updateY();
			em_updateA1();
			em_updateT1();
			emTriggerUpdateState("size");
			emTriggerUpdateState("State.size");
		}
	}
	private void em_updateX(){
		try{
			int new_x = ((id * size) * 2);
			setX(new_x);
		}catch(Exception e){
			x = 0;
		}
	}
	public void setX(int em_x){
		if(x != em_x){
			x = em_x;
			em_updateA1();
			em_updateT1();
			emTriggerUpdateState("x");
			emTriggerUpdateState("State.x");
		}
	}
	public int getX(){
		return x;
	}
	private void em_updateY(){
		try{
			int new_y = (((int) (Math.floor(((id * size) / 200)))) + size);
			setY(new_y);
		}catch(Exception e){
			y = 0;
		}
	}
	public void setY(int em_y){
		if(y != em_y){
			y = em_y;
			em_updateA1();
			em_updateT1();
			emTriggerUpdateState("y");
			emTriggerUpdateState("State.y");
		}
	}
	public int getY(){
		return y;
	}
	private void em_updateA1(){
		try{
			emArc new_a1 = new emArc(new Arc(x, y, size, size, 0, 360));
			setA1(new_a1.item);
		}catch(Exception e){
			a1.item = null;
		}
	}
	private void setA1(Arc em_a1){
		if(a1.item == null || !a1.item.equals(em_a1)){
			a1.item = em_a1;
			emTriggerUpdateState("a1");
			emTriggerUpdateState("State.a1");
		}
	}
	private void em_updateT1(){
		try{
			emText new_t1 = new emText(new Text((x + (size / 2)), (y + (size / 2)), toString()));
			setT1(new_t1.item);
		}catch(Exception e){
			t1.item = null;
		}
	}
	private void setT1(Text em_t1){
		if(t1.item == null || !t1.item.equals(em_t1)){
			t1.item = em_t1;
			emTriggerUpdateState("t1");
			emTriggerUpdateState("State.t1");
		}
	}

}

//Interface for classes to send / receive variable update events
interface emDependent{
	public void emUpdate(String property);
	public void emUpdate(Object obj, String property);
}

//Wrapper classes for all objects who are the results of dependencies
class emTape extends emGroup{
	public Tape item;

	public emTape (Tape obj){
		 super(obj);
		 item = obj;
	}

	public emTape (){}
	public char readHead(){return item.readHead();}
	public void writeHead(char c){item.writeHead(c);}
	public  void  setTape(char[] obj){item.setTape(obj);}
	public char[] getTape(){return item.getTape();}
	public  void  setHeadPosition(int obj){item.setHeadPosition(obj);}
	public int getHeadPosition(){return item.getHeadPosition();}
	public  void  setOutput(Text obj){item.setOutput(obj);}
	public Text getOutput(){return item.getOutput();}
	public  void  setCurrentSymbol(Text obj){item.setCurrentSymbol(obj);}
	public Text getCurrentSymbol(){return item.getCurrentSymbol();}
}
class emGroup extends emShape{
	public Group item;

	public emGroup (Group obj){
		 super(obj);
		 item = obj;
	}

	public emGroup (){}
	public void draw(Graphics g){item.draw(g);}
	public ArrayList getShapes(){return item.getShapes();}
	public  void  setPicture(ArrayList obj){item.setPicture(obj);}
	public ArrayList getPicture(){return item.getPicture();}
}
class emShape extends Object{
	public Shape item;

	public emShape (Shape obj){
		 super();
		 item = obj;
	}

	public emShape (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
	public  void  setX1(int obj){item.setX1(obj);}
	public int getX1(){return item.getX1();}
	public  void  setX2(int obj){item.setX2(obj);}
	public int getX2(){return item.getX2();}
	public  void  setY1(int obj){item.setY1(obj);}
	public int getY1(){return item.getY1();}
	public  void  setY2(int obj){item.setY2(obj);}
	public int getY2(){return item.getY2();}
	public  void  setColor(Color obj){item.setColor(obj);}
	public Color getColor(){return item.getColor();}
}
class emMachineStates extends emGroup{
	public MachineStates item;

	public emMachineStates (MachineStates obj){
		 super(obj);
		 item = obj;
	}

	public emMachineStates (){}
	public void add(emState a){item.add(a);}
}
class emLink extends emGroup{
	public Link item;

	public emLink (Link obj){
		 super(obj);
		 item = obj;
	}

	public emLink (){}
}
class emState extends emGroup{
	public State item;

	public emState (State obj){
		 super(obj);
		 item = obj;
	}

	public emState (){}
	public String toString(){return item.toString();}
	public  void  setX(int obj){item.setX(obj);}
	public int getX(){return item.getX();}
	public  void  setY(int obj){item.setY(obj);}
	public int getY(){return item.getY();}
}
class emText extends emShape{
	public Text item;

	public emText (Text obj){
		 super(obj);
		 item = obj;
	}

	public emText (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
	public  void  setLabel(String obj){item.setLabel(obj);}
	public String getLabel(){return item.getLabel();}
}
class emLine extends emShape{
	public Line item;

	public emLine (Line obj){
		 super(obj);
		 item = obj;
	}

	public emLine (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
}
class emArc extends emShape{
	public Arc item;

	public emArc (Arc obj){
		 super(obj);
		 item = obj;
	}

	public emArc (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
	public  void  setStartAngle(int obj){item.setStartAngle(obj);}
	public int getStartAngle(){return item.getStartAngle();}
	public  void  setEndAngle(int obj){item.setEndAngle(obj);}
	public int getEndAngle(){return item.getEndAngle();}
}

//Annotation interface for dependency labelling
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface EDEN_DESCRIPTION {
	String definition();
}
