using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using ScrewTurn.Wiki;
using ScrewTurn.Wiki.PluginFramework;
using System.Drawing.Imaging;

namespace ScrewTurn.Wiki {

	public partial class ImageEditor : BasePage {

		private MemoryStream resultMemStream = null;
		private string file = "";
		private string page = "";
		private IFilesStorageProviderV30 provider = null;

		protected void Page_Load(object sender, EventArgs e) {
			SetProvider();
			SetInputData();

			string currentUser = SessionFacade.GetCurrentUsername();
			string[] currentGroups = SessionFacade.GetCurrentGroupNames();
			string dir = Tools.GetDirectoryName(file);

			// Verify permissions
			bool canUpload = AuthChecker.CheckActionForDirectory(provider, dir,
				Actions.ForDirectories.UploadFiles, currentUser, currentGroups);
			bool canDeleteFiles = AuthChecker.CheckActionForDirectory(provider, dir,
				Actions.ForDirectories.DeleteFiles, currentUser, currentGroups);

			if(!canUpload || !canDeleteFiles) UrlTools.Redirect("AccessDenied.aspx");

			// Inject the proper stylesheet in page head
			Literal l = new Literal();
			l.Text = Tools.GetIncludes(DetectNamespace());
			Page.Header.Controls.Add(l);

			ResizeImage();
		}

		private void SetProvider() {
			string p = Request["Provider"];
			if(string.IsNullOrEmpty(p)) {
				p = Settings.DefaultFilesProvider;
			}
			provider = Collectors.FilesProviderCollector.GetProvider(p);
		}

		private void SetInputData() {
			page = Request["page"];

			file = Request["File"];
			if(string.IsNullOrEmpty(file)) {
				Response.Write("No file specified.");
				return;
			}
			file = file.Replace("..", "");
		}

		private int GetSelectedRotation() {
			if(rdo90CW.Checked) return 90;
			else if(rdo90CCW.Checked) return 270;
			else if(rdo180.Checked) return 180;
			else return 0;
		}

