using System;
using System.Text;

namespace ynhtm.DBUtility
{
    /// <summary>
    /// 数据查询生成。
    /// </summary>
    public abstract class QueryBuilder : IQuery
    {
        StringBuilder query;

        public QueryBuilder()
        {
            this.query = new StringBuilder();
        }

        /// <summary>
        /// 编码数据库可识别的字符串。
        /// </summary>
        /// <param name="s">要编码的字符串。</param>
        /// <returns>一个已编码的字符串。</returns>
        public abstract string EncodeString(string s);

        protected virtual object GetValue(object value)
        {
            if (value == null || DBNull.Value.Equals(value))
                return "NULL";
            else
            {
                if (value is QueryText) return ((QueryText)value).Sql;
                var type = value.GetType();
                switch (Type.GetTypeCode(type))
                {
                    case TypeCode.Boolean:
                        return (bool)value ? 1 : 0;
                    case TypeCode.String:
                    case TypeCode.Char:
                        return this.EncodeString((string)value);
                    default:
                        return value;
                }
            }
        }

        /// <summary>
        /// 开始括号 "("。
        /// </summary>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery BracketBegin()
        {
            this.query.Append("(");
            return this;
        }

        /// <summary>
        /// 结束括号 ")"。
        /// </summary>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery BracketEnd()
        {
            this.query.Append(")");
            return this;
        }

        /// <summary>
        /// 小于比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Lt(string name, object value)
        {
            this.query.Append(name).Append(" < ").Append(this.GetValue(value));
            return this;
        }

        /// <summary>
        /// 大于比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Gt(string name, object value)
        {
            this.query.Append(name).Append(" > ").Append(this.GetValue(value));
            return this;
        }

        /// <summary>
        /// 等于比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Equal(string name, object value)
        {
            this.query.Append(name).Append(" = ").Append(this.GetValue(value));
            return this;
        }

        /// <summary>
        /// 不等于比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery NotEqual(string name, object value)
        {
            this.query.Append(name).Append(" != ").Append(this.GetValue(value));
            return this;
        }

        /// <summary>
        /// IS 比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Is(string name, object value)
        {
            this.query.Append(name).Append(" IS ").Append(this.GetValue(value));
            return this;
        }

        /// <summary>
        /// IS NOT 比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery IsNot(string name, object value)
        {
            this.query.Append(name).Append(" IS NOT ").Append(this.GetValue(value));
            return this;
        }

        /// <summary>
        /// IN 比较。
        /// </summary>
        /// <typeparam name="T">values 值类型。</typeparam>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="values">要比较的值集合。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery In<T>(string name, T[] values)
        {
            var arr = Array.ConvertAll<T, string>(values, delegate(T obj) { return this.GetValue(obj).ToString(); });
            this.query.Append(name).Append(" IN (").Append(string.Join(",", arr)).Append(")");
            return this;
        }

        /// <summary>
        /// IN 比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值集合。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery In(string name, object value)
        {
            this.query.Append(name).Append(" IN (").Append(this.GetValue(value)).Append(")");
            return this;
        }

        /// <summary>
        /// NOT IN 比较。
        /// </summary>
        /// <typeparam name="T">values 值类型。</typeparam>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="values">要比较的值集合。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery NotIn<T>(string name, T[] values)
        {
            var arr = Array.ConvertAll<T, string>(values, delegate(T obj) { return this.GetValue(obj).ToString(); });
            this.query.Append(name).Append(" NOT IN (").Append(string.Join(",", arr)).Append(")");
            return this;
        }

        /// <summary>
        /// NOT IN 比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值集合。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery NotIn(string name, object value)
        {
            this.query.Append(name).Append(" NOT IN (").Append(this.GetValue(value)).Append(")");
            return this;
        }

        /// <summary>
        /// LIKE 比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Like(string name, string value)
        {
            this.query.Append(name).Append(" LIKE N'%' + ").Append(this.GetValue(value)).Append(" + N'%'");
            return this;
        }

        /// <summary>
        /// NOT LIKE 比较。
        /// </summary>
        /// <param name="name">要比较的字段名。</param>
        /// <param name="value">要比较的值。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery NotLike(string name, string value)
        {
            this.query.Append(name).Append(" NOT LIKE N'%' + ").Append(this.GetValue(value)).Append(" + N'%'");
            return this;
        }

        /// <summary>
        /// AND 逻辑。
        /// </summary>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery And()
        {
            if (this.query.Length > 0) this.query.Append(" AND ");
            return this;
        }

        /// <summary>
        /// OR 逻辑。
        /// </summary>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Or()
        {
            if (this.query.Length > 0) this.query.Append(" OR ");
            return this;
        }

        /// <summary>
        /// 直接追加 SQL 语句。
        /// </summary>
        /// <param name="sql">SQL 语句。</param>
        /// <returns>返回当前 IQuery 类型。</returns>
        public virtual IQuery Sql(string sql)
        {
            this.query.Append(sql);
            return this;
        }

        /// <summary>
        /// 将生成的 SQL 返回为 String 字符串。
        /// </summary>
        /// <returns>返回一个字符串。</returns>
        public override string ToString()
        {
            return this.query.ToString();
        }
    }
}
