#include "texmgr.h"
#include "wtexcontexted.h"
#pragma once

char szTempFilename[128];
FILE* pChunk = NULL;
FILE* pPalFile = NULL;
tTextureList_s* pTex = NULL;
INT iViewingTexture = -1;
INT iLastSelTexture = 0;

namespace DBLFucker {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;
	using namespace System::Threading;

	/// <summary>
	/// Summary for wtexture_viewer
	/// </summary>
	public ref class wtexture_viewer : public System::Windows::Forms::Form
	{
	public:
		wtexcontexted^ pTexContextEd;
		char* szChunkfilename;
		char* tFoundCHCFname;
		array< Bitmap^ >^ pTextureBitmaps;
		Bitmap^ pReservedBitmap;
		Delegate^ delAddToControls;
		Delegate^ delsetButtonsToAvailable;
		Delegate^ delShowTexConEd;
		Thread^ pThread;
	private: System::Windows::Forms::RichTextBox^  richTextBox1;
	private: System::Windows::Forms::Button^  button1;
	private: System::Windows::Forms::Button^  button2;
	private: System::Windows::Forms::OpenFileDialog^  openFileDialog1;
	private: System::Windows::Forms::Button^  button3;
	private: System::Windows::Forms::CheckBox^  checkBox1;
	private: System::Windows::Forms::CheckBox^  checkBox2;
	public: delegate void SetControlsDel( PictureBox^ picbox );
	public: delegate void MakeButtonsAvailableDel( void );
	public: delegate void ShowTexContextEdDel( void );
	private: System::Windows::Forms::Panel^  panel1;

	//private: PictureBox^ texbox;

	public: 

	public: 
		wtexture_viewer(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~wtexture_viewer()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Label^  label1;


	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->label1 = (gcnew System::Windows::Forms::Label());
			this->panel1 = (gcnew System::Windows::Forms::Panel());
			this->richTextBox1 = (gcnew System::Windows::Forms::RichTextBox());
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->button2 = (gcnew System::Windows::Forms::Button());
			this->openFileDialog1 = (gcnew System::Windows::Forms::OpenFileDialog());
			this->button3 = (gcnew System::Windows::Forms::Button());
			this->checkBox1 = (gcnew System::Windows::Forms::CheckBox());
			this->checkBox2 = (gcnew System::Windows::Forms::CheckBox());
			this->SuspendLayout();
			// 
			// label1
			// 
			this->label1->AutoSize = true;
			this->label1->Location = System::Drawing::Point(12, 9);
			this->label1->Name = L"label1";
			this->label1->Size = System::Drawing::Size(51, 13);
			this->label1->TabIndex = 0;
			this->label1->Text = L"Textures:";
			// 
			// panel1
			// 
			this->panel1->AutoScroll = true;
			this->panel1->BackColor = System::Drawing::Color::Black;
			this->panel1->BorderStyle = System::Windows::Forms::BorderStyle::Fixed3D;
			this->panel1->Location = System::Drawing::Point(15, 25);
			this->panel1->Name = L"panel1";
			this->panel1->Size = System::Drawing::Size(588, 355);
			this->panel1->TabIndex = 13;
			this->panel1->Click += gcnew System::EventHandler(this, &wtexture_viewer::panel1_Click);
			// 
			// richTextBox1
			// 
			this->richTextBox1->Location = System::Drawing::Point(15, 386);
			this->richTextBox1->Name = L"richTextBox1";
			this->richTextBox1->Size = System::Drawing::Size(588, 96);
			this->richTextBox1->TabIndex = 14;
			this->richTextBox1->Text = L"";
			// 
			// button1
			// 
			this->button1->Enabled = false;
			this->button1->Location = System::Drawing::Point(15, 488);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(57, 23);
			this->button1->TabIndex = 15;
			this->button1->Text = L"Export";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &wtexture_viewer::button1_Click);
			// 
			// button2
			// 
			this->button2->Enabled = false;
			this->button2->Location = System::Drawing::Point(78, 488);
			this->button2->Name = L"button2";
			this->button2->Size = System::Drawing::Size(61, 23);
			this->button2->TabIndex = 16;
			this->button2->Text = L"Replace";
			this->button2->UseVisualStyleBackColor = true;
			this->button2->Click += gcnew System::EventHandler(this, &wtexture_viewer::button2_Click);
			// 
			// openFileDialog1
			// 
			this->openFileDialog1->FileName = L"openFileDialog1";
			// 
			// button3
			// 
			this->button3->Enabled = false;
			this->button3->Location = System::Drawing::Point(536, 488);
			this->button3->Name = L"button3";
			this->button3->Size = System::Drawing::Size(67, 23);
			this->button3->TabIndex = 17;
			this->button3->Text = L"Extract all";
			this->button3->UseVisualStyleBackColor = true;
			this->button3->Click += gcnew System::EventHandler(this, &wtexture_viewer::button3_Click);
			// 
			// checkBox1
			// 
			this->checkBox1->AutoSize = true;
			this->checkBox1->Checked = true;
			this->checkBox1->CheckState = System::Windows::Forms::CheckState::Checked;
			this->checkBox1->Location = System::Drawing::Point(145, 492);
			this->checkBox1->Name = L"checkBox1";
			this->checkBox1->Size = System::Drawing::Size(190, 17);
			this->checkBox1->TabIndex = 18;
			this->checkBox1->Text = L"Export palettized textures into PNG";
			this->checkBox1->UseVisualStyleBackColor = true;
			// 
			// checkBox2
			// 
			this->checkBox2->AutoSize = true;
			this->checkBox2->Location = System::Drawing::Point(341, 492);
			this->checkBox2->Name = L"checkBox2";
			this->checkBox2->Size = System::Drawing::Size(170, 17);
			this->checkBox2->TabIndex = 19;
			this->checkBox2->Text = L"Export textures in perfect order";
			this->checkBox2->UseVisualStyleBackColor = true;
			// 
			// wtexture_viewer
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(615, 531);
			this->Controls->Add(this->checkBox2);
			this->Controls->Add(this->checkBox1);
			this->Controls->Add(this->button3);
			this->Controls->Add(this->button2);
			this->Controls->Add(this->button1);
			this->Controls->Add(this->richTextBox1);
			this->Controls->Add(this->panel1);
			this->Controls->Add(this->label1);
			this->DoubleBuffered = true;
			this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedToolWindow;
			this->MaximizeBox = false;
			this->MinimizeBox = false;
			this->Name = L"wtexture_viewer";
			this->ShowIcon = false;
			this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
			this->Text = L"Texture Viewer";
			this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &wtexture_viewer::wtexture_viewer_FormClosing);
			this->Load += gcnew System::EventHandler(this, &wtexture_viewer::wtexture_viewer_Load);
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
	void SetControls( PictureBox^ pb ) {
		pb->Location = Point( pb->Location.X-panel1->HorizontalScroll->Value, pb->Location.Y-panel1->VerticalScroll->Value );
		panel1->Controls->Add( pb );
	}
	void SetBTAvailable( void ) {
		button1->Enabled = TRUE; button2->Enabled = TRUE; button3->Enabled = TRUE;
	}

