#pragma once
#include "somarray.h"
#include "texcontext.h"

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;

	/// <summary>
	/// Summary for wsomed
	/// </summary>
	public ref class wsomed : public System::Windows::Forms::Form
	{
	public:
		dbl_chunk_header_s* pChunkHeader;
		char* szChunkfilename;
		char** meshnames;
		BOOL bMNamesAdded, bIsAnyMeshSelected;
		somArray_s* pMeshes;
		wsomed(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}
	private: System::Windows::Forms::Label^  label4;
	private: System::Windows::Forms::CheckBox^  checkBox1;
	private: System::Windows::Forms::TextBox^  textBox2;
	private: System::Windows::Forms::Label^  label5;
	private: System::Windows::Forms::TextBox^  textBox3;
	private: System::Windows::Forms::TextBox^  textBox4;
	private: System::Windows::Forms::Label^  label6;
	private: System::Windows::Forms::TextBox^  textBox5;
	private: System::Windows::Forms::Label^  label7;
	private: System::Windows::Forms::TextBox^  textBox6;
	private: System::Windows::Forms::Label^  label8;
	private: System::Windows::Forms::TextBox^  textBox7;
	private: System::Windows::Forms::Label^  label9;
	private: System::Windows::Forms::Button^  button1;
	private: System::Windows::Forms::Label^  label3;
	private: System::Windows::Forms::RichTextBox^  richTextBox1;
	private: System::Windows::Forms::ListBox^  listBox1;
	private: System::Windows::Forms::Label^  label2;
	private: System::Windows::Forms::TextBox^  textBox1;
	private: System::Windows::Forms::Label^  label1;

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~wsomed()
		{
			if (components)
			{
				delete components;
			}
		}

	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->listBox1 = (gcnew System::Windows::Forms::ListBox());
			this->label2 = (gcnew System::Windows::Forms::Label());
			this->textBox1 = (gcnew System::Windows::Forms::TextBox());
			this->label1 = (gcnew System::Windows::Forms::Label());
			this->label3 = (gcnew System::Windows::Forms::Label());
			this->richTextBox1 = (gcnew System::Windows::Forms::RichTextBox());
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->textBox2 = (gcnew System::Windows::Forms::TextBox());
			this->label5 = (gcnew System::Windows::Forms::Label());
			this->textBox3 = (gcnew System::Windows::Forms::TextBox());
			this->textBox4 = (gcnew System::Windows::Forms::TextBox());
			this->label6 = (gcnew System::Windows::Forms::Label());
			this->textBox5 = (gcnew System::Windows::Forms::TextBox());
			this->label7 = (gcnew System::Windows::Forms::Label());
			this->textBox6 = (gcnew System::Windows::Forms::TextBox());
			this->label8 = (gcnew System::Windows::Forms::Label());
			this->textBox7 = (gcnew System::Windows::Forms::TextBox());
			this->label9 = (gcnew System::Windows::Forms::Label());
			this->label4 = (gcnew System::Windows::Forms::Label());
			this->checkBox1 = (gcnew System::Windows::Forms::CheckBox());
			this->SuspendLayout();
			// 
			// listBox1
			// 
			this->listBox1->FormattingEnabled = true;
			this->listBox1->Location = System::Drawing::Point(12, 41);
			this->listBox1->Name = L"listBox1";
			this->listBox1->Size = System::Drawing::Size(175, 212);
			this->listBox1->TabIndex = 6;
			this->listBox1->SelectedIndexChanged += gcnew System::EventHandler(this, &wsomed::listBox1_SelectedIndexChanged);
			// 
			// label2
			// 
			this->label2->AutoSize = true;
			this->label2->Location = System::Drawing::Point(9, 25);
			this->label2->Name = L"label2";
			this->label2->Size = System::Drawing::Size(110, 13);
			this->label2->TabIndex = 7;
			this->label2->Text = L"Meshes in this chunk:";
			// 
			// textBox1
			// 
			this->textBox1->BackColor = System::Drawing::SystemColors::Control;
			this->textBox1->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->textBox1->Location = System::Drawing::Point(132, 4);
			this->textBox1->Name = L"textBox1";
			this->textBox1->ReadOnly = true;
			this->textBox1->Size = System::Drawing::Size(250, 20);
			this->textBox1->TabIndex = 5;
			// 
			// label1
			// 
			this->label1->AutoSize = true;
			this->label1->Location = System::Drawing::Point(9, 7);
			this->label1->Name = L"label1";
			this->label1->Size = System::Drawing::Size(93, 13);
			this->label1->TabIndex = 4;
			this->label1->Text = L"SOM array chunk:";
			// 
			// label3
			// 
			this->label3->AutoSize = true;
			this->label3->Location = System::Drawing::Point(9, 260);
			this->label3->Name = L"label3";
			this->label3->Size = System::Drawing::Size(28, 13);
			this->label3->TabIndex = 8;
			this->label3->Text = L"Log:";
			// 
			// richTextBox1
			// 
			this->richTextBox1->Location = System::Drawing::Point(12, 276);
			this->richTextBox1->Name = L"richTextBox1";
			this->richTextBox1->ReadOnly = true;
			this->richTextBox1->Size = System::Drawing::Size(370, 96);
			this->richTextBox1->TabIndex = 9;
			this->richTextBox1->Text = L"";
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(193, 230);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(189, 23);
			this->button1->TabIndex = 10;
			this->button1->Text = L"Export into OBJ";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &wsomed::button1_Click);
			// 
			// textBox2
			// 
			this->textBox2->Location = System::Drawing::Point(300, 171);
			this->textBox2->Name = L"textBox2";
			this->textBox2->Size = System::Drawing::Size(82, 20);
			this->textBox2->TabIndex = 12;
			this->textBox2->Text = L"Export.obj";
			// 
			// label5
			// 
			this->label5->AutoSize = true;
			this->label5->Location = System::Drawing::Point(190, 44);
			this->label5->Name = L"label5";
			this->label5->Size = System::Drawing::Size(46, 13);
			this->label5->TabIndex = 13;
			this->label5->Text = L"Mesh #:";
			// 
			// textBox3
			// 
			this->textBox3->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->textBox3->Location = System::Drawing::Point(300, 41);
			this->textBox3->Name = L"textBox3";
			this->textBox3->ReadOnly = true;
			this->textBox3->Size = System::Drawing::Size(82, 20);
			this->textBox3->TabIndex = 14;
			// 
			// textBox4
			// 
			this->textBox4->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->textBox4->Location = System::Drawing::Point(300, 67);
			this->textBox4->Name = L"textBox4";
			this->textBox4->ReadOnly = true;
			this->textBox4->Size = System::Drawing::Size(82, 20);
			this->textBox4->TabIndex = 16;
			// 
			// label6
			// 
			this->label6->AutoSize = true;
			this->label6->Location = System::Drawing::Point(190, 70);
			this->label6->Name = L"label6";
			this->label6->Size = System::Drawing::Size(65, 13);
			this->label6->TabIndex = 15;
			this->label6->Text = L"Submeshes:";
			// 
			// textBox5
			// 
			this->textBox5->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->textBox5->Location = System::Drawing::Point(300, 93);
			this->textBox5->Name = L"textBox5";
			this->textBox5->ReadOnly = true;
			this->textBox5->Size = System::Drawing::Size(82, 20);
			this->textBox5->TabIndex = 18;
			// 
			// label7
			// 
			this->label7->AutoSize = true;
			this->label7->Location = System::Drawing::Point(190, 96);
			this->label7->Name = L"label7";
			this->label7->Size = System::Drawing::Size(44, 13);
			this->label7->TabIndex = 17;
			this->label7->Text = L"Indices:";
			// 
			// textBox6
			// 
			this->textBox6->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->textBox6->Location = System::Drawing::Point(300, 119);
			this->textBox6->Name = L"textBox6";
			this->textBox6->ReadOnly = true;
			this->textBox6->Size = System::Drawing::Size(82, 20);
			this->textBox6->TabIndex = 20;
			// 
			// label8
			// 
			this->label8->AutoSize = true;
			this->label8->Location = System::Drawing::Point(190, 122);
			this->label8->Name = L"label8";
			this->label8->Size = System::Drawing::Size(93, 13);
			this->label8->TabIndex = 19;
			this->label8->Text = L"Offset to vertexes:";
			// 
			// textBox7
			// 
			this->textBox7->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->textBox7->Location = System::Drawing::Point(300, 145);
			this->textBox7->Name = L"textBox7";
			this->textBox7->ReadOnly = true;
			this->textBox7->Size = System::Drawing::Size(82, 20);
			this->textBox7->TabIndex = 22;
			// 
			// label9
			// 
			this->label9->AutoSize = true;
			this->label9->Location = System::Drawing::Point(190, 148);
			this->label9->Name = L"label9";
			this->label9->Size = System::Drawing::Size(86, 13);
			this->label9->TabIndex = 21;
			this->label9->Text = L"Offset to indices:";
			// 
			// label4
			// 
			this->label4->AutoSize = true;
			this->label4->Location = System::Drawing::Point(190, 174);
			this->label4->Name = L"label4";
			this->label4->Size = System::Drawing::Size(58, 13);
			this->label4->TabIndex = 24;
			this->label4->Text = L"Output file:";
			// 
			// checkBox1
			// 
			this->checkBox1->AutoSize = true;
			this->checkBox1->Location = System::Drawing::Point(193, 207);
			this->checkBox1->Name = L"checkBox1";
			this->checkBox1->Size = System::Drawing::Size(149, 17);
			this->checkBox1->TabIndex = 25;
			this->checkBox1->Text = L"Export selected mesh only";
			this->checkBox1->UseVisualStyleBackColor = true;
			// 
			// wsomed
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(396, 384);
			this->Controls->Add(this->checkBox1);
			this->Controls->Add(this->label4);
			this->Controls->Add(this->textBox7);
			this->Controls->Add(this->label9);
			this->Controls->Add(this->textBox6);
			this->Controls->Add(this->label8);
			this->Controls->Add(this->textBox5);
			this->Controls->Add(this->label7);
			this->Controls->Add(this->textBox4);
			this->Controls->Add(this->label6);
			this->Controls->Add(this->textBox3);
			this->Controls->Add(this->label5);
			this->Controls->Add(this->textBox2);
			this->Controls->Add(this->button1);
			this->Controls->Add(this->richTextBox1);
			this->Controls->Add(this->label3);
			this->Controls->Add(this->listBox1);
			this->Controls->Add(this->label2);
			this->Controls->Add(this->textBox1);
			this->Controls->Add(this->label1);
			this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedToolWindow;
			this->MaximizeBox = false;
			this->MinimizeBox = false;
			this->Name = L"wsomed";
			this->ShowIcon = false;
			this->Text = L"Som Array Editor";
			this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &wsomed::wsomed_FormClosing);
			this->Load += gcnew System::EventHandler(this, &wsomed::wsomed_Load);
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
	private: System::Void wsomed_Load(System::Object^  sender, System::EventArgs^  e) {
				 char szFname[256];
				 char szPath[256];
				 char szChunkpath[256];
				 char* pTexContextFName;
				 dbl_chunk_header_s* pCurrentChunkHeader;
				 INT iChunkNum;
				 INT iExtraOffset;
				 FILE* pChk;
				 TexContextList_s* pTexContextList;

				 bMNamesAdded = bIsAnyMeshSelected = FALSE;
				 strcpy( szFname, szChunkfilename );
				 strcpy( szPath, szChunkfilename );
				 szFname[ strlen(szFname)-4 ] = '\0'; // Strip the file extension
				 for( INT i = 0; i < strlen(szFname)-1; i++ ) {
					 if( szFname[i] == '\\' ) iChunkNum = i+1;
				 }
				 szPath[iChunkNum-1] = '\0';
				 iChunkNum = atoi( (char*)&szFname[iChunkNum+5] );

				 richTextBox1->Text = "> Opening the DB_SOMARRAY chunk...";

				 pChk = fopen( szChunkfilename, "rb" );
				 if( !pChk ) {
					 MessageBoxA( NULL, "Couldn't open the DB_SOMARRAY chunk", "ERROR", MB_ICONERROR );
					 this->Close();
					 return;
				 }
				 pChunkHeader = ReadChunkHeader( pChk, 0, (dbl_header_s*)DBL_CHUNK_NODBLHEADER );
				 fclose( pChk );

				 if( !pChunkHeader ) {
					 fclose( pChk );
					 MessageBoxA( NULL, "Couldn't parse the data-chunk header", "ERROR", MB_ICONERROR );
					 this->Close();
					 return;
				 }

				 iExtraOffset = iChunkNum = 0;
				 //iChunkNum = 3;

				 if( pChunkHeader->iDataChunkVer == 0x03 ) {
					 for( INT i = 1; i < iChunkNum; i++ ) {
						 sprintf( szFname, (i < 10) ? "\\Chunk0%i.chk" : "\\Chunk%i.chk", i );
						 strcpy( szChunkpath, szPath );
						 strcat( szChunkpath, szFname );
						 pChk = fopen( szChunkpath, "rb" );
						 if( !pChk ) {
							 sprintf( szChunkpath, "Couldn't open the chunk #%i (%s)", i, szFname );
							 MessageBoxA( NULL, szChunkpath, "ERROR", MB_ICONERROR );
							 this->Close();
							 return;
						 }
						 pCurrentChunkHeader = ReadChunkHeader( pChk, 0, (dbl_header_s*)DBL_CHUNK_NODBLHEADER );
						 if( !pCurrentChunkHeader ) {
							 sprintf( szChunkpath, "Couldn't parse the chunk header for chunk #%i (%s)", i, szFname );
							 MessageBoxA( NULL, szChunkpath, "ERROR", MB_ICONERROR );
							 this->Close();
							 return;
						 }

						 iExtraOffset += pCurrentChunkHeader->iDataChunkSize;
						 switch( pCurrentChunkHeader->iFlag ) {
							 case 0x0E:
								 iExtraOffset += FLAG_0E;
							 break;
							 case 0x06:
								 iExtraOffset += FLAG_06;
							 break;
							 case 0x00:
								 iExtraOffset += FLAG_00;
							 break;
							 default:
								 sprintf( szChunkpath, "Unknown chunk-header flag 0x%02x!", pCurrentChunkHeader->iFlag );
								 MessageBoxA( NULL, szChunkpath, "ERROR", MB_ICONERROR );
								 this->Close();
								 return;
							 break;
						 }

						 free( pCurrentChunkHeader );
						 fclose( pChk );
					 }
				 }

				 pMeshes = ReadSomArrayChunk( szChunkfilename, pChunkHeader, richTextBox1 );
				 free( pChunkHeader );

				 textBox1->Text = MakeString( szChunkfilename );

				 pTexContextFName = FindATexContextChunk( szChunkfilename );
				 if( !pTexContextFName ) {
					 for( INT i = 0; i < pMeshes->nummeshes; i++ ) {
						 listBox1->Items->Add( "Polysurface"+i.ToString() );
					 }
					 richTextBox1->Text += "\n> WARNING: Couldn't locate a DB_TEXTURE_CONTEXT chunk,";
					 richTextBox1->Text += "\n\tcouldn't get mesh names";

					 meshnames = (char**)malloc( (pMeshes->nummeshes*4) );
					 return;
				 }

				 richTextBox1->Text += "\nLocated DB_TEXTURE_CONTEXT chunk successfully,";
				 richTextBox1->Text += "\ngetting mesh names...";

				 pTexContextList = LoadTexContextChunk( pTexContextFName );
				 if( !pTexContextList ) {
					 richTextBox1->Text += "\n> ERROR: Couldn't read the DB_TEXTURE_CONTEXT chunk,";
					 richTextBox1->Text += "\n\tcouldn't get mesh names";
					 free( pTexContextFName );
					 return;
				 }
				 free( pTexContextFName );

				 meshnames = (char**)malloc( (pTexContextList->iWrittenEntries*4) );
				 for( INT i = 0; i < pTexContextList->iWrittenEntries; i++ ) {
					 if( !pTexContextList->context[i].iPacked ) continue;
					 listBox1->Items->Add( MakeString(pTexContextList->context[i].associatedMesh) );
				 }

				 free( pTexContextList->context );
				 free( pTexContextList );
			 }
	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
				 if( !bMNamesAdded ) { // Have we added the names already?
					 for( INT i = 0; i < listBox1->Items->Count; i++ ) {
						 meshnames[i] = (char*)Marshal::StringToHGlobalAnsi(listBox1->Items[i]->ToString()).ToPointer();
					 }
					 bMNamesAdded = TRUE;
				 }
				 if( checkBox1->Checked ) {
					 if( !bIsAnyMeshSelected ) {
						 MessageBoxA( NULL, "You haven't selected a mesh to export", "ERROR", MB_ICONERROR );
						 return;
					 }
					 ConstructOBJ( (char*)Marshal::StringToHGlobalAnsi(textBox2->Text).ToPointer(),
						 pMeshes, meshnames, listBox1->SelectedIndex );
					 return;
				 }
				 ConstructOBJ( (char*)Marshal::StringToHGlobalAnsi(textBox2->Text).ToPointer(),
					 pMeshes, meshnames );
			 }
