using System;
using System.Web;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.IO;
using System.Text;

namespace UUN
{
    /// <summary>
    /// 针对某个请求的处理
    /// </summary>
    public class 访问
    {
        public bool 是否前台 = false;
        public bool 是否WML = false;
        //数据项
        public Hashtable 用户;
        public DateTime 请求时间;
        public SqlConnection 连接;
        public HttpContext HC;

        //回调委托
        public delegate void 回调委托();

        public 访问(HttpContext HC)
        {
            if (Directory.Exists(HC.Server.MapPath("~/Install")))
                if (File.ReadAllText(HC.Server.MapPath("~/Install/install.txt"), Encoding.UTF8) != "5")
                    HC.Response.Redirect("~/Install/");

            this.HC = HC;
            this.请求时间 = DateTime.Now;

            //初始化数据
            this.连接 = new SqlConnection(WebConfigurationManager.ConnectionStrings["UUN_UUN3G_CONN"].ConnectionString);
            this.连接.Open();

            //初始化用户
            String 标识=HC.Request.QueryString[Convert.ToString(程序.设置["标识名称"])];
            if(标识==null)
                if(HC.Request.Cookies["UUN_UUN3G_BiaoShi"]!=null)
                    标识=HC.Request.Cookies["UUN_UUN3G_BiaoShi"].Value;

            用户 用户 = new 用户(HC,连接);
            this.用户 = 用户.用户登录(标识);
        }
        /// <summary>
        /// 网页执行的入口
        /// </summary>
        /// <param name="位置">当前用户所在的位置</param>
        /// <param name="内容类型">当前访问的内容类型</param>
        /// <param name="内容子类型">当前访问的内容子类型</param>
        /// <param name="回调">返回执行的方法</param>
        public void 开始处理(String 位置,String 内容类型,String 内容子类型,回调委托 回调)
        {
            HC.Response.ContentType = 是否WML ? "text/vnd.wap.wml" : "text/html";

            if (!是否前台)
                HC.Response.Expires = -1;
            //访问相关
            if (是否前台)
                应用访问设置();

            更新数据();
            应用计划任务();

            if (Convert.ToBoolean(程序.设置["是否启用统计"]))
                应用访问统计(内容类型, 内容子类型);
            if (Convert.ToBoolean(程序.设置["是否启用IP统计"]))
            {
                访问统计_IP记录 IP记录 = new 访问统计_IP记录(HC, 连接);
                IP记录.更新访问次数(HC.Request.UserHostAddress);
            }

            //用户相关
            用户 用户 = new 用户(HC,连接);
            用户.更新登录信息(this.用户,位置);

            排错调用(回调);
        }
        /// <summary>
        /// 通过此方法调用其它方法可以排除并记录异常
        /// </summary>
        /// <param name="回调">回调的方法</param>
        public void 排错调用(回调委托 回调)
        {
            try
            {
                if (回调 != null)
                    回调();
            }
            catch (System.Threading.ThreadAbortException)
            {
                关闭连接();
            }
            catch (Exception e)
            {
                if (Convert.ToBoolean(程序.设置["启用错误日志"]))
                {
                    访问统计_错误日志 访问统计_错误日志 = new 访问统计_错误日志(HC, 连接);
                    访问统计_错误日志.记录(Convert.ToInt32(用户["ID"]),
                        Convert.ToString(用户["昵称"]),
                        Convert.ToString(用户["最后登录IP"]),
                        Convert.ToString(用户["最后登录地区"]),
                        e.Message);
                }

                关闭连接();

                String 输出代码;

                if (!是否前台)
                    输出代码 = Convert.ToString(程序.设置["后台出错提示代码"])
                        .Replace("$错误提示$",e.Message)
                        .Replace("~/", 程序.安装位置);
                else if (是否WML)
                    输出代码 = Convert.ToString(程序.设置["前台出错提示代码_WML"])
                        .Replace("$错误提示$", e.Message)
                        .Replace("~/", 程序.安装位置);
                else
                    输出代码 = Convert.ToString(程序.设置["前台出错提示代码_XHTML"])
                        .Replace("$错误提示$", e.Message)
                        .Replace("~/", 程序.安装位置);

                HC.Response.Clear();
                HC.Response.Write(输出代码);
                HC.Response.End();
            }
        }

        //访问限制