	void ShowTexContextEd( void ) {
		if( IDYES == MessageBoxA(NULL, "The DB_TEXTURE_CONTEXT chunk was located, do you want to load it as well?",
			"Do you?", MB_ICONQUESTION|MB_YESNO) ) {
				pTexContextEd = gcnew wtexcontexted();
				pTexContextEd->szChunkfilename = tFoundCHCFname;
				pTexContextEd->szTexchunkfname = this->szChunkfilename;
				pTexContextEd->Show();
		}
	}

	// Forcing the tex-preview image to be 128x128 proved to be much easier to handle later,
	// cool otherwise
	void LoadupTextures( void ) {
		INT xpos = 24, ypos = 4;

		// Look for a DB_TEXTURE_CONTEXT chunk
		tFoundCHCFname = FindATexContextChunk( szChunkfilename );
		if( tFoundCHCFname ) this->Invoke( delShowTexConEd );

		for( INT i = 0; i < pTex->texturenum; i++ ) {
			PictureBox^ texbox = gcnew PictureBox();
			texbox->Location = Point( xpos, ypos );
			texbox->Size = Drawing::Size( 128, 128 );
			texbox->Tag = i;
			texbox->SizeMode = PictureBoxSizeMode::StretchImage;
			texbox->BorderStyle = BorderStyle::Fixed3D;
			texbox->TabIndex = 0;
			texbox->Cursor = Cursors::Hand;
			texbox->ForeColor = Color::Black;
			texbox->Click += gcnew System::EventHandler( this, &wtexture_viewer::texbox_Click );

			pTextureBitmaps[i] = DrawTextureIntoABMP( pChunk, pTex, i );
			texbox->Image = (Image^)pTextureBitmaps[i];
			// free( pTex->textures[i].pixels ); We need those bytes for texture replacement yep
			panel1->Invoke( delAddToControls, gcnew array<Object^>{texbox} );

			xpos += 132;
			if( xpos >= 512 ) {
				xpos = 24;
				ypos += 132;
			}
			SleepEx( 100, FALSE ); // CPU
		}
		fclose( pChunk ); // > 2 FOR EXPORTING

		this->Invoke( delsetButtonsToAvailable );
	}

