package de.tu_darmstadt.tk.SmartHomeNetworkSim.control;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Connection;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Model;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketCollector;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Protocol;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.configuration.NetworkTreeNodeStatus;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.configuration.SelectionModel;

/**
 * Controller for manipulation of the network model with methods like  
 * 
 *
 * @author Andreas T. Meyer-Berg
 */
public class NetworkController {

	/**
	 * Model which will be manipulated
	 */
	private Model model;
	/**
	 * Controller which can be use
	 */
	private Controller controller;
	/**
	 * NetworkTreeSettings Controller
	 */
	private NetworkTreeSettingsController networkTreeSettings;
	/**
	 * Packet Capture Controller
	 */
	private PacketCaptureController captureController;
	/**
	 * ExampleAnomalyController
	 */
	private ExampleAnomalyController anomalyController;
	/**
	 * Creates a new NetworkController, which may manipulate the given model and use the controller
	 * @param model Model which can be manipulated
	 * @param controller main controller for updates etc
	 */
	public NetworkController(Model model, Controller controller) {
		this.model = model;
		this.controller = controller;
		networkTreeSettings = controller.getSettingsController().getNetworkTreeSettingsController();
		captureController = controller.getSimulationController().getPacketCaptureController();
		anomalyController = new ExampleAnomalyController(controller);
	}

	/**
	 * Validate all device positions, move all devices into the bounds, if they are outside the visualization
	 */
	public void validateDevicePosition() {
		// Update all device positions
		for (SmartDevice d : model.getDevices()) {
			d.setX(controller.getSettingsController().scalePos(d.getX(), 1.0, controller.getSettingsController().getWidth()));
			d.setY(controller.getSettingsController().scalePos(d.getY(), 1.0, controller.getSettingsController().getHeight()));
			d.setZ(controller.getSettingsController().scalePos(d.getZ(), 1.0, controller.getSettingsController().getDepth()));
		}
	}

	/**
	 * Adds SmartDevice to the Model and verifies that it is inside the model
	 * bounds
	 * 
	 * @param sd
	 *            SmartDevice which should be added to the model
	 */
	public void addSmartDevice(SmartDevice sd) {
		if (model.getDevices().contains(sd))
			return;
		model.addDevices(sd);
		// validate Position
		sd.setX(controller.getSettingsController().scalePos(sd.getX(), 1.0, controller.getSettingsController().getWidth()));
		sd.setY(controller.getSettingsController().scalePos(sd.getY(), 1.0, controller.getSettingsController().getHeight()));
		sd.setZ(controller.getSettingsController().scalePos(sd.getZ(), 1.0, controller.getSettingsController().getDepth()));
	}

	/**
	 * Creates a new SmartDevice at the given Position. The Device is moved
	 * into the model bounds, if the position is outside the bounds
	 * 
	 * @param name
	 *            name of the smartDevice
	 * @param x_pos
	 *            position on the x-Axis
	 * @param y_pos
	 *            position on the y-Axis
	 * @param z_pos
	 *            position on the z-Axis
	 */
	public SmartDevice createSmartDevice(String name, int x_pos, int y_pos, int z_pos) {
		SmartDevice sd = new SmartDevice(name);
		sd.setX(controller.getSettingsController().scalePos(x_pos, 1.0, controller.getSettingsController().getWidth()));
		sd.setY(controller.getSettingsController().scalePos(y_pos, 1.0, controller.getSettingsController().getHeight()));
		sd.setZ(controller.getSettingsController().scalePos(z_pos, 1.0, controller.getSettingsController().getDepth()));
		model.addDevices(sd);
		return sd;
	}

