using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.IO;
using Orciid.Core;

/* This page provides access to image files.  It takes the following query string parameters:
 * int id:			The internal image identifier (optional, if res is specified;
 *					required if ssid is specified)
 * int cid:			The internal collection identifier (required)
 * string res:		The resource of the image (optional, if id is specified;
 *					ignored if ssid is specified)
 * int exp:			The preferred image expiration for caching in the browser (optional)
 * string format:	The requested image format: F=full, M=postcard, T=thumbnail (required)
 * int ssid:		The internal identifier of the slideshow this image is in, to
 *					circumvent access control on collections (optional)
 * 
 * Valid parameter combinations are (optionals in square brackets):
 * id,cid[,res][,exp],format
 * [id,]cid,res[,exp],format
 * id,cid[,exp],format,ssid
 */

namespace Orciid
{
	public class GetImage : System.Web.UI.Page
	{
		#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.Init += new System.EventHandler(this.GetImage_Init);

		}
		#endregion
	
		private string returnfilename = null;

		private Stream GetImageStream(ImageIdentifier imageid, string resource, ImageSize format,
			int slideshowid, string slideshowpassword)
		{
			if (slideshowid != 0 && imageid.ID != 0 && imageid.CollectionID != 0)
			{
				// check privileges based on slideshow access
				Slideshow show = Slideshow.GetByID(slideshowid);
				if (show != null)
				{
					Orciid.Core.User showowner = Orciid.Core.User.GetByID(show.Owner);
					string annotation = null;
					Orciid.Core.Image image = null;
					foreach (Slide slide in show.GetSlides(slideshowpassword))
						if (slide.ImageID == imageid)
						{
							annotation = slide.Annotation;
							image = show.GetImage(slideshowpassword, slide.ImageID);
							break;
						}
					Stream stream = show.GetResourceData(slideshowpassword, imageid, format);
					if (image != null && format != ImageSize.Thumbnail)
						stream = image.AddCatalogingDataToStream(stream, showowner, annotation);
					returnfilename = image.Resource;
					return stream;
				}
				else
					throw new Exception("Slideshow not available");
			}
			else
			{
				// check privileges based on collection access
				Orciid.Core.Image image = null;
				Collection coll = Collection.GetByID(imageid.CollectionID);
				if (coll != null)
				{
					if (imageid.CollectionID != 0 && imageid.ID != 0)
					{
						image = Image.GetByID(imageid);
						if (image != null)
							resource = image.Resource;
					}
					else if (resource != null && resource.Length > 0)
					{
						ArrayList images = coll.GetImagesByResource(resource);
						if (images != null && images.Count > 0)
							image = (Orciid.Core.Image)images[0];
					} 

					if (image != null)
					{
						Stream stream = coll.GetResourceData(resource, format);
						if (format != ImageSize.Thumbnail)
							stream = image.AddCatalogingDataToStream(stream,
								Orciid.Core.User.CurrentUser(),	null);
						returnfilename = image.Resource;
						return stream;
					}
					else
						throw new Exception("Image not available [3]");
				}
				else
					throw new Exception("Collection not available");
			}
		}

		private void GetImage_Init(object sender, System.EventArgs e)
		{
			Orciid.Core.User user;
			string token = Request.QueryString["token"];
			if (token != null && token.Length > 0) 
				user = (Orciid.Core.User)Context.Cache.Get(token);
			else 
				user = (Orciid.Core.User)Session["CurrentUser"];

			if (user == null)
			{			
				Properties props = Properties.GetSystemProperties();
				if (props.GetAsInt("allowguest", 0) == 1)
					user = Orciid.Core.AnonymousUser.User;
			}

			if (user != null)
				user.Activate(Request.UserHostAddress);	
			
			bool problem = false;

			// read image identifier
			ImageIdentifier imageid;
			imageid.ID = 0;
			imageid.CollectionID = 0;
			try
			{
				imageid.ID = Int32.Parse(Request.QueryString["id"]);
			}
			catch
			{
			}

			// read collection identifier
			try
			{
				imageid.CollectionID = Int32.Parse(Request.QueryString["cid"]);
			}
			catch 
			{
			}

			// read resource identifier
			string resource = Request.QueryString["res"];

			// read expiration time
			int expiration = Configuration.Instance.GetInt("content.imageexpiration");
			try
			{
				expiration = Int32.Parse(Request.QueryString["exp"]);
				if (expiration < 0)
					expiration = 0;
			}
			catch 
			{
			}

			// read requested image size, default to thumbnail
			ImageSize format;
			switch (Request.QueryString["format"])
			{
				case "F":
					format = ImageSize.Full;
					break;
				case "M":
					format = ImageSize.Medium;
					break;
				case "T":
				default:
					format = ImageSize.Thumbnail;
					break;
			}

			// read slideshow id, if given, check slideshow access instead of
			// collection access, e.g. to allow students to view slideshows with
			// images that they don't have access to otherwise

			int slideshowid;
			try
			{
				slideshowid = Int32.Parse(Request.QueryString["ssid"]);
			}
			catch
			{
				slideshowid = 0;
			}

			string slideshowpassword = 
				Session["slideshowpassword:" + slideshowid.ToString()] as string;

			ImageSize tryformat = format;
			Exception originalexception = null;
			Stream stream;

			while (true)
			{
				try
				{
					stream = GetImageStream(imageid, resource, tryformat, 
						slideshowid, slideshowpassword);
					break;
				}
				catch (Exception ex)
				{
					problem = true;
					stream = null;
					if (originalexception == null)
						originalexception = ex;
					if (tryformat == ImageSize.Full)
						tryformat = ImageSize.Medium;
					else if (tryformat == ImageSize.Medium)
						tryformat = ImageSize.Thumbnail;
					else
						break;
				}
			}

			if (originalexception != null)
				stream = Collection.RenderMessage(originalexception.Message, format);

			if (stream == null)
				stream = Collection.RenderMessage("Internal error", format);

			Response.Clear();
			Response.Buffer = false;
			if (!problem)
				Response.Expires = expiration;
			Response.ContentType = "image/jpeg";
			if (returnfilename == null)
				returnfilename = "image.jpg";
			Response.AddHeader("Content-Disposition", 
				String.Format("attachment; filename=\"{0}\"", returnfilename));
			// if stream is null here something is really wrong, since even the special images failed
			if (stream != null)
			{
				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();
		}
	}
}
