using System;
using System.Collections.Generic;
using System.Text;
using Howest.QueryBuilder.Specifications;
using Howest.QueryBuilder.Conditions;

namespace Howest.QueryBuilder.Statements
{
	public class JoinReference : TableReference
	{
		private TableReference _left;

		public TableReference Left
		{
			get { return _left; }
			set { _left = value; }
		}

		private TableReference _right;

		public TableReference Right
		{
			get { return _right; }
			set { _right = value; }
		}

		private SearchCondition _condition;

		public SearchCondition Condition
		{
			get { return _condition; }
			set { _condition = value; }
		}
	

		private bool _useParentheses;

		public bool UseParentheses
		{
			get { return _useParentheses; }
			set { _useParentheses = value; }
		}

		private bool _useOuter;

		public bool UseOuter
		{
			get { return _useOuter; }
			set { _useOuter = value; }
		}
	

		private bool _isNatural;

		public bool IsNatural
		{
			get { return _isNatural; }
			set { _isNatural = value; }
		}

		private JoinType _type;

		public JoinType Type
		{
			get { return _type; }
			set { _type = value; }
		}

		protected override string Generate()
		{
			StringBuilder sb = new StringBuilder();
			if (UseParentheses)
			{
				sb.Append(QueryConstants.LEFTPARENT);
			}
			switch (_type)
			{
				case JoinType.INNER:
				case JoinType.LEFT:
				case JoinType.RIGHT:
				case JoinType.FULL:
				case JoinType.UNION:
					GenerateQualifiedJoin(sb);
					break;
				case JoinType.CROSSJOIN:
					GenerateCrossJoin(sb);
					break;
				default:
					break;
			}

			if (UseParentheses)
			{
				sb.Append(QueryConstants.RIGHTPARENT);
			}
			return sb.ToString();
		}

		private void GenerateCrossJoin(StringBuilder sb)
		{
			sb.Append(Left.GenerateInternal());
			sb.Append(QueryConstants.SPACE + "CROSS JOIN" + QueryConstants.SPACE);
			sb.Append(Right.GenerateInternal());
		}

		private void GenerateQualifiedJoin(StringBuilder sb)
		{
			sb.Append(Left.GenerateInternal());
			if (IsNatural)
			{
				sb.Append(QueryConstants.SPACE + "NATURAL" + QueryConstants.SPACE);
			}
			string outer = UseOuter ? QueryConstants.SPACE + "OUTER" + QueryConstants.SPACE : string.Empty;
			switch (_type)
			{
				case JoinType.INNER:
					sb.Append(QueryConstants.SPACE + "INNER" + QueryConstants.SPACE);
					break;
				case JoinType.LEFT:
					sb.Append(QueryConstants.SPACE + "LEFT" + QueryConstants.SPACE + outer);
					break;
				case JoinType.RIGHT:
					sb.Append(QueryConstants.SPACE + "RIGHT" + QueryConstants.SPACE + outer);
					break;
				case JoinType.FULL:
					sb.Append(QueryConstants.SPACE + "FULL" + QueryConstants.SPACE + outer);
					break;
				case JoinType.UNION:
					sb.Append(QueryConstants.SPACE + "UNION" + QueryConstants.SPACE);
					break;
			}
			sb.Append(QueryConstants.SPACE + "JOIN" + QueryConstants.SPACE);
			sb.Append(Right.GenerateInternal());
			// TODO: Add Query specification
		}
	}
}