	/**
	 * Deletes the given SmartDevice toDelete, removes it from its links and
	 * connections.
	 * 
	 * @param toDelete
	 *            the SmartDevice to delete
	 */
	public void deleteSmartDevice(SmartDevice toDelete) {
		if (toDelete == null)
			return;
		// Remove from Collectors
		PacketCaptureController captureController = controller.getSimulationController().getPacketCaptureController();
		for(PacketCollector collector:captureController.getPacketCollectors()){
			if(collector.getDevices().contains(toDelete)){
				captureController.removeDeviceFromCollector(collector, toDelete);
			}
		}
		
		// Delete Connections
		for (Port p : toDelete.getPorts()) {
			//Skip ports that are not connected
			if(p.getConnection()==null)
				continue;
			removeDeviceFromConnectionAndProtocol(p, p.getConnection());
		}
		
		// Remove from Links
		LinkedList<Link> links = new LinkedList<Link>(toDelete.getLinks());
		for (Link link : links)
			removeSmartDeviceFromLink(toDelete, link);
		links.clear();
		// Remove Links from Device
		toDelete.getLinks().clear();
				
		//Remove all ports from the device
		toDelete.getPorts().clear();
		
		//Remove from network Tree
		networkTreeSettings.removeStatusOfObject(toDelete);
		model.getDevices().remove(toDelete);
	}
	/**
	 * Returns smartDevices of the model, which are not hidden
	 * @return all SmartDevices which are not hidden
	 */
	public Collection<SmartDevice> getVisibleSmartDevices(){
		LinkedList<SmartDevice> devices = new LinkedList<SmartDevice>(model.getDevices());
		devices.removeIf(c->!controller.getSettingsController().getNetworkTreeSettingsController().isVisible(c));
		return devices;
	}
	/**
	 * Returns smartDevices of the model
	 * @return all SmartDevices of the model
	 */
	public Collection<SmartDevice> getSmartDevices(){
		return model.getDevices();
	}
	/**
	 * Removes the SmartDevice from the given Link
	 * 
	 * @param toRemove the Device that should be removed from the link
	 * @param link the Link, which contains the SmartDevice
	 */
	public void removeSmartDeviceFromLink(SmartDevice toRemove, Link link) {
		if(link != null){
			link.removeDevice(toRemove);
			if(link.getDevices().size()==0)
				deleteLink(link);
		}
		if(toRemove!=null)
			toRemove.removeLink(link);
	}

	/**
	 * Moves the SmartDevice device to the specified location, if it exists
	 * 
	 * @param device
	 *            the device to move
	 * @param x
	 *            new x position
	 * @param y
	 *            new y position
	 * @param z
	 *            new z position
	 */
	public void moveSmartDevice(SmartDevice device, int x, int y, int z) {
		device.setX(x);
		device.setY(y);
		device.setZ(z);
	
	}

	/**
	 * Adds Link to the model
	 * @param link link to add
	 */
	public void addLink(Link link){
		if(link!=null && !model.getConnectionNetworks().contains(link))
			model.addConnectionNetwork(link);
	}

	/**
	 * Removes Link from the Model
	 * @param link link to remove
	 */
	public void removeLink(Link link){
		model.getConnectionNetworks().remove(link);
	}

	/**
	 * Return visible links of the model
	 * @return visible link
	 */
	public Collection<Link> getVisibleLinks(){
		LinkedList<Link> links = new LinkedList<Link>(model.getConnectionNetworks());
		links.removeIf(c->!controller.getSettingsController().getNetworkTreeSettingsController().isVisible(c));
		return links;
	}
	
	/**
	 * Return links of the model
	 * @return link
	 */
	public Collection<Link> getLinks(){
		return model.getConnectionNetworks();
	}

	/**
	 * Add Connection to the model
	 * @param connection connection to be added
	 */
	public void addConnection(Connection connection){
		if(connection!=null && !getConnections().contains(connection))
			model.addConnection(connection);
	}

	/**
	 * Remove the connection from the model
	 * @param connection connection to be removed
	 */
	public void removeConnection(Connection connection){
		model.getConnections().remove(connection);
	}

	/**
	 * Returns visible connections of the model
	 * @return visible connections
	 */
	public Collection<Connection> getVisibleConnections(){
		LinkedList<Connection> links = new LinkedList<Connection>(model.getConnections());
		links.removeIf(c->!controller.getSettingsController().getNetworkTreeSettingsController().isVisible(c));
		return links;
	}
	
	/**
	 * Returns connections of the model
	 * @return connections
	 */
	public Collection<Connection> getConnections(){
		return model.getConnections();
	}
	