        private void 应用访问设置()
        {
            if (!Convert.ToBoolean(程序.设置["访问设置_网站状态"]))
                throw new Exception(程序.设置["访问设置_网站状态_错误提示"].ToString());

            if (Convert.ToInt32(程序.设置["访问时间间隔"]) > 0)
                if (Convert.ToDateTime(用户["最后访问时间"]) > DateTime.Now - new TimeSpan(0, 0, Convert.ToInt32(程序.设置["访问时间间隔"])))
                    throw new Exception(Convert.ToString(程序.设置["访问太快提示"]));

            if (Convert.ToString(用户["用户类型"]) == "会员")
                if (Convert.ToBoolean(用户["是否加黑"]))
                    throw new Exception(Convert.ToString(程序.设置["访问设置_加黑访问提示"]));

            if (Convert.ToBoolean(程序.设置["访问设置_禁止电脑访问"]))
                if (HC.Request.Browser.Browser.IndexOf("IE", StringComparison.OrdinalIgnoreCase) != -1 || HC.Request.Browser.Browser.IndexOf("OPERA", StringComparison.OrdinalIgnoreCase) != -1)
                    throw new Exception(Convert.ToString(程序.设置["访问设置_禁止电脑访问_错误提示"]));

            应用IP屏蔽();
        }

