using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Text.RegularExpressions;
using Orciid.Core;
using Root.Reports;
using System.IO;

namespace Orciid.PageTemplate
{
	public class PdfGeneratingPage: LocalPage
	{

		protected class Paragraph
		{
			private string remainder = null;

			public Paragraph(string s)
			{
				remainder = Cleanup(s);
			}

			private static string Cleanup(string s)
			{
				if (s == null)
					return null;
#if MONO
#warning Unicode support in PDF files is not supported under Mono at this time
				StringBuilder b = new StringBuilder(s.Length);
				for (int i = 0; i < s.Length; i++)
					b.Append(s[i] > 0xFF ? '?' : s[i]);
				return b.ToString();
#else
				return s;
#endif
			}

			[Obsolete]
			public string GetNextLine(FontProp font, double maxWidthMM, string ellipsis)
			{
				if (remainder == null || remainder.Length == 0)
				{
					remainder = null;
					return "";
				}
				string p = remainder;
				double w = maxWidthMM;
				if (font.rWidthMM(p) > w)
					w = maxWidthMM - (ellipsis != null ? font.rWidthMM(ellipsis) : 0);
				while (p.Length > 0 && font.rWidthMM(p) > w)
				{
					int i = p.LastIndexOf(' ');
					p = p.Substring(0, (i > -1 ? i : p.Length - 1));
				}
				if (p.Length == 0)
					throw new Exception("Cannot fit next character in given space");
				if (p != remainder)
				{
					remainder = remainder.Substring(p.Length).TrimStart(new char[] { ' ' });
					p += ellipsis;
				}
				else
					remainder = null;
				return p;
			}

			public bool HasMoreFragments()
			{
				return (remainder != null && remainder.Length > 0);
			}

			[Obsolete]
			public bool CanFitNextWord(FontProp font, double maxWidthMM)
			{
				int i = remainder.IndexOf(' ');
				if (i == -1)
					return font.rWidthMM(remainder) <= maxWidthMM;
				else
					return font.rWidthMM(remainder.Substring(0, i)) <= maxWidthMM;
			}

			public RepObj[] GetNextLine(FontProp font, double maxWidthMM)
			{
				ArrayList items = new ArrayList();
				double usedWidth = 0.0;
				double usedHeight = 0.0;
				while (HasMoreFragments())
				{
					string word = GetNextWord();
					string leftover = null;
					RepObj fragment = GetFragment(font, word, maxWidthMM - usedWidth, out leftover);
                    if (leftover == null && items.Count > 0 && usedWidth + fragment.rWidthMM > maxWidthMM)
					{
						PushBackWord(word);
						break;
					}
					else
					{
						items.Add(fragment);
						usedWidth += fragment.rWidthMM;
						usedHeight = Math.Max(usedHeight, fragment.rHeightMM);
						if (leftover != null)
						{
							PushBackWord(leftover);
							break;
						}
					}
				}
				return (RepObj[])items.ToArray(typeof(RepObj));
			}

			public RepObj GetNextFragment(FontProp font, double maxwidth, out string leftover)
			{
				return GetFragment(font, GetNextWord(), maxwidth, out leftover);
			}

			public static RepObj GetFragment(FontProp font, string text, double maxwidth, out string leftover)
			{
				leftover = null;
				if (ContainsExtendedChars(text))
				{
					Bitmap b = new Bitmap(1, 1, PixelFormat.Format24bppRgb);
					Graphics g = Graphics.FromImage(b);
					// FogBugz case 555: mono does not have the Arial Unicode MS font
					Font f = new Font("Arial Unicode MS", 24, font.bBold ? FontStyle.Bold : FontStyle.Regular);
					SizeF size;
					bool finished = false;
					do
					{
						size = g.MeasureString(text, f);
						if (size.Width * font.rLineFeedMM / size.Height > maxwidth && text.Length > 1)
						{
							leftover = text[text.Length - 1] + (leftover == null ? "" : leftover);
							text = text.Substring(0, text.Length - 1);
						}
						else
							finished = true;
					} while (!finished);
					StringFormat format = new StringFormat(StringFormatFlags.NoClip);
					b = new Bitmap((int)size.Width, (int)size.Height, PixelFormat.Format24bppRgb);
					g = Graphics.FromImage(b);
					g.FillRectangle(Brushes.White, 0, 0, size.Width, size.Height);
					g.DrawString(text, f, Brushes.Black, 0, 0, format);
					
					// 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");
					MemoryStream stream = new MemoryStream();
					b.Save(stream, jpegencoder, ep);
					//b.Save(stream, ImageFormat.Bmp);
					stream.Position = 0;
					return new RepImageMM(stream, Double.NaN, font.rLineFeedMM);
				}
				else
				{
					return new RepString(font, text);
				}
			}

//			public bool CanFitNextFragment(FontProp font, double maxWidthMM)
//			{
//				return true;
//			}

			private string GetNextWord()
			{
				if (remainder != null)
				{
					remainder.Trim();
					if (remainder.Length == 0)
						remainder = null;
				}
				if (remainder == null)
					return "";
				int i = 1;
				while (i < remainder.Length && !Char.IsWhiteSpace(remainder, i))
					i++;
				string s = remainder.Substring(0, i);
				if (i + 1 < remainder.Length) 
				{
					s += ' ';
					remainder = remainder.Substring(i + 1);
				}
				else
					remainder = null;
				return s;
			}

			private void PushBackWord(string word)
			{
				if (remainder == null)
					remainder = word;
				else
					remainder = word + remainder;
			}

			private static bool ContainsExtendedChars(string s)
			{
				for (int i = 0; i < s.Length; i++)
					if (s[i] > 0x00FF)
						return true;
				return false;
			}
		}

		public PdfGeneratingPage()
		{
		}

		public void OutputReport(Report report, string basefilename)
		{
			Response.Clear();
			Response.Buffer = false;
			Response.ContentType = "application/pdf";
			Response.AddHeader("Content-Disposition", 
				String.Format("filename={0}.pdf", basefilename)); 
			report.formatter.Create(report, Response.OutputStream);
			Response.End();
		}

		public static double AddObjectsToPage(Root.Reports.Page page, double x, double y, params RepObj[] objects)
		{
			foreach (RepObj o in objects)
			{
				page.AddMM(x, y + (o is RepImage ? 1 : 0), o);
				x += o.rWidthMM;
			}
			return x;
		}
	}
}