	/**
	 * Adds the smartDevice to the link
	 * @param link link to be added to the device
	 * @param smartDevice device to be added to the link
	 */
	public void addLinkToDevice(Link link, SmartDevice smartDevice) {
		if(link == null || smartDevice == null)return;
		
		if(!link.getDevices().contains(smartDevice)){
			link.addDevice(smartDevice);
		}
		
		if(!smartDevice.getLinks().contains(link)){
			smartDevice.addLink(link);
		}
		
	}

	/**
	 * Remove the smartDevice from the link
	 * @param link link, the device should be removed from
	 * @param smartDevice device which should be removed
	 */
	public void removeLinkFromDevice(Link link, SmartDevice smartDevice) {
		if(smartDevice!=null)
			smartDevice.removeLink(link);
		if(link!=null){
			link.removeDevice(smartDevice);
			if(link.getDevices().size()==0)
				deleteLink(link);
		}
	}

	/**
	 * Changes Roles of the device to the newRole, returns true, if the role was successfully changed, false if not.
	 * If false is returned, the device will no longer be part of this connection.
	 * 
	 * @param protocol protocol which should be edited
	 * @param con Connection, which contains the protocol
	 * @param device device which should be added
	 * @param newRole new role of the device
	 * @return true if new role was set, false if not
	 */
	public boolean changeRoleOfDevice(Protocol protocol, Connection con, Port device, int newRole){
		if(newRole < 0 || newRole >= protocol.getNumberOfRoles()){
			protocol.removeDevice(device);
			removeDeviceFromConnectionAndProtocol(device, con);
			return false;
		} else if(protocol.getDevicesWithRole(newRole).contains(device)){
			if(!con.getParticipants().contains(device))
				con.addSmartDevice(device);
			if(device.getConnection()!=con)
				device.setConnection(con);
			return true;
		}
		else{
			protocol.removeDevice(device);
			boolean added = protocol.addDeviceOfRole(device, newRole);
			if(added){
				if(!con.getParticipants().contains(device))
					con.addSmartDevice(device);
				if(device.getConnection()!=con)
					device.setConnection(con);
				return true;
			}else{
				if(con.getParticipants().contains(device))
					con.removeSmartDevice(device);
				if(device.getConnection()!=null)
					device.setConnection(null);
				return false;
			}
		}
	}

	/**
	 * Removes Device p from the Connection and Protocol
	 * @param p Port/Device to remove
	 * @param connection connection, which should remove the device
	 */
	public void removeDeviceFromConnectionAndProtocol(Port p, Connection connection){
		if(connection != null){
			connection.removeSmartDevice(p);
			//TODO: Protocol ?
			if(connection.getProtocol()!=null){
				connection.getProtocol().removeDevice(p);
				if(connection.getParticipants().size() == 0)
					deleteConnection(connection);
			}
		}
		if(p!=null && p.getConnection() == connection)
			p.setConnection(null);
	}
	
	/**
	 * Removes Device p from the Connection and Protocol
	 * @param p Port/Device to remove
	 * @param connection connection, which should remove the device
	 */
	public void removeDeviceFromConnection(Port p, Connection connection){
		if(connection != null){
			connection.removeSmartDevice(p);
			p.setConnection(null);
			if(connection.getParticipants().isEmpty())
				deleteConnection(connection);
		}
		if(p != connection)
			p.setConnection(null);
	}

	/**
	 * Adds Device p to the connection with the specified role
	 * @param p Port/Device to be added
	 * @param connection Connection
	 * @param role new role of the device (See {@link Protocol} Roles)
	 * @return true, if the device was added
	 */
	public boolean addDeviceToConnectionAndProtocol(Port p, Connection connection, int role){
		if(connection.getProtocol().getDevicesWithRole(role).contains(p) || connection.getProtocol().addDeviceOfRole(p, role)){
			//If port already has the role, or it could be assigned - just check the fields
			if(!connection.getParticipants().contains(p))
				connection.addSmartDevice(p);
			if(p.getConnection()!=connection)
				p.setConnection(connection);
			if(!p.getOwner().getPorts().contains(p))
				p.getOwner().addPort(p);
			return true;
		}else {
			//Device could not be added -> Remove
			if(p.getConnection()==connection)
				p.setConnection(null);
			if(connection.getParticipants().contains(p))
				connection.removeSmartDevice(p);
			if(connection.getProtocol().getDevices().contains(p))
				connection.getProtocol().removeDevice(p);
			return false;
		}
	}
	