        private void 应用计划任务()
        {
            DataSet 数据 = (DataSet)HC.Application["UUN_UUN3G_JiHuaRenWu"];

            for (int i = 0; i < 数据.Tables[0].Rows.Count; i++)
            {
                DataRow 行 = 数据.Tables[0].Rows[i];
                DateTime 最后执行时间 = Convert.ToDateTime(行["最后执行时间"]);
                String 操作文件 = Convert.ToString(行["操作文件"]);
                switch (行["更新频率"].ToString())
                {
                    case "每月":
                        {
                            if (Convert.ToInt32(最后执行时间.ToString("yyyyMM")) < Convert.ToInt32(DateTime.Now.ToString("yyyyMM")))
                                计划任务_更新(Convert.ToString(行["操作文件"]), Convert.ToInt32(行["ID"]), Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-0 0:0:0")));
                        }
                        break;
                    case "每周":
                        {
                            if (最后执行时间 < DateTime.Now - new TimeSpan(7, 0, 0, 0))
                                计划任务_更新(Convert.ToString(行["操作文件"]), Convert.ToInt32(行["ID"]), Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-0 0:0:0")) - new TimeSpan(DateTime.Now.DayOfYear % 7, 0, 0, 0));
                        }
                        break;
                    case "每日":
                        {
                            if (最后执行时间 < DateTime.Now - new TimeSpan(1, 0, 0, 0))
                                计划任务_更新(Convert.ToString(行["操作文件"]),Convert.ToInt32(行["ID"]),Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")));
                        }
                        break;
                    case "每时":
                        {
                            if (最后执行时间 < DateTime.Now - new TimeSpan(1, 0, 0))
                                计划任务_更新(Convert.ToString(行["操作文件"]), Convert.ToInt32(行["ID"]), Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:00:00")));
                        }
                        break;
                    case "每五分钟":
                        {
                            if (最后执行时间 < DateTime.Now - new TimeSpan(0, 5, 0))
                                计划任务_更新(Convert.ToString(行["操作文件"]), Convert.ToInt32(行["ID"]), DateTime.Now);
                        }
                        break;
                    case "每分钟":
                        {
                            if (最后执行时间 < DateTime.Now - new TimeSpan(0, 1, 0))
                                计划任务_更新(Convert.ToString(行["操作文件"]), Convert.ToInt32(行["ID"]), DateTime.Now);
                        }
                        break;
                }
            }
        }

        private void 计划任务_更新(String 操作文件,int ID,DateTime 最后执行时间)
        {
            HC.Server.Execute(操作文件);
            SqlCommand 语句 = new SqlCommand("UPDATE ["+程序.数据表前缀+"网站_计划任务] SET [最后执行时间]=@最后执行时间 WHERE [ID]=" + ID, 连接);
            语句.Parameters.Add("@最后执行时间", SqlDbType.DateTime).Value = 最后执行时间;
            语句.ExecuteNonQuery();
            new 更新缓存数据(HC, 连接).计划任务_更新计划任务();
        }

        private void 应用IP屏蔽()
        {
            String[] IP数组 = Convert.ToString(程序.设置["IP屏蔽_IP列表"]).Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            String 用户IP = HC.Request.UserHostAddress;
            for (int i = 0; i < IP数组.Length; i++)
                if (IP数组[i] == 用户IP)
                    throw new Exception(程序.设置["IP屏蔽_错误提示"].ToString());
        }

        public void 应用域名分配()
        {
            String[] 域名数组 = Convert.ToString(程序.设置["域名分配_域名列表"]).Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            String[] 地址数组 = Convert.ToString(程序.设置["域名分配_地址列表"]).Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            String 域名 = HC.Request.Url.Authority;
            for (int i = 0; i < 域名数组.Length && i < 地址数组.Length; i++)
                if (域名 == 域名数组[i])
                    HC.Response.Redirect(地址数组[i]);
        }

        public void 验证管理员()
        {
            if (Convert.ToString(用户["用户类型"]) != "管理员")
                HC.Response.Redirect("~/Admin/DenLu.aspx");
        }

        public void 验证会员()
        {
            if (Convert.ToString(用户["用户类型"]) != "会员")
                HC.Response.Redirect(常用.处理地址(程序.安装位置 + "Club/Login.aspx?rurl="+
                    HC.Server.UrlEncode(HC.Request.Url.ToString().Replace(用户["标识"].ToString(),"@sid@")), 用户["标识"].ToString()));
        }

        public void 验证等级(int 等级)
        {
            验证会员();
            if (Convert.ToInt32(用户["等级"]) < 等级)
                throw new Exception("访问此内容至少需要" + 等级);
        }

        public void 验证扣除积分(String 类型, int ID)
        {
            SqlCommand 语句 = new SqlCommand("SELECT [ID] FROM [" + 程序.数据表前缀 + "内容_积分记录] WHERE [类型]=@类型 AND [ID]=@ID", 连接);
            语句.Parameters.Add("@类型", SqlDbType.NVarChar).Value = 类型;
            语句.Parameters.Add("@ID", SqlDbType.Int).Value = ID;
            SqlDataReader 读取 = 语句.ExecuteReader();
            bool 是否存在 = 读取.HasRows;
            读取.Close();

            if (!是否存在)
                HC.Response.Redirect(常用.处理地址(程序.安装位置 + "Club/Content_Permission.aspx?type=" +
                    HC.Server.UrlEncode(类型) + "&ID=" + ID + "&rurl=" + HC.Server.UrlEncode(HC.Request.Url.ToString()), 用户["标识"].ToString()));
        }

        public void 验证权限(String 权限)
        {
            UUN.用户.验证权限(Convert.ToString(用户["用户组"]), 权限);
        }

        public bool 是否包含权限(String 权限)
        {
            return UUN.用户.是否包含权限(Convert.ToString(用户["用户组"]), 权限);
        }

        //访问限制结束

        private void 更新数据()
        {
            if (HC.Application["UUN_UUN3G_GengXinShiJian"] == null)
                HC.Application["UUN_UUN3G_GengXinShiJian"] = new 设置(File.ReadAllText(HC.Server.MapPath("~/Data/GengXin.xml"), Encoding.UTF8));
            设置 更新时间 = (设置)HC.Application["UUN_UUN3G_GengXinShiJian"];

            更新缓存数据 更新缓存数据 = new 更新缓存数据(HC, 连接);
            更新缓存数据.开始更新();
        }

        private void 应用访问统计(String 内容类型, String 内容子类型)
        {
            访问统计_访问记录 访问记录 = new 访问统计_访问记录(HC, 连接);
            HC.Application.Lock();
            访问记录.记录(Convert.ToInt32(用户["ID"]),
                Convert.ToString(用户["昵称"]),
                Convert.ToString(用户["最后登录地区"]),
                内容类型, 内容子类型);
            HC.Application.UnLock();
        }

        public int 获取一页显示记录数()
        {
            if (用户["用户类型"].ToString() == "会员")
                return Convert.ToInt32(用户["一页显示记录数"]);
            else
                return Convert.ToInt32(程序.设置["显示设置_一页显示记录数"]);
        }

        public int 获取一页显示文字数()
        {
            if (用户["用户类型"].ToString() == "会员")
                return Convert.ToInt32(用户["一页显示文字数"]);
            else
                return Convert.ToInt32(程序.设置["显示设置_一页显示文字数"]);
        }

        public int 获取一页显示图片数()
        {
            if (用户["用户类型"].ToString() == "会员")
                return Convert.ToInt32(用户["一页显示图片数"]);
            else
                return Convert.ToInt32(程序.设置["显示设置_一页显示图片数"]);
        }

        public int 获取一页显示文件数()
        {
            if (用户["用户类型"].ToString() == "会员")
                return Convert.ToInt32(用户["一页显示文件数"]);
            else
                return Convert.ToInt32(程序.设置["显示设置_一页显示文件数"]);
        }

        public void 关闭连接()
        {
            if(连接.State!=ConnectionState.Closed)
                连接.Close();
        }
    }
}