	// Deselect whatever texture is selected now
	void DeselectTexture( void ) {
		PictureBox^ pbox = (PictureBox^)PictureBox::FromHandle((IntPtr)iLastSelTexture);

		if( iLastSelTexture ) {
			pbox->Image = pTextureBitmaps[(INT)pbox->Tag];
		}
		delete[] pReservedBitmap;
		iLastSelTexture = 0;
		iViewingTexture = -1;
		richTextBox1->Clear();
	}

	private: System::Void wtexture_viewer_Load(System::Object^  sender, System::EventArgs^  e) {
		pChunk = fopen( szChunkfilename, "rb" ); // > 1
		pTex = LoadTexChunk( pChunk );
		
		pTextureBitmaps = gcnew array< Bitmap^ >( pTex->texturenum );
		delAddToControls = gcnew SetControlsDel( this, &wtexture_viewer::SetControls );
		delsetButtonsToAvailable = gcnew MakeButtonsAvailableDel( this, &wtexture_viewer::SetBTAvailable );
		delShowTexConEd = gcnew ShowTexContextEdDel( this, &wtexture_viewer::ShowTexContextEd );

		// Load all textures from the datachunk in a sep' thread so that the interface doesn't hang
		pThread = gcnew Thread( gcnew Threading::ThreadStart(this, &wtexture_viewer::LoadupTextures) );
		pThread->Start();
	}

		 // When we click on a texture preview
private: System::Void texbox_Click(System::Object^  sender, System::EventArgs^  e) {
			 PictureBox^ pbox; Imaging::BitmapData^ bmpData;
			 BYTE* dataptr; INT stride;

			 iViewingTexture = Convert::ToInt32( ((PictureBox^)sender)->Tag );

			 if( iLastSelTexture == (INT)((PictureBox^)sender)->Handle ) {
				 DeselectTexture();
				 return;
			 }

			 if( iLastSelTexture ) {
				 pbox = (PictureBox^)PictureBox::FromHandle( (IntPtr)iLastSelTexture );
				 pbox->Image = (Image^)pTextureBitmaps[(INT)pbox->Tag] ; // Restore the original bitmap because another texture
			 } // has been selected

			 delete pReservedBitmap;
			 pReservedBitmap = gcnew Bitmap( pTextureBitmaps[iViewingTexture] ); // Store the original non-tinted bitmap
			 iLastSelTexture = (INT)((PictureBox^)sender)->Handle; // I believe it doubles the memory usage
			 // with each selected texture

			 bmpData = pReservedBitmap->LockBits( System::Drawing::Rectangle(0, 0, pTextureBitmaps[iViewingTexture]->Width, pTextureBitmaps[iViewingTexture]->Height),
				 System::Drawing::Imaging::ImageLockMode::WriteOnly, System::Drawing::Imaging::PixelFormat::Format32bppArgb );
			 dataptr = (BYTE*)(INT)bmpData->Scan0;
			 stride = bmpData->Stride;

			 for( INT y = 0; y < pTextureBitmaps[iViewingTexture]->Height; y++ ) {
				 for( INT x = 0; x < pTextureBitmaps[iViewingTexture]->Width; x++ ) {
					 dataptr[(x*4)+y*stride+2] = 180; // Tint the texture so we know it's the one we've selected
					 if( dataptr[(x*4)+y*stride+2] > 255 ) dataptr[(x*4)+y*stride+2] = 255;
				 }
			 }
			 pReservedBitmap->UnlockBits( bmpData );
			 ((PictureBox^)sender)->Image = (Image^)pReservedBitmap;
			 delete bmpData;

			 richTextBox1->Text = "Texture #"+iViewingTexture.ToString()+" \""+MakeString(pTex->textures[iViewingTexture].name)+"\"";
			 richTextBox1->Text += "\n===============================";
			 richTextBox1->Text += "\nDimensions: "+pTex->textures[iViewingTexture].w.ToString()+"x"+pTex->textures[iViewingTexture].h.ToString();
			 richTextBox1->Text += "\nTexture offset: 0x"+String::Format( "{0:X}", pTex->textures[iViewingTexture].offset );
			 richTextBox1->Text += "\nTexture mode: 0x"+String::Format( "{0:X2}", pTex->textures[iViewingTexture].mode );
			 if( pTex->textures[iViewingTexture].mode == TEX_PALET ) {
				 richTextBox1->Text += "\nTexture palette offset: 0x"+String::Format( "{0:X}", pTex->textures[iViewingTexture].paloffs );
			 }
		 }

