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 notecards : PageTemplate.PdfGeneratingPage 
	{
		private class NoteCardReport: 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 NoteCardReport(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 void AddBlankPage()
			{
				string leftover;
				FontProp hintfont = new FontPropMM(fontdef, 1.5);
				hintfont.color = Color.DarkGray;
				PenProp pen = new PenProp(this, 0.5, Color.DarkGray);
				pen.rPatternOn = 1;
				pen.rPatternOff = 2;
				new Root.Reports.Page(this);
				page_Cur.rHeightMM = 279.4;
				page_Cur.rWidthMM = 215.9;
				page_Cur.AddCB_MM(8.5, new RepLineMM(pen, 0, -262.4));
				page_Cur.AddCB_MM(93.1, new RepLineMM(pen, 199.0, 0));
				page_Cur.AddMM(20, 93.6, Paragraph.GetFragment(hintfont, page.GetLocalString(page, "CutHere", "Cut here"), 100, out leftover));
				page_Cur.AddCB_MM(186.3, new RepLineMM(pen, 199.0, 0));
				page_Cur.AddMM(20, 186.8, Paragraph.GetFragment(hintfont, page.GetLocalString(page, "CutHere", "Cut here"), 100, out leftover));
				RepObj fold = Paragraph.GetFragment(hintfont, page.GetLocalString(page, "FoldHere", "Fold here"), 100, out leftover);
				fold.RotateTransform(90);
				page_Cur.AddMM(107.3, 20, fold);
			}

			protected override void Create() 
			{	
				fontdef = new FontDef(this, FontDef.StandardFont.Helvetica);
				FontProp textfont = new FontPropMM(fontdef, 2.0);
				FontProp labelfont = new FontPropMM(fontdef, 2.0);
				labelfont.bBold = true;
				PenProp blackpen = new PenProp(this, 0.5, Color.Black);

				for (int i = 0; i < slides.Length; i++)
				{
					if (i % 3 == 0)
						AddBlankPage();
					
					Orciid.Core.Image image = images[i];
					if (image == null)
						continue;
					System.IO.Stream stream = show.GetResourceData(password, images[i].ID, ImageSize.Medium);
					
					StaticContainer sc = new StaticContainer(RT.rPointFromMM(88.9), RT.rPointFromMM(76.2));
					page_Cur.AddMM(8.5, 84.7 + 93.1 * (i % 3), 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;
					double bitmapratio = (double)bitmap.Width / (double)bitmap.Height;
					if (bitmapratio > 3.5 / 3.0)
					{
						double heightmm = 88.9 / bitmap.Width * bitmap.Height;
						RepImageMM repimg = new RepImageMM(stream, 88.9, Double.NaN);
						sc.AddMM(0,  -(76.2 - heightmm) / 2, repimg);
					}
					else
						sc.AddCB_MM(0, new RepImageMM(stream, Double.NaN, 76.2));

					double ypos = 8.5 + 93.1 * (i % 3) + 2.0;
					double xpos = 118.5;
					double height = 76.2;
					double width = 88.9;
					double yend = ypos + height;
					double xend = xpos + width;

					// add slide counter
					RepString slidecounter = new RepString(textfont, String.Format("{0}/{1}", i + 1, slides.Length));
					page_Cur.AddMM(xend - slidecounter.rWidthMM, ypos, slidecounter);
					
					string leftover;

					// add slide show owner and title
					string initial = (owner.FirstName != null ? owner.FirstName.Substring(0, 1) : "");
					RepObj ownerstring = Paragraph.GetFragment(labelfont, String.Format("({0}{1}{2})",
						initial, (initial.Length > 0 ? ". " : ""), owner.LastName), width, out leftover);
					Paragraph title = new Paragraph(show.Title);
					xpos = AddObjectsToPage(page_Cur, xpos, ypos, title.GetNextLine(labelfont, 
						width - 2.0 - slidecounter.rWidthMM - ownerstring.rWidthMM));
					page_Cur.AddMM(xpos + 1.0, ypos, ownerstring);
					xpos = 118.5;

					ypos += 5.0;

					// add annotation and notes
					ArrayList lines = new ArrayList();
					
					if (slides[i].Annotation != null)
					{
						Paragraph p = new Paragraph(slides[i].Annotation);
						while (p.HasMoreFragments())
							lines.Add(p.GetNextLine(textfont, width));
					}
					if (annotations[i] != null)
					{
						Paragraph p = new Paragraph(annotations[i]);
						while (p.HasMoreFragments())
							lines.Add(p.GetNextLine(textfont, width));
					}

					if (lines.Count > 0)
					{
						if (lines.Count > 15)
							lines.RemoveRange(15, lines.Count - 15);
						double y = yend - (lines.Count - 1) * 4.0;
						yend = y - 8.0;
						page_Cur.AddMM(xpos, y - 5.5, new RepLineMM(blackpen, width, 0));
						foreach (RepObj[] objs in lines)
						{
							double x = xpos;
							foreach (RepObj obj in objs)
							{
								page_Cur.AddMM(x, y, obj);
								x += obj.rWidthMM;
							}
							y += 4.0;
						}
					}
					
					// add catalog data
					ArrayList data = new ArrayList();
					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));

					foreach (DictionaryEntry entry in data)
					{
						RepObj label = Paragraph.GetFragment(labelfont, entry.Key + ": ", width, out leftover);
						page_Cur.AddMM(xpos, ypos, label);
						Paragraph p = new Paragraph((string)entry.Value);
						AddObjectsToPage(page_Cur, xpos + label.rWidthMM, ypos, 
							p.GetNextLine(textfont, width - label.rWidthMM));
						ypos += 4.0;
						while (p.HasMoreFragments() && ypos < yend)
						{
							AddObjectsToPage(page_Cur, xpos + 5.0, ypos,
								p.GetNextLine(textfont, width - 5.0));
							ypos += 4.0;
						}
						if (ypos > yend)
							break;
					}
				}
			}
		}
		
		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)
			{
				NoteCardReport report = new NoteCardReport(Slideshow.GetByID(id), 
					Session["slideshowpassword:" + id.ToString()] as string, this);
				OutputReport(report, "flashcard" + 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

	}
}