using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using Orciid.Core;
using Root.Reports;
using System.IO;

namespace Orciid
{
	public class printshow : PageTemplate.PdfGeneratingPage
	{
		private class PrintShowReport: Report
		{
			private Slideshow show;
			private Slide[] slides;
			private string[] annotations = null;
			private Orciid.Core.Image[] images;
			private Orciid.Core.User owner;
			private string password;
			private PageTemplate.PdfGeneratingPage page;

			public PrintShowReport(Slideshow s, string pwd, PageTemplate.PdfGeneratingPage p):
				base()
			{
				show = s;
				password = pwd;
				page = p;
				ArrayList temp = new ArrayList();
				foreach (Slide slide in show.GetSlides(pwd))
					if (!slide.Scratch)
						temp.Add(slide);
				slides = (Slide[])temp.ToArray(typeof(Slide));
				ImageIdentifier[] id = new ImageIdentifier[slides.Length];
				for (int i = 0; i < slides.Length; i++)
					id[i] = slides[i].ImageID;
				images = show.GetImages(pwd);
				owner = Orciid.Core.User.GetByID(show.Owner);
				annotations = Orciid.Core.Image.GetAnnotations(owner, id);
				Create();
			}

			private FontDef fontdef;
			private FontProp titlefont;
			private FontProp textfont;
			private FontProp labelfont;
			private PenProp linepen;

			private const double LINESPACING = 3.3;
			private const double TOPPOSITION = 31;
				
			private void AddBlankPage()
			{
				string leftover = null;
				new Root.Reports.Page(this);
				page_Cur.rHeightMM = 279.4;
				page_Cur.rWidthMM = 215.9;
				RepObj pagenumber = Paragraph.GetFragment(textfont, String.Format(
					page.GetLocalString(page, "PageNumber", "Page {0}"), 
					page_Cur.iPageNo), 200, out leftover);
				page_Cur.AddMM(206 - pagenumber.rWidthMM, 10 + pagenumber.rHeightMM, pagenumber);
				Paragraph titlepar = new Paragraph(show.Title);
				AddObjectsToPage(page_Cur, 10, 10 + titlefont.rHeight() * 1.0 / 72.0 * 25.4, 
					titlepar.GetNextLine(titlefont, 186 - pagenumber.rWidthMM));
				Paragraph ownernamepar = new Paragraph(owner.FullName);
				AddObjectsToPage(page_Cur, 10, 18 + titlefont.rHeight() * 1.0 / 72.0 * 25.4, 
					ownernamepar.GetNextLine(titlefont, 186 - pagenumber.rWidthMM));
				page_Cur.AddMM(10, 30, new RepLineMM(linepen, 0, -240));
				page_Cur.AddMM(108, 30, new RepLineMM(linepen, 0, -240));
				page_Cur.AddMM(206, 30, new RepLineMM(linepen, 0, -240));
				page_Cur.AddMM(10, 30, new RepLineMM(linepen, 196, 0));
				page_Cur.AddMM(10, 270, new RepLineMM(linepen, 196, 0));
			}

			private void NextColumn(ref double xpos, ref double ypos)
			{
				ypos = TOPPOSITION;
				if (xpos < 109)
					xpos = 109;
				else
				{
					xpos = 11;
					AddBlankPage();
				}
			}

			private void NextLine(ref double xpos, ref double ypos,
				ref double thumbnailypos, 
				ref double minxpos, ref double maxxpos, double thumbnailwidth)
			{
				ypos += LINESPACING;
				if (ypos > 269 - LINESPACING)
				{
					NextColumn(ref xpos, ref ypos);
					thumbnailypos = 0;
					minxpos = xpos;
					maxxpos = xpos + 93;
				}
				if (ypos > thumbnailypos)
					xpos = minxpos;
				else
					xpos = minxpos + thumbnailwidth + 1;
			}

