package dfatool.views.dialogs;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import dfatool.expressions.Expression;
import dfatool.expressions.ListExpression;
import dfatool.expressions.SetExpression;
import dfatool.expressions.TupleExpression;
import dfatool.parser.LanguageUtil;
import dfatool.strategy.elements.Atom;
import dfatool.strategy.elements.Description;
import dfatool.strategy.elements.patterns.ResourceAllocationDescription;
import dfatool.strategy.verification.ResourceAllocationAdherence;
import dfatool.strategy.verification.elements.EssentialComponent;

public class ResourceAllocationDescriptionCreationDialog extends Dialog{

	private Map<String,Expression> funUsers;
	private Map<String,Expression> funResources;
	private Map<String,Map<String,Expression>> acquireFunc; 
	private Map<String,Map<String,Expression>> releaseFunc; 
	private EssentialComponent ec;
	private Text usersText;
	private Text essentialComponentName;
	private Text resourcesText;
	private static final int cells = 8;
	private List listFuncUsers;
	private List listFuncResources;
	private List listFuncAcquire;
	private List listFuncRelease;
	private UnaryFunctionListener resourcesListener;
	private UnaryFunctionListener usersListener;
	private BinaryFunctionListener acquireListener;
	private BinaryFunctionListener releaseListener;
	
	private ResourceAllocationDescription rad;

	public ResourceAllocationDescriptionCreationDialog(IShellProvider parentShell) {
		super(parentShell);
		initMaps();
		parentShell.getShell().setText("Resource allocation description creation dialog");
	}
	
	@Override
	protected Control createDialogArea(Composite parent) {
		Composite composite = (Composite) super.createDialogArea(parent);
		GridLayout gLayout = new GridLayout(cells,true);
		composite.setSize(1000, 600);
		composite.setLayout(gLayout);
		label(composite, "Users");
		usersText = text(composite, cells-1);
		usersText.setSize(400, 20);
		label(composite, "Resources");
		resourcesText = text(composite, cells-1);
		resourcesText.setSize(400, 20);
		createCompositeFunUsers(composite);
		createCompositeFunResources(composite);
		createCompositeFunAcquire(composite);
		createCompositeFunRelease(composite);
		label(composite, "users(id)",cells/2);
		label(composite, "resources(id)",cells/2);
		listFuncUsers = list(composite);
		usersListener.setList(listFuncUsers);
		listFuncResources = list(composite);
		resourcesListener.setList(listFuncResources);
		label(composite, "acquire(idU,idR)",cells/2);
		label(composite, "release(idU,idR)",cells/2);
		listFuncAcquire = list(composite);
		acquireListener.setList(listFuncAcquire);
		listFuncRelease = list(composite);
		releaseListener.setList(listFuncRelease);
		return composite;
	}
	
	private void initMaps() {
		funUsers = new HashMap<String,Expression>();
		funResources = new HashMap<String,Expression>();
		acquireFunc = new HashMap<String,Map<String,Expression>>();
		releaseFunc = new HashMap<String,Map<String,Expression>>();
	}

	public void createCompositeFunUsers(Composite parent){
		label(parent,"Function users(id):");
		label(parent, "Atom name:");
		Text name = text(parent,1);
		label(parent, "Set:");
		Text function = text(parent,cells-5);
		usersListener = new UnaryFunctionListener(name, function, funUsers,"users");
		button(parent, "Add", usersListener);
	}
	
	public void createCompositeFunResources(Composite parent){
		label(parent,"Function resources(id):");
		label(parent, "Atom name:");
		Text name = text(parent,1);
		label(parent, "Seq:");
		Text function = text(parent,cells-5);
		resourcesListener = new UnaryFunctionListener(name, function, funResources, "resources");
		button(parent, "Add", resourcesListener);
	}
	
	public void createCompositeFunAcquire(Composite parent){
		label(parent,"Function acquire(idU,idR):");
		label(parent, "User atom name:");
		Text name1 = text(parent,1);
		label(parent, "Resource atom name:");
		Text name2 = text(parent,1);
		label(parent, "Tuple:");
		Text function = text(parent,cells-7);
		acquireListener = new BinaryFunctionListener(name1, name2, function, acquireFunc,"acquire");
		button(parent, "Add", acquireListener);
	}
	
