using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Text.RegularExpressions;
using Orciid.Core;

namespace Orciid
{
	public class downloads : PageTemplate.OrciidPage
	{
		protected System.Web.UI.WebControls.Repeater DownloadsRepeater;
		protected System.Web.UI.HtmlControls.HtmlGenericControl Heading;

		#region XSD
		private string DownloadsSchema = @"
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' elementFormDefault='qualified'>
  <xs:element name='downloads'>
    <xs:complexType>
      <xs:choice maxOccurs='unbounded'>
        <xs:element name='file' maxOccurs='unbounded'>
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base='xs:string'>
                <xs:attribute name='name' type='xs:string' use='required'/>
                <xs:attribute name='title' type='xs:string' use='required'/>
              </xs:extension>
            </xs:simpleContent>
          </xs:complexType>
        </xs:element>
        <xs:element name='link' maxOccurs='unbounded'>
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base='xs:string'>
                <xs:attribute name='url' type='xs:string' use='required'/>
                <xs:attribute name='title' type='xs:string' use='required'/>
              </xs:extension>
            </xs:simpleContent>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>
";
		#endregion

		public enum DownloadEntryType
		{
			File,
			Link
		}

		public class DownloadEntry
		{
			public DownloadEntryType type;
			public string name;
			public string url;
			public string title;
			public string description;

			public string GetLink()
			{
				if (type == DownloadEntryType.File)
					return "downloads.aspx?file=" + name;
				else if (type == DownloadEntryType.Link)
					return url;
				else return "";
			}
		}

		private void Page_Load(object sender, System.EventArgs e)
		{
			ArrayList entries = new ArrayList();
			XmlValidatingReader reader = null;
			string downloadpath = Configuration.Instance.GetString("content.downloads");
			try
			{
				reader = new XmlValidatingReader(
					new XmlTextReader(new StreamReader(Path.Combine(downloadpath, "downloads.xml"))));
				XmlSchemaCollection schemas = new XmlSchemaCollection();
				schemas.Add(null, new XmlTextReader(new StringReader(DownloadsSchema)));
				reader.ValidationType = ValidationType.Schema;
				reader.Schemas.Add(schemas);
				XmlDocument doc = new XmlDocument();
				doc.Load(reader);
				foreach (XmlNode node in doc.SelectNodes("/downloads/*"))
				{
					if (node.Name == "file")
					{
						string name = node.Attributes["name"].Value;
						if (File.Exists(Path.Combine(downloadpath, Path.GetFileName(name))))
						{
							DownloadEntry entry = new DownloadEntry();
							entry.type = DownloadEntryType.File;
							entry.name = name;
							entry.title = node.Attributes["title"].Value;
							entry.description = node.InnerText;
							entries.Add(entry);
						}
					}
					else if (node.Name == "link")
					{
						DownloadEntry entry = new DownloadEntry();
						entry.type = DownloadEntryType.Link;
						entry.url = node.Attributes["url"].Value;
						entry.title = node.Attributes["title"].Value;
						entry.description = node.InnerText;
						entries.Add(entry);
					}
				}
			}
			catch
			{
			}
			finally
			{
				if (reader != null)
					reader.Close();
			}
			if (entries.Count > 0)
			{
				DownloadsRepeater.DataSource = entries;
				DownloadsRepeater.DataBind();
			}
			else
			{
				ShowWarning(GetLocalString(this, "NoDownloads", "No downloads are available at this time."));
				DownloadsRepeater.Visible = false;
			}
			string download = Request.QueryString["file"];
			if (download != null && download.Length > 0)
			{
				bool found = false;
				foreach (DownloadEntry entry in entries)
					if (entry.name == download)
					{
						found = true;
						break;
					}
				if (found)
				{
					ReturnFile(Path.GetFileName(download), 
						Path.Combine(downloadpath, Path.GetFileName(download)));
					return;
				}
				else
					throw new Exception("Requested file not found");
			}
			string internaldownload = Request.QueryString["internalfile"];
			if (internaldownload != null && internaldownload.Length > 0)
			{
				Hashtable h = GetInternalFileList();
				if (h.ContainsKey(internaldownload))
				{
					ReturnFile(Path.GetFileName((string)h[internaldownload]),
						Path.Combine(Path.Combine(downloadpath, "internal"), (string)h[internaldownload]));
					return;
				}
				else
					throw new Exception("Requested internal file not found");
			}
			string checkiv = Request.QueryString["checkiv"];
			if (checkiv != null && checkiv.Length > 0)
			{
				// check current ImageViewer version
				string message;
				try
				{
					StreamReader inifile = File.OpenText(Path.Combine(downloadpath, 
						"internal" + Path.DirectorySeparatorChar + 
						"imageviewer2" + Path.DirectorySeparatorChar +
						"imageviewer.ini"));
					string content = inifile.ReadToEnd();
					inifile.Close();
					Regex availableregex = new Regex(@"\[ImageViewer\][^[]+Version=(\d+)\.(\d+)\.(\d+)",
						RegexOptions.Singleline);
					Regex installedregex = new Regex(@"(\d+)\.(\d+)\.(\d+)");
					Match available = availableregex.Match(content);
					if (available.Success)
					{
						int a1 = Int32.Parse(available.Groups[1].Value);
						int a2 = Int32.Parse(available.Groups[2].Value);
						int a3 = Int32.Parse(available.Groups[3].Value);
						Match installed = installedregex.Match(checkiv);
						if (installed.Success)
						{
							int i1 = Int32.Parse(installed.Groups[1].Value);
							int i2 = Int32.Parse(installed.Groups[2].Value);
							int i3 = Int32.Parse(installed.Groups[3].Value);
							if (i1 > a1 || 
								(i1 == a1 && i2 > a2) || 
								(i1 == a1 && i2 == a2 && i3 > a3))
								message = GetLocalString(this, "OlderAvailable", 
									"The version of ImageViewer you have installed is newer than the version available for download.");
							else if (i1 == a1 && i2 == a2 && i3 == a3)
								message = GetLocalString(this, "CurrentAvailable", 
									"You have the most recent version of ImageViewer installed.");
							else
								message = GetLocalString(this, "NewerAvailable", 
									"A newer version of ImageViewer is available.");
						}
						else
							message = GetLocalString(this, "InstalledVersionProblem", 
								"Could not determine installed version.");
					}
					else
						message = GetLocalString(this, "AvailableVersionProblem", 
							"Could not determine available version.");
				}
				catch
				{
					message = GetLocalString(this, "VersionFileProblem", 
						"Could not read version file.");
				}
				ShowInformation(message);
			}
		}

