using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tao.OpenGl;
using LibEveryFileExplorer._3D;
using System.Drawing.Imaging;
using NDS.NitroSystem.G3D;
using NDS.GPU;
using LibEveryFileExplorer.Files;
using LibEveryFileExplorer;
using System.Runtime.InteropServices;

namespace NDS.UI
{
	public partial class NSBMDViewer : Form, IUseOtherFiles
	{
		ImageList ImageL;
		MDL0Viewer ModViewer = null;

		NSBMD mod;
		NSBTX tex = null;

		public NSBMDViewer(NSBMD mod)
		{
			this.mod = mod;
			InitializeComponent();
			Win32Util.SetWindowTheme(treeView1.Handle, "explorer", null);
			ImageL = new ImageList();
			ImageL.ColorDepth = ColorDepth.Depth32Bit;
			ImageL.ImageSize = new Size(16, 16);
			ImageL.Images.Add(Resource.jar);
			ImageL.Images.Add(Resource.point);
			ImageL.Images.Add(Resource.fruit);
			ImageL.Images.Add(Resource.molecule);
			ImageL.Images.Add(Resource.image_sunset16);
			ImageL.Images.Add(Resource.color_swatch);
			ImageL.Images.Add(Resource.images_stack);
			ImageL.Images.Add(Resource.fruit_grape);
			ImageL.Images.Add(Resource.node);
			ImageL.Images.Add(Resource.color_swatches);
			ImageL.Images.Add(Resource.images_stack);
			treeView1.ImageList = ImageL;
		}


		private void CGFX_Load(object sender, EventArgs e)
		{
			treeView1.BeginUpdate();
			treeView1.Nodes.Clear();
			if (mod.ModelSet != null)
			{
				TreeNode mdl0 = new TreeNode("MDL0", 0, 0);
				mdl0.Expand();
				treeView1.Nodes.Add(mdl0);
				for (int i = 0; i < mod.ModelSet.models.Length; i++)
				{
					TreeNode mdl = new TreeNode(mod.ModelSet.dict[i].Key, 1, 1) { Tag = mod.ModelSet.models[i] };
					mdl0.Nodes.Add(mdl);
					if (i == 0) treeView1.SelectedNode = mdl;
					var v = mod.ModelSet.models[i];
					TreeNode n = new TreeNode("Nodes", 8, 8);
					mdl.Nodes.Add(n);
					for (int j = 0; j < v.nodes.data.Length; j++)
					{
						n.Nodes.Add(new TreeNode(v.nodes.dict[j].Key, 3, 3) { Tag = v.nodes.data[j] });
					}
					n = new TreeNode("Materials", 7, 7);
					mdl.Nodes.Add(n);
					for (int j = 0; j < v.materials.materials.Length; j++)
					{
						n.Nodes.Add(new TreeNode(v.materials.dict[j].Key, 2, 2) { Tag = v.materials.materials[j] });
					}
					n = new TreeNode("Textures", 10, 10);
					mdl.Nodes.Add(n);
					for (int j = 0; j < v.materials.dictTexToMatList.numEntry; j++)
					{
						n.Nodes.Add(new TreeNode(v.materials.dictTexToMatList[j].Key, 4, 4) { Tag = v.materials.dictTexToMatList[j].Value });
					}
					n = new TreeNode("Palettes", 9, 9);
					mdl.Nodes.Add(n);
					for (int j = 0; j < v.materials.dictPlttToMatList.numEntry; j++)
					{
						n.Nodes.Add(new TreeNode(v.materials.dictPlttToMatList[j].Key, 5, 5) { Tag = v.materials.dictPlttToMatList[j].Value });
					}
				}
			}
			if (mod.TexPlttSet != null)
			{
				treeView1.Nodes.Add(new TreeNode("TEX0", 6, 6));
			}
			treeView1.EndUpdate();
			//LoadTex();
		}

		private void LoadTex()
		{
			try
			{
				TEX0 tt;
				if (mod.TexPlttSet != null) tt = mod.TexPlttSet;
				else if (tex != null) tt = tex.TexPlttSet;
				else return;
				for (int i = 0; i < mod.ModelSet.models.Length; i++)
				{
					for (int j = 0; j < mod.ModelSet.models[i].materials.materials.Length; j++)
					{
						TEX0.DictTexData t = null;
						for (int k = 0; k < mod.ModelSet.models[i].materials.dictTexToMatList.numEntry; k++)
						{
							if (mod.ModelSet.models[i].materials.dictTexToMatList[k].Value.Materials.Contains((byte)j))
							{
								int texid = k;
								for (int l = 0; l < tt.dictTex.numEntry; l++)
								{
									if (tt.dictTex[l].Key == mod.ModelSet.models[i].materials.dictTexToMatList[k].Key) { texid = l; break; }
								}
								t = tt.dictTex[texid].Value;
								break;
							}
						}
						if (t == null)
							continue;
						mod.ModelSet.models[i].materials.materials[j].Fmt = t.Fmt;
						mod.ModelSet.models[i].materials.materials[j].origHeight = t.T;
						mod.ModelSet.models[i].materials.materials[j].origWidth = t.S;
						TEX0.DictPlttData p = null;
						if (t.Fmt != Textures.ImageFormat.DIRECT)
						{
							for (int k = 0; k < mod.ModelSet.models[i].materials.dictPlttToMatList.numEntry; k++)
							{
								if (mod.ModelSet.models[i].materials.dictPlttToMatList[k].Value.Materials.Contains((byte)j))
								{
									int palid = k;
									for (int l = 0; l < tt.dictPltt.numEntry; l++)
									{
										if (tt.dictPltt[l].Key == mod.ModelSet.models[i].materials.dictPlttToMatList[k].Key) { palid = l; break; }
									}
									p = tt.dictPltt[palid].Value;
									break;
								}
							}
						}
						UploadTex(t.ToBitmap(p), mod.ModelSet.models[i].materials.materials[j], j + 1);//+ offset);
					}
				}
			}
			catch { }
		}