		private void ResizeImage() {
			SetProvider();
			SetInputData();

			// Contains the image bytes
			MemoryStream ms = new MemoryStream(1048576);

			// Load from provider
			if(string.IsNullOrEmpty(page)) {
				if(!provider.RetrieveFile(file, ms, false)) {
					Response.StatusCode = 404;
					Response.Write("File not found.");
					return;
				}
			}
			else {
				PageInfo info = Pages.FindPage(page);
				if(info == null) {
					Response.StatusCode = 404;
					Response.WriteFile("Page not found.");
					return;
				}

				if(!provider.RetrievePageAttachment(info, file, ms, false)) {
					Response.StatusCode = 404;
					Response.WriteFile("File not found.");
					return;
				}
			}

			// Setup new file name and image format
			if(!Page.IsPostBack) {
				string ext = Path.GetExtension(file);
				txtNewName.Text = Path.GetFileNameWithoutExtension(file) + "-2" + ext;
				switch(ext.ToLowerInvariant()) {
					case ".jpg":
					case ".jpeg":
						rdoPng.Checked = false;
						rdoJpegHigh.Checked = true;
						rdoJpegMedium.Checked = false;
						break;
					default:
						rdoPng.Checked = true;
						rdoJpegHigh.Checked = false;
						rdoJpegMedium.Checked = false;
						break;
				}

			}

			ms.Seek(0, SeekOrigin.Begin);

			// Load the source image
			System.Drawing.Image source = System.Drawing.Image.FromStream(ms);

			lblCurrentSize.Text = string.Format("{0}x{1}", source.Width, source.Height);
			if(!Page.IsPostBack) {
				txtWidth.Text = source.Width.ToString();
				txtHeight.Text = source.Height.ToString();
			}

			// Put dimension in script
			lblDimensions.Text = "<script type=\"text/javascript\"><!--\r\nvar width = " +
				source.Width.ToString() +
				";\r\nvar height = " + source.Height.ToString() +
				";\r\n// -->\r\n</script>";

			int resultWidth = source.Width;
			int resultHeight = source.Height;

			if(rdoPercentage.Checked) {
				// Resize by percentage
				int dim = 100;
				if(string.IsNullOrEmpty(txtPercentage.Text)) dim = 100;
				else {
					try {
						dim = int.Parse(txtPercentage.Text);
					}
					catch(FormatException) { }
				}

				// Possible final preview dimensions
				resultWidth = source.Width * dim / 100;
				resultHeight = source.Height * dim / 100;
			}
			else {
				// Resize by pixel
				if(!string.IsNullOrEmpty(txtWidth.Text) && !string.IsNullOrEmpty(txtHeight.Text)) {
					try {
						resultWidth = int.Parse(txtWidth.Text);
						resultHeight = int.Parse(txtHeight.Text);
					}
					catch(FormatException) { }
				}
			}

			int rotation = GetSelectedRotation();

			// Draw preview
			if(resultWidth > 290 || resultHeight > 290) {
				int previewWidth = resultWidth;
				int previewHeight = resultHeight;

				// Max preview dimension 290x290
				if(resultWidth > resultHeight) {
					previewWidth = 290;
					previewHeight = (int)((float)290 / (float)resultWidth * (float)resultHeight);
					lblScale.Text = string.Format("{0:N0}", (float)290 / (float)resultWidth * 100);
				}
				else {
					previewHeight = 290;
					previewWidth = (int)((float)290 / (float)resultHeight * (float)resultWidth);
					lblScale.Text = string.Format("{0:N0}", (float)290 / (float)resultHeight * 100);
				}
				imgPreview.ImageUrl = "Thumb.aspx?File=" + Request["File"] +
					@"&Size=imgeditprev&Width=" + previewWidth + @"&Height=" + previewHeight +
					@"&Page=" + (string.IsNullOrEmpty(page) ? "" : page) +
					(!rdoNoRotation.Checked ? ("&Rot=" + rotation.ToString()) : "");
			}
			else {
				lblScale.Text = "100";
				imgPreview.ImageUrl = "Thumb.aspx?File=" + Request["File"] +
					@"&Size=imgeditprev&Width=" + resultWidth + @"&Height=" + resultHeight +
					@"&Page=" + (string.IsNullOrEmpty(page) ? "" : page) +
					(!rdoNoRotation.Checked ? ("&Rot=" + rotation.ToString()) : "");
			}

			// Destination bitmap
			Bitmap result = new Bitmap(
				rotation != 90 && rotation != 270 ? resultWidth : resultHeight,
				rotation != 90 && rotation != 270 ? resultHeight : resultWidth,
				System.Drawing.Imaging.PixelFormat.Format32bppArgb);

			// Get Graphics object for destination bitmap
			Graphics g = Graphics.FromImage(result);
			g.Clear(Color.Transparent);

			g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
			g.SmoothingMode = SmoothingMode.HighQuality;
			g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;

			g.TranslateTransform(result.Width / 2, result.Height / 2);
			g.RotateTransform(rotation);
			g.TranslateTransform(-result.Width / 2, -result.Height / 2);

			// Draw bitmap
			g.DrawImage(source, GetImageRectangle(result.Width, result.Height,
				rotation != 90 && rotation != 270 ? source.Width : source.Height,
				rotation != 90 && rotation != 270 ? source.Height : source.Width,
				rotation == 90 || rotation == 270));

			// Prepare encoder parameters
			string format = GetCurrentFormat();
			resultMemStream = new MemoryStream(1048576);

			// Only JPEG and PNG images are editable
			if(format == "image/jpeg") {
				EncoderParameters encoderParams = new EncoderParameters(1);
				encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, rdoJpegHigh.Checked ? 100L : 60L);

				result.Save(resultMemStream, GetEncoderInfo(format), encoderParams);
			}
			else {
				result.Save(resultMemStream, ImageFormat.Png);
			}