		private void ReturnFile(string name, string file)
		{
			Response.Clear();
			Response.Buffer = false;
			Response.ContentType = "application/octet-stream";
			Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", name));
			Stream stream = File.OpenRead(file);
			Response.AddHeader("Content-Length", stream.Length.ToString());
			byte[] buffer = new byte[16384];
			int bytesread;
			do
			{
				bytesread = stream.Read(buffer, 0, 16384);
				if (bytesread > 0)
					Response.OutputStream.Write(buffer, 0, bytesread);
			} while (Response.IsClientConnected && bytesread > 0);
			stream.Close();
			Response.End();
		}

		public override string GetHighlightedMenuItem()
		{
			return "Resources_Downloads";
		}

		protected override bool CheckUserPrivileges(Orciid.Core.User user)
		{
			string s = Request.QueryString["sessiontoken"];
			string i = Request.QueryString["internalfile"];
			// allow token in addition to regular user sessions
			if (s != null && s.Length > 0)
			{
				Orciid.Core.User u = (Orciid.Core.User)Context.Cache.Get(s);
				return (u != null);
			}
			// allow certain internal files to be downloaded without logging in
			else if (i != null && i.Length > 0)
			{
				return !RequireLoginForInternalFile(i);
			}
			// otherwise require login
			else	
				return (user != null);
		}

		private Hashtable GetInternalFileList()
		{
			Hashtable h = new Hashtable();
			h.Add("display", "imageviewer2/display.dcr");
			return h;
		}

		private bool RequireLoginForInternalFile(string file)
		{
			if (file == "display")
				return false;
			return true;
		}
		 
		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    
			this.Load += new System.EventHandler(this.Page_Load);

		}
		#endregion
	}
}