	public void createCompositeFunRelease(Composite parent){
		label(parent,"Function release(idU,idR):");
		label(parent, "User atom name:");
		Text name1 = text(parent,1);
		label(parent, "Resource atom name:");
		Text name2 = text(parent,1);
		label(parent, "Tuple:");
		Text function = text(parent,cells-7);
		releaseListener = new BinaryFunctionListener(name1, name2, function, releaseFunc, "release");
		button(parent, "Add", releaseListener);
	}

	private List list(Composite parent) {
		int cells = this.cells/2;
		List list = new List(parent, SWT.MULTI);
		GridData gd = new GridData();
		gd.horizontalSpan = cells;
		gd.verticalSpan = cells;
		gd.verticalAlignment = SWT.FILL;
		gd.horizontalAlignment = SWT.FILL;
		list.setLayoutData(gd);
		return list;
	}
	
	private void button(Composite parent, String name, Listener listener){
		Button bt = new Button(parent, SWT.PUSH);
		bt.setText(name);
		bt.addListener(SWT.Selection, listener);
	}
	
	private void label(Composite parent, String label){
		label(parent, label, 1);
	}
	
	private void label(Composite parent, String label, int span){
		Label l = new Label(parent, SWT.NONE);
		l.setText(label);
		GridData gd = new GridData();
		gd.horizontalSpan = span;
		l.setLayoutData(gd);
	}
	
	private Text text(Composite parent, int span){
		Text t = new Text(parent, SWT.BORDER);
		t.setSize(400, 20);
		t.redraw();
		GridData gd = new GridData();
		gd.horizontalSpan = span;
		t.setLayoutData(gd);
		return t; 
	}
	
	@Override
	protected void okPressed() {
		try{
			rad = createResourceAllocationDescription();
			super.okPressed();
		}catch (Exception e){
			MessageDialog.openError(this.getParentShell(), "Error", e.getMessage());
		}finally{
			this.close();
		}
	}
	
	public ResourceAllocationDescription getResourceAllocationDescription(){
		return rad;
	}
	
	private void test() {
		usersText.setText("{ Phil.i , APhil.10 | i <- {0..9}}");
		resourcesText.setText("{ Fork.i | i <- {0..10}}");
	}
	
	private ResourceAllocationDescription createResourceAllocationDescription() {
		SetExpression users = (SetExpression) LanguageUtil.parseString(usersText.getText());
		SetExpression resources = (SetExpression) LanguageUtil.parseString(resourcesText.getText());
		return new ResourceAllocationDescription(users, resources, funUsers, funResources, acquireFunc, releaseFunc);
	}
	
	
	
	class UnaryFunctionListener implements Listener{

		private Text name, funcDescription;
		private Map<String,Expression> map;
		private List list;
		private String funcName;
		
		public UnaryFunctionListener(Text atomName, Text funcDescription, Map<String, Expression> funUsers, String funcName) {
			this.map = funUsers;
			this.funcDescription = funcDescription;
			this.name = atomName;
			this.funcName = funcName;
		}
		
		public void setList(List list) {
			this.list = list;
		}
		
		@Override
		public void handleEvent(Event event) {
			map.put(name.getText(), LanguageUtil.parseString(funcDescription.getText()));
			updateList();
		}
		
		protected void updateList(){
			list.removeAll();
			for(String name : map.keySet())
				list.add(funcName+"("+name+".id) = "+map.get(name).toConcreteSyntax());
			list.redraw();
		}
		
	}
	
	class BinaryFunctionListener implements Listener{

		private Text name1, name2, funcDescription;
		private Map<String,Map<String,Expression>> map;
		private List list;
		private String funcName;
		
		public BinaryFunctionListener(Text name1, Text name2, Text funcDescription, Map<String,Map<String,Expression>> map, String funcName) {
			this.map = map;
			this.funcDescription = funcDescription;
			this.name1 = name1;
			this.name2 = name2;
			this.funcName = funcName;
		}
		
		@Override
		public void handleEvent(Event event) {
			Map<String, Expression> m = map.get(name1.getText());
			if(m == null){
				m = new HashMap<String,Expression>();
				map.put(name1.getText(), m);
			}
			m.put(name2.getText(), (Expression) LanguageUtil.parseString(funcDescription.getText()));
			updateList();
		}
		
		protected void updateList(){
			list.removeAll();
			for(String name1 : map.keySet())
				for(String name2 : map.get(name1).keySet())
					list.add(funcName+"("+name1+".idU,"+name2+".idR) = "+map.get(name1).get(name2).toConcreteSyntax());
			list.redraw();
		}
		
		public void setList(List list) {
			this.list = list;
		}
		
	}
	
	public static void main(String[] args) {
		
	}
	


}
