//==============================================================
//  版权所有：深圳杰文科技
//  文件名：UpgradeFileManager.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Infrastructure.Log;
using Infrastructure.Utilities;

namespace Framework.HandlerBase
{
	public class UpgradeFileManager
	{
		private static readonly List<UpgradeFileMapping> _UpgradeFileMappingList = new List<UpgradeFileMapping>();

		internal static readonly string _ServerUpgradePath = AppDomain.CurrentDomain.BaseDirectory + "ServerUpgrade";
		//internal static readonly string _ClientUpgradePath = AppDomain.CurrentDomain.BaseDirectory + "ClientUpgrade";
		internal static readonly string _ClientUpgradePath = ConfigurationManager.AppSettings["ClientUpgradePath"];
		internal static readonly string _UpgradeApplication = "Framework.Upgrade.exe";
		internal static readonly string _UpgradeApplicationPath = AppDomain.CurrentDomain.BaseDirectory + _UpgradeApplication;
		internal static readonly string _UpgradeLogFileName = "Upgrade.log";

		public UpgradeFileManager()
		{
			InitMapping();
		}

		#region - MaxVersionNo -

		public long GetMaxVersionNo()
		{
			if (_MaxVersionNo == -1)
			{
				if (_UpgradeFileMappingList.Count > 0)
				{
					_MaxVersionNo = _UpgradeFileMappingList.Max(a => a.VersionNo);
				}
				else
				{
					_MaxVersionNo = 0;
				}
			}
			return _MaxVersionNo;
		}

		//最大版本号。
		private long _MaxVersionNo = -1;
		public long MaxVersionNo
		{
			get
			{
				return GetMaxVersionNo();
			}
			set
			{
				MaxVersionNo = value;
			}
		}

		#endregion

		public string GetUpgradeLog()
		{
			string path = Path.Combine(_ClientUpgradePath, _UpgradeLogFileName);
			if (File.Exists(path))
			{
				return File.ReadAllText(path);
			}
			return "";
		}

		#region - Upgrade -

		//获得指定起始版本之后的升级文件列表。
		public List<UpgradeFile> Get(long startingVersionNo)
		{
			List<UpgradeFile> upgradeFileList = new List<UpgradeFile>();

			//按版本号筛选出文件列表。
			var r = from a in _UpgradeFileMappingList
					where a.VersionNo > startingVersionNo
					select a;
			foreach (UpgradeFileMapping mapping in r)
			{
				upgradeFileList.AddRange(mapping.FileList);
			}

			//过滤重复的文件，只保留版本号最大的同名文件。
			upgradeFileList = FilterReduplicate(upgradeFileList);

			foreach (UpgradeFile upgradeFile in upgradeFileList)
			{
				if (!upgradeFile.IsLoaded)
				{
					byte[] buf = File.ReadAllBytes(upgradeFile.FullPath);
					upgradeFile.Content = GZip.Compress(buf); //压缩
					upgradeFile.IsLoaded = true;
				}
			}

			return upgradeFileList;
		}

		//过滤掉重复的文件：如果多个版本中两个文件名相同，那么取版本号最大的那个进行升级。
		private List<UpgradeFile> FilterReduplicate(List<UpgradeFile> upgradeFileList)
		{
			List<UpgradeFile> list = new List<UpgradeFile>();

			foreach (UpgradeFile file in upgradeFileList)
			{
				var r = (from a in list
						 where a.FileName == file.FileName
						 select a).SingleOrDefault();
				if (r == null)
				{
					list.Add(file);
				}
				else if (file.VersionNo > r.VersionNo)
				{
					list.Remove(r);
					list.Add(file);
				}
			}

			return list;
		}

		//初始化升级文件。
		public void InitMapping()
		{
			_MaxVersionNo = -1;
			if (!Directory.Exists(_ClientUpgradePath))
			{
				return;
			}

			long versionNo = 0;
			_UpgradeFileMappingList.Clear();
			string[] directories = Directory.GetDirectories(_ClientUpgradePath);
			foreach (string subDir in directories)
			{
				//注意，根目录的名称一定是版本号（数字）。
				try
				{
					versionNo = long.Parse(Path.GetFileName(subDir));
				}
				catch
				{
					throw new ServiceException("版本号解析错误：{0}", subDir);
				}

				UpgradeFileMapping mapping = new UpgradeFileMapping(versionNo, subDir);
				_UpgradeFileMappingList.Add(mapping);

				InitMapping(versionNo, subDir);
			}

		}

		private void InitMapping(long versionNo, string dir)
		{
			string[] directories = Directory.GetDirectories(dir);
			foreach (string subDir in directories)
			{
				UpgradeFileMapping mapping = new UpgradeFileMapping(versionNo, subDir);
				_UpgradeFileMappingList.Add(mapping);

				InitMapping(versionNo, subDir); //递归，继续解析子目录。
			}
		}

		#endregion

		#region - 服务器升级管理 -

		//升级服务器。
		public void UpgradeServer(UpgradeData upgradeData)
		{
			SessionCache.Save(); //先保存Session。

			if (!Directory.Exists(_ServerUpgradePath))
			{
				Directory.CreateDirectory(_ServerUpgradePath);
			}

			//把客户端传过来的升级文件写到升级目录下。
			foreach (UpgradeFile file in upgradeData.UpgradeFileList)
			{
				string path = "";
				if (file.FileName == _UpgradeApplication)
				{
					path = _UpgradeApplicationPath;
				}
				else
				{
					path = Path.Combine(_ServerUpgradePath, file.FileName);
				}

				File.WriteAllBytes(path, file.Content);
			}

			string processName = Process.GetCurrentProcess().ProcessName;
			Process.Start(_UpgradeApplicationPath, processName); //启动升级程序。
		}

		#endregion

		#region - 客户端升级管理 -

		//上传新的客户端升级包。
		public void UploadClient(UpgradeData upgradeData)
		{
			if (upgradeData.VersionNo <= this.MaxVersionNo)
			{
				throw new ServiceException("版本号必须大于已有的升级版本号");
			}

			//创建升级目录。
			string dir = Path.Combine(_ClientUpgradePath, upgradeData.VersionNo.ToString());
			Directory.CreateDirectory(dir);

			//写升级文件。
			foreach (UpgradeFile file in upgradeData.UpgradeFileList)
			{
				string path = Path.Combine(dir, file.FileName);
				File.WriteAllBytes(path, file.Content);
			}

			//写升级日志。
			string upgradeLogFilePath = Path.Combine(_ClientUpgradePath, _UpgradeLogFileName);
			File.WriteAllText(upgradeLogFilePath, upgradeData.UpgradeLog);

			InitMapping(); //刷新升级映射包。
		}

		//删除客户端升级。
		public void DeleteClientUpgrade(long versionNo)
		{
			string path = Path.Combine(_ClientUpgradePath, versionNo.ToString());
			if (!Directory.Exists(path))
			{
				throw new ServiceException("版本{0}不存在", versionNo);
			}

			Directory.Delete(path, true);

			InitMapping(); //刷新升级映射包。
		}

		#endregion

	}

}