	/**
	 * Adds Device p to the connection
	 * @param p Port/Device to be added
	 * @param connection Connection
	 */
	public void addDeviceToConnection(Port p, Connection connection){
		if(p==null || connection == null)
			return;
		if(!connection.getParticipants().contains(p))
			connection.addSmartDevice(p);
		p.setConnection(connection);
	}

	/**
	 * Changes the link of the given connection to the new link. Returns true if it was successfully changed, false if it could not be changed.
	 * @param connection connection which should be edited
	 * @param link new link
	 * @return true on successful change, false on failure and restore
	 */
	public boolean changeLinkOfConnection(Connection connection, Link link) {
		if(connection !=null && link != null){
			addConnectionToLink(connection, link);
			return true;
		}else{
			return false;
		}
	}

	/**
	 * Adds the given connection to the link
	 * @param connection connection to be added
	 * @param link link the connection should be added to
	 */
	public void addConnectionToLink(Connection connection, Link link) {
		if(connection == null || link == null)return;
		/**
		 * Remove connection from Old Link
		 */
		if(connection.getLink()!=null)
			removeConnectionFromLink(connection, connection.getLink());
		/**
		 * Add Connection to new Link
		 */
		connection.setLink(link);
		if(!link.getConnections().contains(connection))
			link.addConnection(connection);
		/**
		 * 
		 */
		for(Port p:connection.getParticipants()){
			if(p!=null && !link.getDevices().contains(p.getOwner())){
				addLinkToDevice(link, p.getOwner());
			}
		}
	}

	/**
	 * Changes the type of the connection to the new Type and updates all references
	 * @param connection connection to be updated
	 * @param newConnectionClass class of new type
	 * @return newly created connection
	 */
	public Connection changeConnectionType(Connection connection, Class<? extends Connection> newConnectionClass) {
		
		Connection newCon = null;
		try{
			newCon = newConnectionClass.newInstance();
			copyNetworkTreeStatus(connection, newCon);
			newCon.setProtocol(connection.getProtocol());
			newCon.setStatus(connection.getStatus());
			newCon.setPacketLossProbability(connection.getPacketLossProbability());
			newCon.setName(connection.getName());
			if(getConnections().contains(connection)){
				removeConnection(connection);
				addConnection(newCon);	
			}
			addConnectionToLink(newCon, connection.getLink());
			connection.setProtocol(null);
			for (Iterator<Port> p = connection.getParticipants().iterator(); p.hasNext();) {
				Port type = (Port) p.next();
				removeDeviceFromConnection(type, connection);
				addDeviceToConnection(type, newCon);
				
			}
		}catch(Exception e){
			System.out.println("Error while changing protocol: "+e.toString());
			/**
			 * Restore old connection on Failure
			 */
			if(newCon != null){
				if(getConnections().contains(newCon)){
					removeConnection(newCon);
					addConnection(connection);	
				}
				if(newCon.getProtocol()!=null){
					connection.setProtocol(newCon.getProtocol());
					newCon.setProtocol(null);
				}
				if(newCon.getLink()!=null)
					newCon.getLink().removeConnection(newCon);
				newCon.setLink(null);
				for (Iterator<Port> p = connection.getParticipants().iterator(); p.hasNext();) {
					Port type = (Port) p.next();
					if(type.getConnection()!=connection)
						type.setConnection(connection);
					newCon.removeSmartDevice(type);
				}
			}
			return null;
		}
		
		controller.getSettingsController().getConfigurationManager().getSelectionModel().clickedConnection.clear();
		connection.setProtocol(null);
		deleteConnection(connection);
		
		controller.notifyObservers();
		
		return newCon;
	}