		private void UploadTex(Bitmap b, MDL0.Model.MaterialSet.Material m, int Id)
		{
			Gl.glBindTexture(Gl.GL_TEXTURE_2D, Id);
			Gl.glColor3f(1, 1, 1);
			BitmapData d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
			Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, b.Width, b.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, d.Scan0);
			b.UnlockBits(d);
			Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
			Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
			bool repeatS = (m.texImageParam >> 16 & 0x1) == 1;
			bool repeatT = (m.texImageParam >> 17 & 0x1) == 1;
			bool flipS = (m.texImageParam >> 18 & 0x1) == 1;
			bool flipT = (m.texImageParam >> 19 & 0x1) == 1;
			int S;
			if (repeatS && flipS)
			{
				S = Gl.GL_MIRRORED_REPEAT;
			}
			else if (repeatS)
			{
				S = Gl.GL_REPEAT;
			}
			else
			{
				S = Gl.GL_CLAMP;
			}
			int T;
			if (repeatT && flipT)
			{
				T = Gl.GL_MIRRORED_REPEAT;
			}
			else if (repeatT)
			{
				T = Gl.GL_REPEAT;
			}
			else
			{
				T = Gl.GL_CLAMP;
			}
			Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, S);
			Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, T);
		}

		private void CGFX_Resize(object sender, EventArgs e)
		{
			if (ModViewer != null)
			{
				ModViewer.Render();
				ModViewer.Render();
			}
		}

		private void CGFX_Layout(object sender, LayoutEventArgs e)
		{
			if (ModViewer != null)
			{
				ModViewer.Render();
			}
		}

		private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e)
		{
			if (ModViewer != null)
			{
				ModViewer.Render();
			}
		}

		public void FileOpened(ViewableFile File)
		{
			if (!(File.FileFormat is NSBTX)) return;
			ViewableFile[] v = EveryFileExplorerUtil.GetOpenFilesOfType(typeof(NSBTX));
			menuItem1.MenuItems.Clear();
			bool curavab = false;
			foreach (var vv in v)
			{
				var m = menuItem1.MenuItems.Add(vv.File.Name);
				if (vv.FileFormat == tex)
				{
					curavab = true;
					m.Checked = true;
				}
			}
			if (!curavab && v.Length != 0)
			{
				menuItem1.MenuItems[0].Checked = true;
				tex = v[0].FileFormat;
			}
			LoadTex();
			if (ModViewer != null)
			{
				ModViewer.Render();
				ModViewer.Render();
			}
		}

		public void FileClosed(ViewableFile File)
		{
			if (File.FileFormat is NSBTX && File.FileFormat == tex) tex = null;
			ViewableFile[] v = EveryFileExplorerUtil.GetOpenFilesOfType(typeof(NSBTX));
			menuItem1.MenuItems.Clear();
			foreach (var vv in v)
			{
				menuItem1.MenuItems.Add(vv.File.Name);
			}
			if (v.Length != 0)
			{
				menuItem1.MenuItems[0].Checked = true;
				tex = v[0].FileFormat;
			}
			LoadTex();
			if (ModViewer != null)
			{
				ModViewer.Render();
				ModViewer.Render();
			}
		}

		private void NSBMDViewer_Activated(object sender, EventArgs e)
		{
			//otherwise the nsbtx menu is not refreshed!
			mainMenu1.MenuItems.Clear();
			mainMenu1.MenuItems.Add(menuItem1);
			//render it multiple times to avoid glitches!
			if (ModViewer != null)
			{
				for (int i = 0; i < 8; i++) ModViewer.Render();
			}
		}

		private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
		{
			switch (e.Node.ImageIndex)
			{
				case 1:
					ModViewer = new MDL0Viewer((MDL0.Model)e.Node.Tag) { Dock = DockStyle.Fill };
					ModViewer.Width = panel1.Width;
					ModViewer.Height = panel1.Height;
					panel1.SuspendLayout();
					panel1.Controls.Add(ModViewer);
					if (panel1.Controls.Count > 1) panel1.Controls.RemoveAt(0);
					panel1.Invalidate();
					panel1.ResumeLayout();
					ModViewer.Invalidate();
					LoadTex();
					ModViewer.Render();
					ModViewer.Render();
					break;
				case 2:
					ModViewer = null;
					panel1.SuspendLayout();
					panel1.Controls.Add(new MDL0MaterialEditor((MDL0.Model.MaterialSet.Material)e.Node.Tag) { Dock = DockStyle.Fill, Width = panel1.Width, Height = panel1.Height });
					if (panel1.Controls.Count > 1) panel1.Controls.RemoveAt(0);
					panel1.Invalidate();
					panel1.ResumeLayout();
					break;
				case 6:
					ModViewer = null;
					panel1.SuspendLayout();
					panel1.Controls.Add(new TEX0Viewer(mod.TexPlttSet) { Dock = DockStyle.Fill, Width = panel1.Width, Height = panel1.Height });
					if (panel1.Controls.Count > 1) panel1.Controls.RemoveAt(0);
					panel1.Invalidate();
					panel1.ResumeLayout();
					break;
				default:
					ModViewer = null;
					panel1.SuspendLayout();
					panel1.Controls.Clear();
					panel1.Invalidate();
					panel1.ResumeLayout();
					break;
			}
		}

		private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
		{
			if (ModViewer != null)
			{
				ModViewer.Render();
			}
		}
	}
}