			protected override void Create() 
			{	
				fontdef = new FontDef(this, FontDef.StandardFont.Helvetica);
				titlefont = new FontPropMM(fontdef, 5.0);
				textfont = new FontPropMM(fontdef, 1.8);
				labelfont = new FontPropMM(fontdef, 1.8);
				labelfont.bBold = true;
				linepen = new PenProp(this, 0.5, Color.Black);
				
				double xpos = 1000; // so that NextColumn will go to first column
				double ypos = 1000; // so that a new page is triggered
				double thumbnailwidth = 30;
				double thumbnailheight = thumbnailwidth * 3 / 4;

				for (int i = 0; i < slides.Length; i++)
				{
					Orciid.Core.Image image = images[i];
					if (image == null)
						continue;

					// check if there is enough space for another thumbnail in current column
					if (ypos + thumbnailheight > 269)
						// no, switch to next column
						NextColumn(ref xpos, ref ypos);

					if (ypos > TOPPOSITION)
						// add horizontal line before record if it is not first in column
						page_Cur.AddMM(xpos - 1, ypos - 1, new RepLineMM(linepen, 98, 0));

					System.IO.Stream stream = show.GetResourceData(password, images[i].ID, ImageSize.Thumbnail);
					
					StaticContainer sc = new StaticContainer(RT.rPointFromMM(thumbnailwidth), RT.rPointFromMM(thumbnailheight));
					page_Cur.AddMM(xpos, ypos + thumbnailheight, sc);
					Bitmap bitmap = new Bitmap(stream);

					// Acrobat Reader does not understand some image formats, so convert
					// everything else to 24 bit RGB
					if (bitmap.PixelFormat != PixelFormat.Format24bppRgb)
					{
						Bitmap b = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format24bppRgb);
						for (int y = 0; y < bitmap.Height; y++)
							for (int x = 0; x < bitmap.Width; x++)
								b.SetPixel(x, y, bitmap.GetPixel(x, y));
						// default to 80 percent
						EncoderParameters ep = new EncoderParameters();
						ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, new long[] { 80 });
						ImageCodecInfo jpegencoder = null;
						foreach (ImageCodecInfo ici in ImageCodecInfo.GetImageEncoders())
							if (ici.FormatDescription == "JPEG")
							{
								jpegencoder = ici;
								break;
							}
						if (jpegencoder == null)
							throw new Exception("No JPEG encoder found");
						stream = new MemoryStream();
						b.Save(stream, jpegencoder, ep);
					}
					
					stream.Position = 0;
					sc.AddCB_MM(0, new RepImageMM(stream, thumbnailwidth, thumbnailheight));

					double minxpos = xpos;
					xpos += thumbnailwidth + 1;
					double maxxpos = minxpos + 93;
					double thumbnailypos = ypos + thumbnailheight + 2;
					
					// push down text to fit
					ypos += 2.5;

					ArrayList data = new ArrayList();
					// add slide counter
					data.Add(new DictionaryEntry(
						page.GetLocalString(page, "Slide", "Slide"), (i + 1).ToString()));

					// add catalog data					
					data.Add(new DictionaryEntry(
						page.GetLocalString(page, "Collection", "Collection"), 
						image.GetCollectionTitle()));
					foreach (Field f in image.GetFields())
						foreach (string s in image.GetDisplayValues(f, ViewMode.Long, "..."))
							data.Add(new DictionaryEntry(f.Label, s));
					if (image.UserName != null)
						data.Add(new DictionaryEntry(
							page.GetLocalString(page, "Owner", "Owner"), image.UserName));
					if (slides[i].Annotation != null && slides[i].Annotation.Length > 0)
						data.Add(new DictionaryEntry(
							page.GetLocalString(page, "SlideAnnotation", "Slide Annotation"), 
							slides[i].Annotation));
					if (annotations[i] != null && annotations[i].Length > 0)
						data.Add(new DictionaryEntry(
							page.GetLocalString(page, "ImageNotes", "Image Notes"),
							annotations[i]));

					bool pack = !Configuration.Instance.ContainsKey("ui.notecards.pack") ||
						Configuration.Instance.GetBool("ui.notecards.pack");