	/**
	 * Deletes the network model, removes all Devices, Connections and Links
	 */
	public void deleteNetworkModel(){
		/**
		 * Devices which should be deleted
		 */
		LinkedList<SmartDevice> devicesToDelete = new LinkedList<SmartDevice>(model.getDevices());
		for(SmartDevice d: devicesToDelete)
			deleteSmartDevice(d);
		devicesToDelete.clear();
		/**
		 * Connections which should be deleted
		 */
		LinkedList<Connection> connectionsToDelete = new LinkedList<Connection>(model.getConnections());
		for(Connection c: connectionsToDelete)
			deleteConnection(c);
		connectionsToDelete.clear();
		/**
		 * Links which should be deleted
		 */
		LinkedList<Link> linksToDelete = new LinkedList<Link>(model.getConnectionNetworks());
		for(Link l: model.getConnectionNetworks())
			deleteLink(l);
		linksToDelete.clear();
		
		/**
		 * Delete Collectors
		 */
		LinkedList<PacketCollector> collectors = new LinkedList<PacketCollector>(captureController.getPacketCollectors());
		for(PacketCollector p:collectors){
			captureController.removePacketCollector(p);
		}
		
		/**
		 * Clear event queue
		 */
		
		/**
		 * Update the GUI
		 */
		controller.notifyObservers();
	}

	/**
	 * Deletes the Connection c and all references
	 * @param c Connection to be deleted
	 */
	public void deleteConnection(Connection c) {
		if(c == null)
			return;
		c.setName("Deleted");
		LinkedList<Port> ports = new LinkedList<Port>(c.getParticipants());
		for(Port p:ports)
			removeDeviceFromConnectionAndProtocol(p, c);
		ports.clear();
		removeConnectionFromLink(c, c.getLink());
		c.setStatus(Connection.TERMINATED);
		networkTreeSettings.removeStatusOfObject(c);
		removeConnection(c);
	}

	/**
	 * Deletes Link 'toDelete' and all references
	 * @param toDelete Link to be deleted
	 */
	public void deleteLink(Link toDelete) {
		if(toDelete==null)return;
		LinkedList<SmartDevice> devices = new LinkedList<SmartDevice>(toDelete.getDevices());
		for(SmartDevice d : devices)
			removeLinkFromDevice(toDelete, d);
		devices.clear();
		LinkedList<Connection> connections = new LinkedList<Connection>(toDelete.getConnections());
		for(Connection c:connections)
			removeConnectionFromLink(c,toDelete);
		connections.clear();
		toDelete.getPackets().clear();
		/**
		 * Remove Link Color
		 */
		controller.getSettingsController().getLinkColors().removeLink(toDelete);
		networkTreeSettings.removeStatusOfObject(toDelete);
		/**
		 * Remove from Collectors
		 */
		PacketCaptureController captureController = controller.getSimulationController().getPacketCaptureController();
		for(PacketCollector collector:captureController.getPacketCollectors()){
			if(collector.getLinks().contains(toDelete)){
				captureController.removeLinkFromCollector(collector, toDelete);
			}
		}
		/**
		 * Remove Link from model
		 */
		removeLink(toDelete);
	}

	/**
	 * Removes Connection from Link
	 * @param c Connection to be removed
	 * @param l Link to be removed
	 */
	public void removeConnectionFromLink(Connection c, Link l) {
		if(c!=null && c.getLink()==l){
			c.setLink(null);
		}
		if(l!=null){
			l.removeConnection(c);		
		}
	}

	/**
	 * Changes the type of the link to new type, specified by the given Link-class
	 * @param oldLink oldLink, whose attributes will b copied to the new Link 
	 * @param newType Type/Class of the new Link
	 * @return newly created Link, null on failure/error
	 */
	public Link changeLinkType(Link oldLink, Class<? extends Link> newType) {
		if(newType == null)
			return null;
		/**
		 * New Link which was created
		 */
		Link newLink = null;
		try{
			newLink = newType.newInstance();
		}catch(Exception e){
			return null;
		}
		if (newLink == null || !(newLink instanceof Link)) {
			return null;
		}else {
			//Update Link Color
			LinkColorController linkColor = controller.getSettingsController().getLinkColors();
			linkColor.setColorOfLink(newLink, linkColor.getColorOfLink(oldLink).getRight());
			copyNetworkTreeStatus(oldLink, newLink);
			//Update Collectors
			PacketCaptureController captureController = controller.getSimulationController().getPacketCaptureController();
			for(PacketCollector collector:captureController.getPacketCollectors()){
				if(collector.getLinks().contains(oldLink)){
					captureController.removeLinkFromCollector(collector, oldLink);
					captureController.addLinkToCollector(collector, newLink);
				}
			}
			// Set old Name
			newLink.setName(oldLink.getName());
			
			// Add to Model
			if(getLinks().contains(oldLink)){
				removeLink(oldLink);
				addLink(newLink);
			}
			
			//Connection to the new Link
			for(Connection c: new LinkedList<Connection>(oldLink.getConnections())){
				addConnectionToLink(c, newLink);
			}
			// Add devices to the new Link
			LinkedList<SmartDevice> devices= new LinkedList<>(oldLink.getDevices());
			for(SmartDevice device:devices){
				removeLinkFromDevice(oldLink, device);
				addLinkToDevice(newLink, device);
			}
			return newLink;
		}
	}
	