		 // Export a selected texture
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			 if( iViewingTexture >= 0 ) { // See if it's a palettized texture and if so, should we export it as a PNG?
				 if( pTex->textures[iViewingTexture].mode != TEX_PALET ||
					 (pTex->textures[iViewingTexture].mode == TEX_PALET && checkBox1->Checked) ) {
						 pTextureBitmaps[iViewingTexture]->Save( MakeString(pTex->textures[iViewingTexture].name)+".png" );
						 return;
				 }
				 else{ // Export the palettized texture in raw + palette itself
					 pChunk = fopen( szChunkfilename, "rb" );
					 sprintf( szTempFilename, "%s.pal", pTex->textures[iViewingTexture].name );
					 pPalFile = fopen( szTempFilename, "wb" );

					 ExportPalettized( pPalFile, pChunk, pTex, iViewingTexture, checkBox1->Checked );

					 fclose( pChunk );
					 fclose( pPalFile );
					 return;
				 }
			 }
			 MessageBoxA( NULL, "You haven't selected a texture to save", "ERROR", MB_ICONERROR );
		 }

		 // Replace the selected texture
private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
			 openFileDialog1->ShowDialog();
			 if( IO::File::Exists(openFileDialog1->FileName) ) ReplaceTexture( szChunkfilename, openFileDialog1->FileName, pTex, iViewingTexture );
			 else MessageBoxA( NULL, "The file doesn't exist anymore!", "ERROR", MB_ICONERROR );
		 }


private: System::Void panel1_Click(System::Object^  sender, System::EventArgs^  e) {
			 DeselectTexture();
		 }

		 // Clean-up when the window is being closed
private: System::Void wtexture_viewer_FormClosing(System::Object^  sender, System::Windows::Forms::FormClosingEventArgs^  e) {
			 pThread->Abort();
			 while( pThread->IsAlive ) SleepEx( 100, FALSE );
			 delete pThread;
			 iViewingTexture = -1; iLastSelTexture = 0;
			 if( pChunk ) fclose( pChunk );
			 if( pPalFile ) fclose( pPalFile );
			 if( pTex ) free( pTex );
			 /*if( pTex ) {
				 for( INT i = 0; i < pTex->texturenum; i++ ) {
					 if( pTex->textures[i].pixelcount ) {
						 free( pTex->textures[i].pixels );
					 }
				 }
				 free( pTex->textures );
				 free( pTex ); // If I didn't do the selected texture info this could've been gotten rid of way earlier
			 }*/
			 delete[] pTextureBitmaps; delete pReservedBitmap;
			 if( pTexContextEd ) {
				 if( pTexContextEd->IsHandleCreated ) {
					 pTexContextEd->Close();
					 delete pTexContextEd;
				 }
			 }
			 //free( szChunkfilename );
			 GC::Collect(); // Saves 200 KB, 200 KB is enough for anyone
			 fclose( pChunk ); //<<<<<
			 delete this;
		 }

		 // Export all textures
private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) {
			 String^ fname;

			 for( INT i = 0; i < pTex->texturenum; i++ ) {
				 if( !checkBox1->Checked && pTex->textures[i].mode == TEX_PALET ) {
					 pChunk = fopen( szChunkfilename, "rb" );
					 sprintf( szTempFilename, checkBox2->Checked ? "%03i.pal" : "%s.pal", checkBox2->Checked ? (char*)i : pTex->textures[i].name );
					 pPalFile = fopen( szTempFilename, "wb" );

					 ExportPalettized( pPalFile, pChunk, pTex, i, !checkBox1->Checked );

					 fclose( pChunk );
					 fclose( pPalFile );
					 continue;
				 }

				 fname = checkBox2->Checked ? i.ToString("D3")+".png" : MakeString(pTex->textures[i].name)+".png";
				 pTextureBitmaps[i]->Save( fname );
				 delete fname; // ~ 600K
			 }
		 }
};
}