			resultMemStream.Seek(0, SeekOrigin.Begin);

			// Dispose of source and result bitmaps
			source.Dispose();
			g.Dispose();
			result.Dispose();
		}

		private static ImageCodecInfo GetEncoderInfo(string mimeType) {
			int j;
			ImageCodecInfo[] encoders;
			encoders = ImageCodecInfo.GetImageEncoders();
			for(j = 0; j < encoders.Length; ++j) {
				if(encoders[j].MimeType == mimeType)
					return encoders[j];
			}
			return null;
		}

		private string GetCurrentFormat() {
			if(chkNewName.Checked) {
				if(rdoPng.Checked) return "image/png";
				else return "image/jpeg";
			}
			else {
				switch(Path.GetExtension(file).ToLowerInvariant()) {
					case ".jpg":
					case ".jpeg":
						return "image/jpeg";
					default:
						return "image/png";
				}
			}
		}

		private Rectangle GetImageRectangle(int targetW, int targetH, int w, int h, bool swapped) {
			if(w == h) {
				// Square
				return new Rectangle(0, 0, targetW, targetH);
			}
			else if(w > h) {
				// Landscape
				float scale = (float)targetW / (float)w;
				if(targetW > w) scale = 1;
				int width = (int)(w * scale);
				int height = (int)(h * scale);

				if(swapped) {
					int temp = width;
					width = height;
					height = temp;
				}

				return new Rectangle((targetW - width) / 2, (targetH - height) / 2, width, height);
			}
			else {
				// Portrait
				float scale = (float)targetH / (float)h;
				if(targetH > h) scale = 1;
				int width = (int)(w * scale);
				int height = (int)(h * scale);

				if(swapped) {
					int temp = width;
					width = height;
					height = temp;
				}

				return new Rectangle((targetW - width) / 2, (targetH - height) / 2, width, height);
			}
		}

		protected void btnPreview_Click(object sender, EventArgs e) {
			//ResizeImage();
		}

		protected void btnSave_Click(object sender, EventArgs e) {
			ResizeImage();
			bool done = false;

			string targetName = chkNewName.Checked ? txtNewName.Text : Path.GetFileName(file);
			bool overwrite = !chkNewName.Checked;

			if(targetName.Length == 0 || Path.GetFileNameWithoutExtension(targetName).Length == 0) {
				lblResult.CssClass = "resulterror";
				lblResult.Text = Properties.Messages.InvalidFileName;
				return;
			}

			if(!overwrite) {
				// Force extension
				targetName = Path.ChangeExtension(targetName,
					rdoPng.Checked ? "png" : "jpg");
			}

			if(string.IsNullOrEmpty(page)) {
				string path = (file.LastIndexOf('/') > 0) ? file.Substring(0, file.LastIndexOf('/') + 1) : "";
				done = provider.StoreFile(path + targetName, resultMemStream, overwrite);
			}
			else {
				done = provider.StorePageAttachment(Pages.FindPage(page), targetName, resultMemStream, overwrite);
			}

			if(done) {
				lblResult.Text = Properties.Messages.FileSaved;
				lblResult.CssClass = "resultok";
			}
			else {
				lblResult.Text = Properties.Messages.CouldNotSaveFile;
				lblResult.CssClass = "resulterror";
			}
		}

		protected void chkNewName_CheckedChanged(object sender, EventArgs e) {
			txtNewName.Enabled = chkNewName.Checked;
			rdoPng.Enabled = chkNewName.Checked;
			rdoJpegHigh.Enabled = chkNewName.Checked;
			rdoJpegMedium.Enabled = chkNewName.Checked;
		}

		protected void rdoFormat_CheckedChanged(object sender, EventArgs e) {
			string ext = "";
			if(rdoPng.Checked) {
				ext = ".png";
			}
			else {
				ext = ".jpg";
			}
			txtNewName.Text = Path.ChangeExtension(txtNewName.Text, ext);
		}

	}

}