	/**
	 * Adds status of the old Object to the new Object
	 * @param oldObject old object, whose status should be copied
	 * @param newObject new object, which should get the new status
	 */
	private void copyNetworkTreeStatus(Object oldObject, Object newObject){
		NetworkTreeNodeStatus oldStatus = networkTreeSettings.getStatusOfObject(oldObject);
		NetworkTreeNodeStatus newStatus = new NetworkTreeNodeStatus(newObject);
		newStatus.setExpanded(oldStatus.isExpanded());
		newStatus.setVisible(oldStatus.isVisible());
		networkTreeSettings.addStatusOfObject(newObject, newStatus);
	}
	
	/**
	 * Changes the Type of the SmartDevice
	 * @param old old Device which should be 
	 * @param newClass new Class of the SmartDevice
	 * @return new SmartDevice, null on failure
	 */
	public SmartDevice changeDeviceType(SmartDevice old, Class<? extends SmartDevice> newClass){
		//Compile new SmartDevice
		if(newClass == null)
			return null;
		/**
		 * New Link which was created
		 */
		SmartDevice newDevice = null;
		try{
			newDevice = newClass.newInstance();
		}catch(Exception e){
			return null;
		}
		if (newDevice == null || !(newDevice instanceof SmartDevice)) {
			return null;
		}else {
			// Update base informations
			newDevice.setName(old.getName());
			old.setName("Deleted");
			newDevice.setX(old.getX());
			newDevice.setY(old.getY());
			newDevice.setZ(old.getZ());
			
			//Update Packet Collectors
			PacketCaptureController captureController = controller.getSimulationController().getPacketCaptureController();
			for(PacketCollector collector:captureController.getPacketCollectors()){
				if(collector.getDevices().contains(old)){
					captureController.removeDeviceFromCollector(collector, newDevice);
					captureController.addDeviceToCollector(collector, newDevice);
				}
			}
			
			//Update all references
			LinkedList<Link> links = new LinkedList<Link>(old.getLinks());
			for(Link l: links){
				addLinkToDevice(l, newDevice);
				removeLinkFromDevice(l, old);
			}
			LinkedList<Port> ports = new LinkedList<Port>(old.getPorts());
			for(Port p:ports){
				p.setOwner(newDevice);
				newDevice.addPort(p);
				old.removePort(p);
			}
			
			SelectionModel selectionModel = controller.getSettingsController().getConfigurationManager().getSelectionModel();
			if(selectionModel.selectedDevices.contains(old)){
				selectionModel.selectedDevices.add(newDevice);
				selectionModel.selectedDevices.remove(old);
			}			
			if(selectionModel.selectedDevicesDrag.contains(old)){
				selectionModel.selectedDevicesDrag.add(newDevice);
				selectionModel.selectedDevicesDrag.remove(old);
			}
			
			//Update Colors tree status ?
			copyNetworkTreeStatus(old, newDevice);
			
			//Remove and add Device
			deleteSmartDevice(old);
			addSmartDevice(newDevice);
			return newDevice;
		}
	}

	/**
	 * Returns the AnomalyController, which can be used to insert anomalies into the network model
	 * @return Anomaly Controller
	 */
	public ExampleAnomalyController getAnomalyController() {
		return anomalyController;
	}
}
