#using <mscorlib.dll>
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>

#include <iostream>
#include <istream>
#include <fstream>
#include "Parameters.h"
#include "PreyCompositionForm.h"

using namespace std;
using namespace System;
using namespace System::IO;
using namespace System::Drawing;
using namespace System::Collections;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Runtime::Serialization;
using namespace System::Runtime::Serialization::Formatters;
using namespace System::Runtime::Serialization::Formatters::Binary;


public __gc class SpeciesEntryForm : public System::Windows::Forms::Form {
private:

	System::Windows::Forms::Button* btnNext;
	System::Windows::Forms::Button* btnBack;
	System::Windows::Forms::Button* btnMoveRight;
	System::Windows::Forms::Button* btnMoveLeft;

	System::Windows::Forms::MainMenu* mainMenu;
	System::Windows::Forms::MenuItem* miFile;

	Parameters *parameterObject;

	System::Windows::Forms::Label* codeFileLabel;
	System::Windows::Forms::TextBox* codeFileTextBox;
	System::Windows::Forms::Button* codeFileButton;

    System::Windows::Forms::ListBox* availableCodesListBox;
	System::Windows::Forms::ListBox* selectedCodesListBox;

	System::Windows::Forms::Label* availableCodesLabel;
	System::Windows::Forms::Label* selectedCodesLabel;

	System::Windows::Forms::TextBox* codeTextBox;
	System::Windows::Forms::Label* codeLabel;

	System::Windows::Forms::TextBox* taxaTextBox;
	System::Windows::Forms::Label* taxaLabel;

	System::Windows::Forms::Button* taxaSetButton;

	ArrayList* availableCodesList;
	ArrayList* selectedCodesList;

	PreyCompositionForm* formPreyComposition;


public:

    SpeciesEntryForm(Parameters* sentParameterObject) {

		this->set_MaximizeBox(false);

		this->parameterObject = sentParameterObject;

		this->availableCodesListBox = new System::Windows::Forms::ListBox();
		this->availableCodesLabel = new System::Windows::Forms::Label();
        this->availableCodesListBox->SelectedIndexChanged += new EventHandler(this, availableCodesListBox_SelectedIndexChanged);

		this->selectedCodesListBox = new System::Windows::Forms::ListBox();
		this->selectedCodesLabel = new System::Windows::Forms::Label();
        this->selectedCodesListBox->SelectedIndexChanged += new EventHandler(this, selectedCodesListBox_SelectedIndexChanged);

		this->btnMoveLeft = new System::Windows::Forms::Button();
		this->btnMoveRight = new System::Windows::Forms::Button();

		this->codeFileLabel = new System::Windows::Forms::Label();
		this->codeFileTextBox = new System::Windows::Forms::TextBox();
		this->codeFileButton = new System::Windows::Forms::Button();

		this->codeLabel = new System::Windows::Forms::Label();
		this->codeTextBox = new System::Windows::Forms::TextBox();

		this->taxaLabel = new System::Windows::Forms::Label();
		this->taxaTextBox = new System::Windows::Forms::TextBox();

		this->taxaSetButton = new System::Windows::Forms::Button();

		this->btnNext = new System::Windows::Forms::Button();
		this->btnBack = new System::Windows::Forms::Button();

        this->SuspendLayout();

        this->availableCodesLabel->Location = System::Drawing::Point(70, 70);
        this->availableCodesLabel->Size = System::Drawing::Size(137, 24);
        this->availableCodesLabel->Text = S"Potential Species";

        this->availableCodesListBox->Location = System::Drawing::Point(10, 90);
        this->availableCodesListBox->Size = System::Drawing::Size(220, 535);
  
  		this->selectedCodesLabel->Location = System::Drawing::Point(340, 70);
        this->selectedCodesLabel->Size = System::Drawing::Size(137, 24);
        this->selectedCodesLabel->Text = S"Selected Species";
 
        this->selectedCodesListBox->Location = System::Drawing::Point(279, 90);
        this->selectedCodesListBox->Size = System::Drawing::Size(220, 535);
  
		this->btnMoveRight->Location = System::Drawing::Point(235, 315);
		this->btnMoveRight->Size = System::Drawing::Size(40, 20);
		this->btnMoveRight->Text = S"->";
		this->btnMoveRight->Click += new EventHandler(this, btnMoveRight_Click);

		this->btnMoveLeft->Location = System::Drawing::Point(235, 345);
		this->btnMoveLeft->Size = System::Drawing::Size(40, 20);
		this->btnMoveLeft->Text = S"<-";
		this->btnMoveLeft->Click += new EventHandler(this, btnMoveLeft_Click);

		this->codeFileLabel->Location = System::Drawing::Point(120, 20);
		this->codeFileLabel->Text = S"Code Filename";

		this->codeFileTextBox->Location = System::Drawing::Point(220, 20);
		this->codeFileTextBox->Text = S"Group Codes.csv";
		this->codeFileTextBox->set_ReadOnly(true);

		this->codeFileButton->Location = System::Drawing::Point(330, 20);
		this->codeFileButton->Text = S"...";
		this->codeFileButton->Size = System::Drawing::Size(20, 20);
		this->codeFileButton->Click += new EventHandler(this, codeFileButton_Click);

		this->codeTextBox->Location = System::Drawing::Point(50, 647);
		this->codeTextBox->Size = System::Drawing::Size(50, 20);
		this->codeTextBox->set_ReadOnly(true);

		this->codeLabel->Location = System::Drawing::Point(10, 650);
		this->codeLabel->Size = System::Drawing::Size(40, 20);
		this->codeLabel->Text = S"Code";

		this->taxaTextBox->Location = System::Drawing::Point(165, 647);
		this->taxaTextBox->Size = System::Drawing::Size(100, 20);

		this->taxaLabel->Location = System::Drawing::Point(125, 650);
		this->taxaLabel->Size = System::Drawing::Size(40, 20);
		this->taxaLabel->Text = S"Taxa";

		this->taxaSetButton->Location = System::Drawing::Point(280, 645);
		this->taxaSetButton->Text = S"Change Taxa";
		this->taxaSetButton->Size = System::Drawing::Size(80, 20);
		this->taxaSetButton->set_BackColor(System::Drawing::Color::Gold);
		this->taxaSetButton->Click += new EventHandler(this, taxaSetButton_Click);

 		this->btnNext->Location = System::Drawing::Point(440, 665);
		this->btnNext->Size = System::Drawing::Size(50, 24);
		this->btnNext->Text = S"Next";
		this->btnNext->Click += new EventHandler(this, btnNext_Click);

		this->btnBack->Location = System::Drawing::Point(375, 665);
		this->btnBack->Size = System::Drawing::Size(50, 24);
		this->btnBack->Text = S"Back";
		this->btnBack->Click += new EventHandler(this, btnBack_Click);

		this->Closing += new System::ComponentModel::CancelEventHandler(this, ApplicationExit);

		this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
        this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
        this->ClientSize = System::Drawing::Size(517, 700);
		this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::Fixed3D;
		System::Windows::Forms::Control* formControls[] = {this->btnNext, this->btnBack, this->taxaSetButton, this->taxaLabel, this->taxaTextBox, this->codeLabel, this->codeTextBox, this->availableCodesListBox, this->selectedCodesListBox, this->btnMoveLeft, this->btnMoveRight, this->availableCodesLabel, this->selectedCodesLabel, this->codeFileLabel, this->codeFileTextBox, this->codeFileButton};
        this->Controls->AddRange(formControls);
        this->Text = S"Species Code Selection";
		this->Menu = this->mainMenu;
//		this->set_BackColor(System::Drawing::Color::AliceBlue);
      
		this->initializeLists();

		this->ResumeLayout(false);
		this->Visible = true;

		this->availableCodesList = new ArrayList();
		this->selectedCodesList = this->parameterObject->getCodesList();
	}


private:
	void initializeLists() {

		String* codesFileName = this->getCodesFile();
   		StreamReader* readStream = File::OpenText(codesFileName);

		// Initialize Available Codes Hash

		String* line = readStream->ReadLine();
 
		String* delimiterString = S",";

		Char delimiter[];
		delimiter = delimiterString->ToCharArray();
		
		String* splitLine[] = line->Split(delimiter);

        ArrayList* codesList = new ArrayList();
        Hashtable* codeHash = new Hashtable();

		String* speciesCode;
		while (!(splitLine[3]->Equals(S""))) {

        	speciesCode = splitLine[3]; 
			// Update codes list and the code hash.

			codesList->Add(speciesCode);
            ArrayList* currentCodeList = new ArrayList();
			currentCodeList->Add(splitLine[1]);   // Common name
			currentCodeList->Add(splitLine[2]);   // General Group
			currentCodeList->Add(splitLine[0]);   // User group

			codeHash->Add(speciesCode, currentCodeList);

			line = readStream->ReadLine();
			splitLine = line->Split(delimiter);
    	}		

		readStream->Close();

		this->availableCodesList = codesList;
		this->populateAvailableCodesListBox();

//		if (this->parameterObject->isInitialized()) {
			this->populateSelectedCodesListBox();
//		} else {
            this->parameterObject->setCodeHash(codeHash);
//		}
	}


	String* getCodesFile() {
		String* fileName = this->codeFileTextBox->Text;
		return fileName;
	}


	void populateAvailableCodesListBox() {

		this->availableCodesListBox->BeginUpdate();
		this->availableCodesListBox->Items->Clear();

		// Fill available codes listbox with the data from the codesList
		IEnumerator *codesListEnum = this->availableCodesList->GetEnumerator();
		while (codesListEnum->MoveNext()) {
    		availableCodesListBox->Items->Add(codesListEnum->Current);
		}      

		// Sort the available codes listbox and redisplay
		this->availableCodesListBox->Sorted = true;
		this->availableCodesListBox->EndUpdate();
	}


	void populateSelectedCodesListBox() {

		this->selectedCodesListBox->BeginUpdate();
		this->selectedCodesListBox->Items->Clear();


		// Fill available codes listbox with the data from the codesList
		this->selectedCodesList = this->parameterObject->getCodesList();

		IEnumerator *codesListEnum = this->selectedCodesList->GetEnumerator();
        String* selectedCode;
		while (codesListEnum->MoveNext()) {
            selectedCode = static_cast<String*>(codesListEnum->Current);
    		this->selectedCodesListBox->Items->Add(selectedCode);
			this->availableCodesList->Remove(selectedCode);
			this->availableCodesListBox->Items->Remove(selectedCode);
		}      

		// Sort the available codes listbox and redisplay
		this->selectedCodesListBox->Sorted = true;
		this->selectedCodesListBox->EndUpdate();
	}


	void btnMoveLeft_Click(Object* /*sender*/, EventArgs* /*e*/) {

        this->moveCode(this->selectedCodesListBox, this->availableCodesListBox, this->selectedCodesList, this->availableCodesList);
	}


	void btnMoveRight_Click(Object* /*sender*/, EventArgs* /*e*/) {

        this->moveCode(this->availableCodesListBox, this->selectedCodesListBox, this->availableCodesList, this->selectedCodesList);
	}


	void moveCode(ListBox* sourceListBox, ListBox* destinationListBox, ArrayList* sourceList, ArrayList* destinationList) {

		int index = sourceListBox->get_SelectedIndex();

        // If no code is selected, nothing happens
 		if (index == -1) {
			return;
		}

		String* selectedCode = static_cast<String*>(sourceListBox->SelectedItem);
		destinationListBox->Items->Add(selectedCode);
		destinationList->Add(selectedCode);
        sourceListBox->Items->Remove(selectedCode);
        sourceList->Remove(selectedCode);

		this->parameterObject->setCodesList(this->selectedCodesList);

		destinationListBox->Sorted = true;
		sourceListBox->set_SelectedIndex(-1);

		this->codeTextBox->Text = S"";
		this->taxaTextBox->Text = S"";
		this->parameterObject->reInitialize();
	}


	void codeFileButton_Click(Object* /*sender*/, EventArgs* /*e*/) {

		OpenFileDialog *openCodeFileDialog = new OpenFileDialog();

        openCodeFileDialog->Filter = "csv files (*.csv)|*.csv" ;
		openCodeFileDialog->FilterIndex = 1;
        openCodeFileDialog->RestoreDirectory = true;

       
        if (openCodeFileDialog->ShowDialog() == DialogResult::OK) {
            String* codeFilePath = openCodeFileDialog->get_FileName();

    		String* delimiterString = S"\\";

	    	Char delimiter[];
	    	delimiter = delimiterString->ToCharArray();
		
		    String* splitPath[] = codeFilePath->Split(delimiter);
			int nameIndex = splitPath->get_Count() - 1;
            String* codeFileName = splitPath[nameIndex];

			this->codeFileTextBox->Text = codeFileName;
			this->initializeLists();
		}
	}


    void availableCodesListBox_SelectedIndexChanged(Object* /*sender*/, EventArgs* /*e*/) {
  
		int selectedIndex = this->availableCodesListBox->SelectedIndex;

		if (selectedIndex != -1) {
    		// Get the currently selected item in the ListBox.
	    	String *selectedCode = this->availableCodesListBox->SelectedItem->ToString();
			this->codeTextBox->Text = selectedCode;
			String* taxa = this->parameterObject->getTaxa(selectedCode);
			this->taxaTextBox->Text = taxa;
		}
	}


    void selectedCodesListBox_SelectedIndexChanged(Object* /*sender*/, EventArgs* /*e*/) {
    
		int selectedIndex = this->selectedCodesListBox->SelectedIndex;

		if (selectedIndex != -1) {
			// Get the currently selected item in the ListBox.
			String *selectedCode = this->selectedCodesListBox->SelectedItem->ToString();
            this->codeTextBox->Text = selectedCode;
			String* taxa = this->parameterObject->getTaxa(selectedCode);
			this->taxaTextBox->Text = taxa;
		}
	}


	void taxaSetButton_Click(Object* /*sender*/, EventArgs* /*e*/) {

		String* code = this->codeTextBox->Text;
		String* taxa = this->taxaTextBox->Text;
		
        this->parameterObject->setTaxa(code, taxa);
 	}


	void taxaTextBox_Paste(Object* /*sender*/, EventArgs* /*e*/) {

		String* taxa = this->taxaTextBox->Text;
	}


	void btnNext_Click (Object* /*sender*/, EventArgs* /*e*/) {

		if (this->selectedCodesList->Count == 0) {
			String* message = S"No species have been selected yet.  Please select at least one species before continuing.";
			String* caption = S"ERROR: No Species Selected";
			MessageBoxButtons buttons = MessageBoxButtons::OK;
			System::Windows::Forms::DialogResult result;
			result = MessageBox::Show(message, caption, buttons);
			return;
		}

		this->btnNext->set_Enabled(false);
		this->btnBack->set_Enabled(false);
		this->parameterObject->initializePreyCompositionList();

		this->formPreyComposition = new PreyCompositionForm(this->parameterObject, this->btnBack, this->btnNext);
	}


	void btnBack_Click(Object* sender, EventArgs* e) {

		this->miFile_Exit(sender, e);
	}


	void miFile_Exit(Object* sender, EventArgs* e) {

		this->Close();
	}


	void miFile_SaveAs(Object* /*sender*/, EventArgs* /*e*/) {

		SaveFileDialog *pfileSaveFileDialog = new SaveFileDialog();

        pfileSaveFileDialog->Filter = "parameter files (*.pob)|*.pob"  ;
        pfileSaveFileDialog->FilterIndex = 1 ;
        pfileSaveFileDialog->RestoreDirectory = true ;

	    if (pfileSaveFileDialog->ShowDialog() == DialogResult::OK) {

			String *saveParameterFileName = pfileSaveFileDialog->get_FileName();

			IFormatter *parameterObjectFormatter = new BinaryFormatter();
			Stream *pfileStream = new FileStream(saveParameterFileName, FileMode::Create, FileAccess::Write, FileShare::None);
 
			parameterObjectFormatter->Serialize(pfileStream, this->parameterObject);
            pfileStream->Close();
		}
	}

	void ApplicationExit(Object* sender, System::ComponentModel::CancelEventArgs* e) {

        String *message = S"Do you want to Save?";
		String *caption = S"Warning: Save?";
        MessageBoxButtons buttons = MessageBoxButtons::YesNoCancel;
        System::Windows::Forms::DialogResult result;

        // Displays the MessageBox.
        result = MessageBox::Show(this, message, caption, buttons);

		e->Cancel = false;
		if (result == DialogResult::Yes) {
			this->miFile_SaveAs(sender, e); 
		} else {
			if (result == DialogResult::Cancel) { 
				e->Cancel = true;
			    return;
			}
		}
    }
};
