package org.reldb.dbrowser.ui.content.rev;

import java.util.Vector;

import org.eclipse.swt.graphics.Point;
import org.reldb.rel.client.Attribute;
import org.reldb.rel.client.Heading;
import org.reldb.rel.client.Tuple;
import org.reldb.rel.client.Tuples;
import org.reldb.rel.client.Value;

public abstract class Operator extends Visualiser {

	private int lastSide = Parameter.EASTTOWEST;

	private String kind;

	private java.util.Vector<Parameter> parameters = new java.util.Vector<Parameter>();

	protected Operator(Model model, String id, String kind, int xpos, int ypos) {
		super(model, id, kind, xpos, ypos);
		this.kind = kind;
		btnEdit.dispose();
		pack();
	}

	public String getKind() {
		return kind;
	}

	public Parameter getParameter(int parameterNumber) {
		return parameters.get(parameterNumber);
	}

	private String getQueryForParameter(int parameterNumber, boolean allowParentheses) {
		Parameter parameter = parameters.get(parameterNumber);
		Argument argument = parameter.getArgument();
		if (argument == null) {
			System.out.println("Operator: argument for parameter " + parameterNumber + " in operator " + toString() + " is null!");
			return null;
		}
		Visualiser operand = argument.getOperand();
		if (operand == null) {
			System.out.println("Operator: operand for parameter " + parameterNumber + " in operator " + toString() + " is null!");
			return null;
		}
		String query = operand.getQuery();
		if (query == null) {
			System.out.println("Operator: query for parameter " + parameterNumber + " in operator " + toString() + " is null!");
			return null;
		}		
		if (allowParentheses && operand instanceof Operator)
			return "(" + query + ")";
		return query;
	}

	public String getQueryForParameterUnparenthesised(int parameterNumber) {
		return getQueryForParameter(parameterNumber, false);
	}

	public String getQueryForParameter(int parameterNumber) {
		return getQueryForParameter(parameterNumber, true);
	}

	public Heading getHeadingOfParameter(int parameterNumber) {
		String query = getQueryForParameter(parameterNumber);
		if (query == null)
			return null;
		Value returned = getDatabase().evaluate(query);
		if (returned instanceof Tuples) {
			Tuples tuples = (Tuples) returned;
			return tuples.getHeading();
		}
		return null;
	}

	public Vector<String> getAttributeNamesOfParameter(int parameterNumber) {
		String query = getQueryForParameter(parameterNumber);
		if (query == null)
			return null;
		Value returned = getDatabase().evaluate(query);
		Vector<String> output = new Vector<String>();
		if (returned instanceof Tuples) {
			Heading heading = ((Tuples) returned).getHeading();
			for (Attribute attribute : heading.toArray())
				output.add(attribute.getName());
		} else if (returned instanceof Tuple) {
			Tuple tuple = (Tuple) returned;
			for (int index = 0; index < tuple.getAttributeCount(); index++)
				output.add(tuple.getAttributeName(index));
		}
		return output;
	}

	public String toString() {
		return "Operator " + getTitle() + " (" + getID() + ")";
	}

	protected void disconnect() {
		for (Parameter parameter : parameters)
			parameter.getArgument().setOperand(null);
		super.disconnect();
	}

	protected void delete() {
		disconnect();
		for (Parameter parameter : parameters)
			parameter.dispose();
		parameters.clear();
		getDatabase().removeQuery(getID());
		super.delete();
	}

	public boolean isQueryable() {
		for (Parameter parameter : parameters)
			if (parameter.getArgument().isVisible() && parameter.getArgument().getOperand().getQuery() == null)
				return false;
		return true;
	}

	public void verify() {
		super.verify();
		notifyArgumentChanged();
	}

	private String cachedQuery = null;

	private void notifyArgumentChanged() {
		if (isQueryable()) {
			setReadyColour();
			btnInfo.setEnabled(true);
			btnRun.setEnabled(true);
			String query = getQuery();
			if (cachedQuery == null || query.compareTo(cachedQuery) != 0) {
				notifyArgumentChanged(true);
				cachedQuery = query;
			}
		} else {
			setWarningColour();
			btnInfo.setEnabled(false);
			btnRun.setEnabled(false);
			if (cachedQuery != null) {
				notifyArgumentChanged(false);
				cachedQuery = null;
			}
		}
	}

	/**
	 * Override to be notified that a parameter's argument has changed, with
	 * identification as to whether it's queryable or not.
	 */
	protected void notifyArgumentChanged(boolean queryable) {
	}

	protected Parameter addParameter(String name) {
		Parameter p = new Parameter(this, name, parameters.size(), lastSide);
		lastSide = (lastSide == Parameter.EASTTOWEST) ? Parameter.WESTTOEAST : Parameter.EASTTOWEST;
		parameters.add(p);
		new Argument(p);
		return p;
	}

	/** Return number of parameters. */
	public int getParameterCount() {
		return parameters.size();
	}

	/** Get connections to this Op as a relation in Tutorial D syntax. */
	private String getConnections() {
		String out = "RELATION {parameter INT, Name CHAR} {";
		for (int i = 0; i < getParameterCount(); i++) {
			Parameter parameter = getParameter(i);
			if (parameter.getArgument() != null) {
				if (i > 0)
					out += ", ";
				out += " tuple {";
				out += "parameter " + parameter.getNumber() + ", ";
				out += "Name '" + parameter.getArgument().getOperand().getID() + "'";
				out += "}";
			}
		}
		out += "   } ";
		return out;
	}

	protected void movement() {
		super.movement();
		if (parameters != null)
			for (Parameter parameter : parameters)
				parameter.redraw();
	}

	protected void visualiserMoved() {
		Point location = getLocation();
		getDatabase().updateQueryPosition(getID(), location.x, location.y, kind, getConnections(),
				getModel().getModelName());
	}

}

@@ -1029,134 +1029,9 @@
 ull)
- %7B%0A%09%09%09System.out.println(%22Operator: argument for parameter %22 + parameterNumber + %22 in operator %22 + toString() + %22 is null!%22);
 %0A
+
 %09%09%09r
@@ -1042,20 +1042,16 @@
 n null;%0A
-%09%09%7D%0A
 %09%09Visual
@@ -1114,132 +1114,8 @@
 ull)
- %7B%0A%09%09%09System.out.println(%22Operator: operand for parameter %22 + parameterNumber + %22 in operator %22 + toString() + %22 is null!%22);
 %0A%09%09%09
@@ -1127,20 +1127,16 @@
 n null;%0A
-%09%09%7D%0A
 %09%09String
@@ -1188,130 +1188,8 @@
 ull)
- %7B%0A%09%09%09System.out.println(%22Operator: query for parameter %22 + parameterNumber + %22 in operator %22 + toString() + %22 is null!%22);
 %0A%09%09%09
@@ -1205,14 +1205,8 @@
 ll;%0A
-%09%09%7D%09%09%0A
 %09%09if

Remove debugging code.