package org.seamframework.sql;

import static org.seamframework.sql.Type.BIT;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public abstract class Expressions {
	
	public static <T> Expression<Boolean> eq(final Expression<T> x, final Expression<T> y) {
		return new Expression<Boolean>() {
			@Override
			public String toSql() {
				return new StringBuffer()
					.append( x.toSql() )
					.append('=')
					.append( y.toSql() )
					.toString();
			}
			@Override
			public Type<Boolean> getType() {
				//TODO: is this really the correct thing to do?
				//      Boolean expressions in SQL aren't really 
				//      assignable to columns of type BIT
				return BIT;
			}
			@Override
			public List<Parameter<?>> getParameters() {
				List<Parameter<?>> params = new ArrayList<Parameter<?>>();
				params.addAll(x.getParameters());
				params.addAll(y.getParameters());
				return params;
			}
		};
	}
	
	public static <T> Parameter<T> parameter(final Type<T> type) {
		return new Parameter<T>() {
			@Override
			public Type<T> getType() {
				return type;
			}
			@Override
			public String toSql() {
				return "?";
			}
			@Override
			public List<Parameter<?>> getParameters() {
				return Collections.<Parameter<?>>singletonList(this);
			}
		};
	}
	
	public static Expression<Boolean> and(final Expression<Boolean>... expressions) {
		return new Expression<Boolean>() {
			@Override
			public String toSql() {
				StringBuilder builder = new StringBuilder();
				builder.append('(');
				for (Iterator<Expression<Boolean>> i = Arrays.asList(expressions).iterator(); i.hasNext(); ) {
					builder.append( i.next().toSql() );
					if ( i.hasNext() ) builder.append(" and ");
				}
				builder.append(')');
				return builder.toString();
			}
			@Override
			public Type<Boolean> getType() {
				//TODO: is this really the right thing to do???
				return BIT;
			}
			@Override
			public List<Parameter<?>> getParameters() {
				List<Parameter<?>> params = new ArrayList<Parameter<?>>();
				for (Expression<Boolean> e: expressions) {
					params.addAll(e.getParameters());
				}
				return params;
			}
		};
	}
	
}