					foreach (DictionaryEntry entry in data)
					{
						if (!pack)
							NextLine(ref xpos, ref ypos, ref thumbnailypos, 
								ref minxpos, ref maxxpos, thumbnailwidth);

						Paragraph l = new Paragraph(entry.Key + ":");
						while (l.HasMoreFragments())
						{
							RepObj[] objects = l.GetNextLine(labelfont, maxxpos - xpos);
							if (xpos > minxpos && objects.Length == 1 &&
								objects[0].rWidthMM > maxxpos - xpos)
								NextLine(ref xpos, ref ypos, ref thumbnailypos, 
									ref minxpos, ref maxxpos, thumbnailwidth);
							xpos = AddObjectsToPage(page_Cur, xpos, ypos, objects);
							if (!l.HasMoreFragments())
								xpos += 1;
							if (l.HasMoreFragments() || xpos > maxxpos)
								NextLine(ref xpos, ref ypos, ref thumbnailypos, 
									ref minxpos, ref maxxpos, thumbnailwidth);
						}
						
//						string leftover;
//						RepObj label = Paragraph.GetFragment(labelfont, entry.Key + ":", maxxpos - xpos, out leftover);
						
//						if (xpos + label.rWidthMM > maxxpos)
//							NextLine(ref xpos, ref ypos, ref thumbnailypos, 
//								ref minxpos, ref maxxpos, thumbnailwidth);
						
//						xpos = AddObjectsToPage(page_Cur, xpos, ypos /*+ label.rHeightMM*/, label);
						//xpos += label.rWidthMM + 1;

						Paragraph p = new Paragraph((string)entry.Value);
						while (p.HasMoreFragments())
						{
							RepObj[] objects = p.GetNextLine(textfont, maxxpos - xpos);
							if (xpos > minxpos && objects.Length == 1 &&
								objects[0].rWidthMM > maxxpos - xpos)
								NextLine(ref xpos, ref ypos, ref thumbnailypos, 
									ref minxpos, ref maxxpos, thumbnailwidth);
							xpos = AddObjectsToPage(page_Cur, xpos, ypos, objects);
							//RepObj obj = p.GetNextFragment(textfont, maxxpos - xpos);
//							if (obj.rWidthMM > maxxpos - xpos)
//							if (!p.CanFitNextWord(textfont, maxxpos - xpos))
							if (!p.HasMoreFragments())
								xpos += 1;
							if (p.HasMoreFragments() || xpos > maxxpos)
								NextLine(ref xpos, ref ypos, ref thumbnailypos, 
									ref minxpos, ref maxxpos, thumbnailwidth);
							
//							xpos = AddObjectsToPage(page_Cur, xpos, ypos/* + obj.rHeightMM*/, obj);

//							RepString s = new RepString(textfont, 
//								p.GetNextLine(textfont, maxxpos - xpos, null));
//							page_Cur.AddMM(xpos, ypos + s.rHeightMM, s);
							
//							if (p.HasMoreFragments())
//								NextLine(ref xpos, ref ypos, ref thumbnailypos, 
//									ref minxpos, ref maxxpos, thumbnailwidth);
//							else
//								xpos += s.rWidthMM + 1;
						}
//						xpos += 1;
					}
					ypos += LINESPACING;
					if (ypos < thumbnailypos)
						ypos = thumbnailypos + 1;
					else
						ypos += 1;
					xpos = minxpos;
				}
			}
		}
		
		private void Page_Init(object sender, System.EventArgs e)
		{
			Orciid.Core.User user = Session["CurrentUser"] as Orciid.Core.User;
			if (user != null)
				user.Activate(Request.UserHostAddress);
			else
				Response.Redirect("insufficientprivileges.aspx"); 
			int id = 0;
			try
			{
				id = Int32.Parse(Request.QueryString["ssid"]);
			}
			catch (Exception)
			{
			}
			if (id != 0)
			{
				PrintShowReport report = new PrintShowReport(Slideshow.GetByID(id), 
					Session["slideshowpassword:" + id.ToString()] as string, this);
				OutputReport(report, "printview" + id.ToString());
			}
			else
				throw new Exception("No slideshow specified");
		}

		#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.Page_Init);
		}
		#endregion

	}
}