private: System::Void wsomed_FormClosing(System::Object^  sender, System::Windows::Forms::FormClosingEventArgs^  e) {
				 if( meshnames ) free( meshnames );
				 if( pMeshes->meshes ) free( pMeshes->meshes );
				 if( pMeshes ) free( pMeshes );
		 }
private: System::Void listBox1_SelectedIndexChanged(System::Object^  sender, System::EventArgs^  e) {
				 INT iNumIndeces;

				 iNumIndeces = 0;
				 if( pMeshes->meshes[listBox1->SelectedIndex].somHeader[SOM_NUMSUBMESHES] > 1 ) {
					 for( INT m = 0; m < pMeshes->meshes[listBox1->SelectedIndex].somHeader[SOM_NUMSUBMESHES]; m++ ) {
						 iNumIndeces += pMeshes->meshes[listBox1->SelectedIndex].submeshes[m].meshData[MESH_NUMINDICES];
					 }
				 }
				 else {
					 iNumIndeces = pMeshes->meshes[listBox1->SelectedIndex].somHeader[SOM_NUMINDICES];
				 }

				 bIsAnyMeshSelected = TRUE;
				 textBox3->Text = listBox1->SelectedIndex.ToString();
				 textBox4->Text = pMeshes->meshes[listBox1->SelectedIndex].somHeader[SOM_NUMSUBMESHES].ToString();
				 textBox5->Text = iNumIndeces.ToString();
				 textBox6->Text = pMeshes->meshes[listBox1->SelectedIndex].somHeader[SOM_VERTOFFS].ToString();
				 textBox7->Text = pMeshes->meshes[listBox1->SelectedIndex].somHeader[SOM_OFFSINDICES].ToString();
		 }
};
}