using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Marr.Data.QGen
{
    public class RowCountQueryDecorator : IQuery
    {
        private SelectQuery _innerQuery;

        public RowCountQueryDecorator(SelectQuery innerQuery)
        {
            _innerQuery = innerQuery;
        }
        
        public string Generate()
        {
            // Decide which type of paging query to create
            if (_innerQuery.IsView || _innerQuery.IsJoin)
            {
                return ComplexRowCount();
            }
            else
            {
                return SimpleRowCount();
            }
        }

        /// <summary>
        /// Generates a row count query for a multiple table joined query (groups by the parent entity).
        /// </summary>
        /// <returns></returns>
        private string ComplexRowCount()
        {
            // Create paged query
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("WITH GroupCTE AS (");
            sql.Append("SELECT ").AppendLine(BuildBaseTablePKColumns());
            BuildGroupColumn(sql);
            _innerQuery.BuildFromClause(sql);
            _innerQuery.BuildJoinClauses(sql);
            _innerQuery.BuildWhereClause(sql);
            sql.AppendLine(")");
            BuildSelectCountClause(sql);
            sql.AppendLine("FROM GroupCTE");
            sql.AppendLine("WHERE GroupRow = 1");

            return sql.ToString();
        }

        /// <summary>
        /// Generates a row count query for a single table query (no joins).
        /// </summary>
        /// <returns></returns>
        private string SimpleRowCount()
        {
            StringBuilder sql = new StringBuilder();

            BuildSelectCountClause(sql);
            _innerQuery.BuildFromClause(sql);
            _innerQuery.BuildJoinClauses(sql);
            _innerQuery.BuildWhereClause(sql);

            return sql.ToString();
        }

        private void BuildGroupColumn(StringBuilder sql)
        {
            string baseTablePKColumns = BuildBaseTablePKColumns();
            sql.AppendFormat(", ROW_NUMBER() OVER (PARTITION BY {0} ORDER BY {1}) As GroupRow ", baseTablePKColumns, baseTablePKColumns);
        }

        private string BuildBaseTablePKColumns()
        {
            Table baseTable = GetBaseTable();

            StringBuilder sb = new StringBuilder();
            foreach (var col in baseTable.Columns.PrimaryKeys)
            {
                if (sb.Length > 0)
                    sb.AppendLine(", ");

                string colName = _innerQuery.IsView ?
                    _innerQuery.NameOrAltName(col.ColumnInfo) :
                    col.ColumnInfo.Name;

                sb.AppendFormat(_innerQuery.Dialect.CreateToken(string.Concat(baseTable.Alias, ".", colName)));
            }

            return sb.ToString();
        }

        private void BuildSelectCountClause(StringBuilder sql)
        {
            sql.AppendLine("SELECT COUNT(*)");
        }

        private Table GetBaseTable()
        {
            Table baseTable = null;
            if (_innerQuery.Tables[0] is View)
            {
                baseTable = (_innerQuery.Tables[0] as View).Tables[0];
            }
            else
            {
                baseTable = _innerQuery.Tables[0];
            }
            return baseTable;
        }
    }
}

/*
WITH GroupCTE AS 
(
	SELECT [t0].[ID],[t0].[OrderName],[t1].[ID] AS OrderItemID,[t1].[OrderID],[t1].[ItemDescription],[t1].[Price], 
	ROW_NUMBER() OVER (PARTITION BY [t0].[ID]  ORDER BY [t0].[OrderName]) As GroupRow  
	FROM [Order] [t0] 
	LEFT JOIN [OrderItem] [t1] ON (([t0].[ID] = [t1].[OrderID])) 
	--WHERE (([t0].[OrderName] = @P0))
)
SELECT * FROM GroupCTE
WHERE GroupRow = 1
*/