#pragma once

#include "../ParserLib/muParser.h"
#include "../ParserLib/muParserInt.h"
#include "WndError.h"
#include <cstdio>
#include <sstream>

#include "muParserTest.h"

#define VARCOUNT 100

namespace Example2
{
	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
  using namespace System::Collections::Specialized;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;
  using namespace System::Runtime::InteropServices;


  /// <summary> 
	/// Zusammenfassung für Form1
	///
	/// Achtung: Wenn Sie den Namen dieser Klasse ändern, müssen Sie die Eigenschaft
	///          'Ressourcendateiname' für das Compilertool für verwaltete Ressourcen ändern, 
	///          das allen .resx-Dateien zugewiesen ist, von denen diese Klasse abhängt. 
	///          Anderenfalls können die Designer nicht korrekt mit den lokalisierten Ressourcen
	///          arbeiten, die diesem Formular zugewiesen sind.
	/// </summary>
	public __gc class WinCalc : public System::Windows::Forms::Form
	{	
  private:
      // Example function for String callbacks
      // these can be used for Database queries
      static double ValueOf(const char*)
      {

        // insert fancy side effect here...
        // ...
        // ...
        // ...

        return 23;  
      }

  public:
		WinCalc(void)
      :m_pParser(0)
      ,m_pParserDbl(new mu::Parser())
      ,m_pParserInt(new mu::ParserInt())
      ,m_pfVar(0)
      ,m_iHistLine(0)
      ,m_iVarCount(0)
      ,m_History(new StringCollection())
      ,dlgError(new WndError())
		{
      // Allocating variables that way is a workaround for managed 
      // C++ normally its too complicated to alloc it that way
      m_pfVar = new double[VARCOUNT];
      m_pfVar[0] = 0;

      InitializeComponent();
      dlgError->Hide();

      // Select double parser
      cbParser->BeginUpdate();
      cbParser->Items->Clear();
      cbParser->Items->Add(new BoxItem("Parser for double (muParser)", m_pParserDbl));
      cbParser->Items->Add(new BoxItem("Parser for int (muParserInt)", m_pParserInt));
      cbParser->SelectedIndex = 0;
      cbParser->EndUpdate();

      // Add the variable that stores the answer
      m_pParserDbl->DefineFun("valueof", (strfun_type1)ValueOf);

      m_pParser = m_pParserDbl;
      m_pParserDbl->DefineVar("ans", &m_pfVar[m_iVarCount] ); 
      m_pParserInt->DefineVar("ans", &m_pfVar[m_iVarCount++] ); 
      // ans always takes the lowest slot in the variable array
		}
  
   ~WinCalc()
    {
      delete [] m_pfVar;
    }

	protected:
		void Dispose(Boolean disposing)
		{
			if (disposing && components)
			{
				components->Dispose();
			}
			__super::Dispose(disposing);
		}

  private: System::Windows::Forms::Panel *  paBase;
  private: System::Windows::Forms::Panel *  paTitle;
  private: System::Windows::Forms::Label *  lbAuthor;
  private: System::Windows::Forms::Label *  label1;
  private: System::Windows::Forms::GroupBox *  gbCalc;
  private: System::Windows::Forms::RichTextBox *  reMain;
  private: System::Windows::Forms::Button *  btnUnit;
  private: System::Windows::Forms::Button *  btnReset;
  private: System::Windows::Forms::CheckBox *  cbShowVar;
  private: System::Windows::Forms::PictureBox *  pbCalc;
  private: System::Windows::Forms::TextBox *  edInput;
  private: System::Windows::Forms::Label *  label2;
  private: System::Windows::Forms::Button *  btnListFun;
  private: System::Windows::Forms::Button *  btnListConst;
  private: System::Windows::Forms::Button *  btnListVar;
  private: System::Windows::Forms::ComboBox *  cbParser;
  private: System::Windows::Forms::Label *  lbSelector;

  private:
		/// <summary>
		/// Erforderliche Designervariable.
		/// </summary>
		System::ComponentModel::Container * components;

		/// <summary>
		/// Erforderliche Methode für die Designerunterstützung. 
		/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
		/// </summary>
		void InitializeComponent(void)
		{
      System::Resources::ResourceManager *  resources = new System::Resources::ResourceManager(__typeof(Example2::WinCalc));
      this->paBase = new System::Windows::Forms::Panel();
      this->gbCalc = new System::Windows::Forms::GroupBox();
      this->btnListVar = new System::Windows::Forms::Button();
      this->btnListConst = new System::Windows::Forms::Button();
      this->btnListFun = new System::Windows::Forms::Button();
      this->label2 = new System::Windows::Forms::Label();
      this->edInput = new System::Windows::Forms::TextBox();
      this->pbCalc = new System::Windows::Forms::PictureBox();
      this->cbShowVar = new System::Windows::Forms::CheckBox();
      this->btnReset = new System::Windows::Forms::Button();
      this->btnUnit = new System::Windows::Forms::Button();
      this->reMain = new System::Windows::Forms::RichTextBox();
      this->paTitle = new System::Windows::Forms::Panel();
      this->lbSelector = new System::Windows::Forms::Label();
      this->cbParser = new System::Windows::Forms::ComboBox();
      this->lbAuthor = new System::Windows::Forms::Label();
      this->label1 = new System::Windows::Forms::Label();
      this->paBase->SuspendLayout();
      this->gbCalc->SuspendLayout();
      this->paTitle->SuspendLayout();
      this->SuspendLayout();
      // 
      // paBase
      // 
      this->paBase->BackColor = System::Drawing::Color::White;
      this->paBase->Controls->Add(this->gbCalc);
      this->paBase->Controls->Add(this->paTitle);
      this->paBase->Dock = System::Windows::Forms::DockStyle::Fill;
      this->paBase->Location = System::Drawing::Point(0, 0);
      this->paBase->Name = S"paBase";
      this->paBase->Size = System::Drawing::Size(600, 349);
      this->paBase->TabIndex = 0;
      // 
      // gbCalc
      // 
      this->gbCalc->Anchor = (System::Windows::Forms::AnchorStyles)(((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Bottom) 
        | System::Windows::Forms::AnchorStyles::Left) 
        | System::Windows::Forms::AnchorStyles::Right);
      this->gbCalc->Controls->Add(this->btnListVar);
      this->gbCalc->Controls->Add(this->btnListConst);
      this->gbCalc->Controls->Add(this->btnListFun);
      this->gbCalc->Controls->Add(this->label2);
      this->gbCalc->Controls->Add(this->edInput);
      this->gbCalc->Controls->Add(this->pbCalc);
      this->gbCalc->Controls->Add(this->cbShowVar);
      this->gbCalc->Controls->Add(this->btnReset);
      this->gbCalc->Controls->Add(this->btnUnit);
      this->gbCalc->Controls->Add(this->reMain);
      this->gbCalc->Font = new System::Drawing::Font(S"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->gbCalc->Location = System::Drawing::Point(8, 56);
      this->gbCalc->Name = S"gbCalc";
      this->gbCalc->Size = System::Drawing::Size(586, 290);
      this->gbCalc->TabIndex = 37;
      this->gbCalc->TabStop = false;
      this->gbCalc->Text = S"Formula parsing";
      // 
      // btnListVar
      // 
      this->btnListVar->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->btnListVar->BackColor = System::Drawing::Color::LightGray;
      this->btnListVar->Location = System::Drawing::Point(482, 88);
      this->btnListVar->Name = S"btnListVar";
      this->btnListVar->Size = System::Drawing::Size(88, 24);
      this->btnListVar->TabIndex = 13;
      this->btnListVar->Text = S"List Variables";
      this->btnListVar->Click += new System::EventHandler(this, btnListVar_Click);
      // 
      // btnListConst
      // 
      this->btnListConst->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->btnListConst->BackColor = System::Drawing::Color::LightGray;
      this->btnListConst->Location = System::Drawing::Point(482, 120);
      this->btnListConst->Name = S"btnListConst";
      this->btnListConst->Size = System::Drawing::Size(88, 24);
      this->btnListConst->TabIndex = 12;
      this->btnListConst->Text = S"List Constants";
      this->btnListConst->Click += new System::EventHandler(this, btnListConst_Click);
      // 
      // btnListFun
      // 
      this->btnListFun->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->btnListFun->BackColor = System::Drawing::Color::LightGray;
      this->btnListFun->Location = System::Drawing::Point(482, 152);
      this->btnListFun->Name = S"btnListFun";
      this->btnListFun->Size = System::Drawing::Size(88, 24);
      this->btnListFun->TabIndex = 11;
      this->btnListFun->Text = S"List Functions";
      this->btnListFun->Click += new System::EventHandler(this, btnListFun_Click);
      // 
      // label2
      // 
      this->label2->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Left);
      this->label2->Font = new System::Drawing::Font(S"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->label2->Location = System::Drawing::Point(8, 258);
      this->label2->Name = S"label2";
      this->label2->Size = System::Drawing::Size(64, 16);
      this->label2->TabIndex = 10;
      this->label2->Text = S"Formula:";
      // 
      // edInput
      // 
      this->edInput->Anchor = (System::Windows::Forms::AnchorStyles)((System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Left) 
        | System::Windows::Forms::AnchorStyles::Right);
      this->edInput->Font = new System::Drawing::Font(S"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->edInput->Location = System::Drawing::Point(80, 258);
      this->edInput->Name = S"edInput";
      this->edInput->Size = System::Drawing::Size(394, 20);
      this->edInput->TabIndex = 9;
      this->edInput->Text = S"";
      this->edInput->KeyDown += new System::Windows::Forms::KeyEventHandler(this, edInput_KeyDown);
      // 
      // pbCalc
      // 
      this->pbCalc->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->pbCalc->Image = (__try_cast<System::Drawing::Image *  >(resources->GetObject(S"pbCalc.Image")));
      this->pbCalc->Location = System::Drawing::Point(498, 16);
      this->pbCalc->Name = S"pbCalc";
      this->pbCalc->Size = System::Drawing::Size(64, 64);
      this->pbCalc->TabIndex = 8;
      this->pbCalc->TabStop = false;
      // 
      // cbShowVar
      // 
      this->cbShowVar->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->cbShowVar->Checked = true;
      this->cbShowVar->CheckState = System::Windows::Forms::CheckState::Checked;
      this->cbShowVar->Location = System::Drawing::Point(490, 240);
      this->cbShowVar->Name = S"cbShowVar";
      this->cbShowVar->Size = System::Drawing::Size(72, 40);
      this->cbShowVar->TabIndex = 7;
      this->cbShowVar->Text = S"Show variables";
      // 
      // btnReset
      // 
      this->btnReset->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->btnReset->BackColor = System::Drawing::Color::LightGray;
      this->btnReset->Location = System::Drawing::Point(482, 216);
      this->btnReset->Name = S"btnReset";
      this->btnReset->Size = System::Drawing::Size(88, 24);
      this->btnReset->TabIndex = 6;
      this->btnReset->Text = S"Reset";
      this->btnReset->Click += new System::EventHandler(this, btnReset_Click);
      // 
      // btnUnit
      // 
      this->btnUnit->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->btnUnit->BackColor = System::Drawing::Color::LightGray;
      this->btnUnit->Location = System::Drawing::Point(482, 184);
      this->btnUnit->Name = S"btnUnit";
      this->btnUnit->Size = System::Drawing::Size(88, 24);
      this->btnUnit->TabIndex = 4;
      this->btnUnit->Text = S"Run unit test";
      this->btnUnit->Click += new System::EventHandler(this, btnUnit_Click);
      // 
      // reMain
      // 
      this->reMain->Anchor = (System::Windows::Forms::AnchorStyles)(((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Bottom) 
        | System::Windows::Forms::AnchorStyles::Left) 
        | System::Windows::Forms::AnchorStyles::Right);
      this->reMain->DetectUrls = false;
      this->reMain->Font = new System::Drawing::Font(S"Arial", 9.75F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->reMain->Location = System::Drawing::Point(8, 16);
      this->reMain->Name = S"reMain";
      this->reMain->ReadOnly = true;
      this->reMain->Size = System::Drawing::Size(466, 234);
      this->reMain->TabIndex = 1;
      this->reMain->Text = S"";
      // 
      // paTitle
      // 
      this->paTitle->BackColor = System::Drawing::Color::Transparent;
      this->paTitle->BackgroundImage = (__try_cast<System::Drawing::Image *  >(resources->GetObject(S"paTitle.BackgroundImage")));
      this->paTitle->Controls->Add(this->lbSelector);
      this->paTitle->Controls->Add(this->cbParser);
      this->paTitle->Controls->Add(this->lbAuthor);
      this->paTitle->Controls->Add(this->label1);
      this->paTitle->Dock = System::Windows::Forms::DockStyle::Top;
      this->paTitle->Location = System::Drawing::Point(0, 0);
      this->paTitle->Name = S"paTitle";
      this->paTitle->Size = System::Drawing::Size(600, 53);
      this->paTitle->TabIndex = 8;
      // 
      // lbSelector
      // 
      this->lbSelector->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->lbSelector->BackColor = System::Drawing::Color::Transparent;
      this->lbSelector->Font = new System::Drawing::Font(S"Microsoft Sans Serif", 10, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->lbSelector->ForeColor = System::Drawing::Color::Black;
      this->lbSelector->Location = System::Drawing::Point(304, 16);
      this->lbSelector->Name = S"lbSelector";
      this->lbSelector->Size = System::Drawing::Size(88, 19);
      this->lbSelector->TabIndex = 15;
      this->lbSelector->Text = S"parser class";
      // 
      // cbParser
      // 
      this->cbParser->Anchor = (System::Windows::Forms::AnchorStyles)(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right);
      this->cbParser->DropDownStyle = System::Windows::Forms::ComboBoxStyle::DropDownList;
      System::Object* __mcTemp__1[] = new System::Object*[2];
      __mcTemp__1[0] = S"double numbers (muParser)";
      __mcTemp__1[1] = S"int numbers (muParserInt)";
      this->cbParser->Items->AddRange(__mcTemp__1);
      this->cbParser->Location = System::Drawing::Point(394, 16);
      this->cbParser->Name = S"cbParser";
      this->cbParser->Size = System::Drawing::Size(176, 21);
      this->cbParser->TabIndex = 14;
      this->cbParser->SelectedIndexChanged += new System::EventHandler(this, cbParser_SelectedIndexChanged);
      // 
      // lbAuthor
      // 
      this->lbAuthor->BackColor = System::Drawing::Color::Transparent;
      this->lbAuthor->Font = new System::Drawing::Font(S"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->lbAuthor->ForeColor = System::Drawing::Color::White;
      this->lbAuthor->Location = System::Drawing::Point(8, 24);
      this->lbAuthor->Name = S"lbAuthor";
      this->lbAuthor->Size = System::Drawing::Size(192, 16);
      this->lbAuthor->TabIndex = 12;
      this->lbAuthor->Text = S"(C) 2005 Ingo Berg";
      // 
      // label1
      // 
      this->label1->BackColor = System::Drawing::Color::Transparent;
      this->label1->Font = new System::Drawing::Font(S"Microsoft Sans Serif", 12, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, (System::Byte)0);
      this->label1->ForeColor = System::Drawing::Color::White;
      this->label1->Location = System::Drawing::Point(8, 3);
      this->label1->Name = S"label1";
      this->label1->Size = System::Drawing::Size(312, 26);
      this->label1->TabIndex = 13;
      this->label1->Text = S"Fast math parser ";
      // 
      // WinCalc
      // 
      this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
      this->ClientSize = System::Drawing::Size(600, 349);
      this->Controls->Add(this->paBase);
      this->MinimumSize = System::Drawing::Size(608, 376);
      this->Name = S"WinCalc";
      this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
      this->Text = S"Calculator";
      this->paBase->ResumeLayout(false);
      this->gbCalc->ResumeLayout(false);
      this->paTitle->ResumeLayout(false);
      this->ResumeLayout(false);

    }	

  private:
      mu::ParserBase *m_pParser;
      mu::Parser    *m_pParserDbl;
      mu::ParserInt *m_pParserInt;

      double *m_pfVar;
      StringCollection *m_History; 
      int m_iHistLine;
      int m_iVarCount;
      WndError *dlgError;

      // Container for a ComboBox entry
      // consisting of a name and a pointer
      // to a parser object
      __gc class BoxItem : public System::Object
      {
      public:
        BoxItem(const char *a_szName, mu::ParserBase *a_pParser)
        :System::Object()
        ,m_pParser(a_pParser)
        ,m_strName(new System::String(a_szName))
        {
        };
        
        String* ToString()
        {
          return m_strName;
        }

        mu::ParserBase* GetParser()
        {
          return m_pParser;
        };

      private:
        mu::ParserBase *m_pParser;
        String *m_strName;
      };

      //---------------------------------------------------------------------------
      void ScrollToEnd()
      {
        reMain->Select(reMain->Text->Length, 0);
        reMain->Focus();
        reMain->ScrollToCaret();
        edInput->Focus();
      }

      //---------------------------------------------------------------------------
      void Calc(const char *pszFormula)
      {
        reMain->SelectionColor = System::Drawing::Color::Blue;
        reMain->AppendText(pszFormula);
        reMain->AppendText("\r\n");
        reMain->SelectionColor = System::Drawing::Color::Black;

        try
        {
          using mu::Parser::exception_type;

          // 1.) does the formula contain a equal sign?
          char szName[256], szEqn[256];
          int iStat = std::sscanf(pszFormula, "%255[^=]=%255s", szName, szEqn);
        

          // There is no "=" present in the string, thus it cant be a variable declaration
          // and must be a normal formula
          if (iStat!=2)
          {
            m_pParser->SetExpr(pszFormula);

            if (cbShowVar->Checked)
              DumpUsedVariables(); 

            m_pfVar[0] = m_pParser->Eval();  // Calculate result and store in variable "ans"
          }
          else
          {
            if (m_iVarCount>=99)
              throw mu::Parser::exception_type("Maximum number of variables exceeded");

            // Variable name is empty or contains invalid charakters
            if (!std::strlen(szName) ||
                 std::strspn(szName, m_pParser->ValidNameChars())!=std::strlen(szName))
            {
              std::ostringstream os;
              os << "Invalid token name: \"" << szName << "\"\n";
              throw mu::Parser::exception_type(os.str().c_str());
            } 
            m_pParser->SetExpr(szEqn);

            // Calculate the new variable value
            m_pfVar[0] = m_pfVar[m_iVarCount] = m_pParser->Eval();

            // Add to parser
            m_pParser->DefineVar(szName, &m_pfVar[m_iVarCount++] ); 
          }

          // Print the result
          String *pResult = Convert::ToString( m_pfVar[0] );
          reMain->AppendText("ans = ");
          reMain->AppendText(pResult);
          reMain->AppendText("\r\n");
        }
        catch(Parser::exception_type &e)
        {
          m_pfVar[0] = 0;
          reMain->SelectionColor = System::Drawing::Color::Red;
          reMain->AppendText(e.GetMsg().c_str());
          reMain->AppendText("\r\n");
          reMain->SelectionColor = System::Drawing::Color::Black;
        }

        ScrollToEnd();
      }

      //---------------------------------------------------------------------------
      void Reset()
      {
        delete [] m_pfVar;
        m_pfVar = new double[VARCOUNT];
        m_pfVar[0] = 0;

        // Reinitialize the parser
        m_pParserInt->ClearVar();
        m_pParserInt->DefineVar("ans", &m_pfVar[0]);

        m_pParserDbl->ClearVar();
        m_pParserDbl->DefineVar("ans", &m_pfVar[0]);

        cbParser->SelectedIndex = 0;

        // Clear history and text fields
        m_History->Clear();
        reMain->ResetText();
        edInput->Text = "";
      }

      //---------------------------------------------------------------------------
      void DumpUsedVariables()
      {
        // Query the used variables (must be done after calc)
        mu::varmap_type UsedVar = m_pParser->GetUsedVar();

        if (UsedVar.size())
        {
          std::ostringstream os;
          os << "Used variables:\n";
          os << "    Number: " << (int)UsedVar.size() << "\n";

          mu::varmap_type::const_iterator item = UsedVar.begin();
          for (; item!=UsedVar.end(); ++item)
            os << "    Name: " << item->first << "   Address: [0x" << item->second << "]\n";

          reMain->SelectionColor = System::Drawing::Color::Green;
          reMain->AppendText(os.str().c_str());
          reMain->SelectionColor = System::Drawing::Color::Black;
          reMain->Invalidate();
        } 
      }

private: System::Void btnReset_Click(System::Object*, System::EventArgs*)
         {
           Reset();
         }

private: System::Void btnUnit_Click(System::Object*, System::EventArgs*)
         {
           Reset();

           std::ostringstream os;
           os << "------------------------------------------------------------\n";
           os << "  Math Parser sample application\n";
           os << "------------------------------------------------------------\n";
           os << "\nUnit testing in progress...\n";
           reMain->AppendText(os.str().c_str());
           reMain->Update();

           os.str(std::string());
           mu::Test::ParserTester pt;
           pt.SetStream(&os);
           pt.Run();

           reMain->AppendText(os.str().c_str());
           ScrollToEnd();
         }

private: System::Void edInput_KeyDown(System::Object*, System::Windows::Forms::KeyEventArgs *e)
         {
           enum Keys iCode = e->KeyCode;
           int iHistLen = m_History->Count;

           switch(iCode)
           {
           case Return:
                {
                  char *pszFormula = (char*)(void*)Marshal::StringToHGlobalAnsi(edInput->Text);
                  try
                  {
                    Calc(pszFormula);

                    // Add Formula to history
                    if ( pszFormula && std::strlen(pszFormula) )
                      m_iHistLine = m_History->Add(pszFormula); 

                    edInput->Text = "";
                  }
                  catch(...)
                  {
                    Marshal::FreeHGlobal(pszFormula);                      
                    throw;
                  }

                  Marshal::FreeHGlobal(pszFormula);                      
                }
                break;

           case Up:
           case Down:
               m_iHistLine = System::Math::Max(0, System::Math::Min(iHistLen-1, m_iHistLine) );
        
               if (!m_History->Count)
                 break;
               
               edInput->Text = static_cast<String*>(m_History->Item[m_iHistLine]);
               edInput->Select(edInput->Text->Length,0);

               m_iHistLine += (iCode==Up) ? -1 : 1;
               break;
           }
         }

private: System::Void btnListFun_Click(System::Object*, System::EventArgs*)
         {
           // Make the type of the map containing function prototypes visible
           using mu::funmap_type;
           
           funmap_type funmap = m_pParser->GetFunDef();
           funmap_type::const_iterator item;
           std::ostringstream os;
           os << "\nFunctions available:\n";
  
           // iterate over all function definitions
           for (item=funmap.begin(); item!=funmap.end(); ++item)
           {
             os << "  " << item->first;   // This is the Function Name
             os << "(";
             
             // Deal with different argument numbers
             int iArgc = item->second.GetArgc();
             if (iArgc>=0)
             {
               // Indicate number of input variables
               for (int i=0; i<iArgc; ++i)
               {
                 char cVar[] = "val ";
                 cVar[3] = '1' + (char)i;
                 os << cVar;
                 if (i!=iArgc-1)
                   os << ",";
               }
             }
             else
             {
               os << "...";  // Multiargument function
             }
             
             os << ")\r\n";
           }

           // output
           reMain->Focus();
           reMain->SelectionColor = System::Drawing::Color::Green;
           reMain->AppendText(os.str().c_str());
           reMain->SelectionColor = System::Drawing::Color::Black;

           ScrollToEnd();
         }

private: System::Void btnListConst_Click(System::Object*, System::EventArgs*)
         {
           // Make the type of the map containing function prototypes visible
           using mu::valmap_type;
           
           valmap_type cvalmap = m_pParser->GetConst();
           valmap_type::const_iterator item;
           std::ostringstream os;
           os << "\nConstants available:\n";
  
           // iterate over all function definitions
           if (!cvalmap.size())
           {
             os << "  none\n";
           }
           else
           {
            for (item=cvalmap.begin(); item!=cvalmap.end(); ++item)
            {
              os << "  " << item->first;   // This is the Function Name
              os << " = ";
              os << item->second;
              os << "\n";
            }
           }

           // output
           reMain->Focus();
           reMain->SelectionColor = System::Drawing::Color::Green;
           reMain->AppendText(os.str().c_str());
           reMain->SelectionColor = System::Drawing::Color::Black;

           ScrollToEnd();
           }

private: System::Void btnListVar_Click(System::Object*, System::EventArgs*)
         {
           mu::varmap_type UsedVar = m_pParser->GetVar();

           if (UsedVar.size())
           {
              std::ostringstream os;
              os << "\nVariables available:\n";

              mu::varmap_type::const_iterator item = UsedVar.begin();
              for (; item!=UsedVar.end(); ++item)
                os << "  " << item->first << "  = " << *item->second << "\n";

              reMain->SelectionColor = System::Drawing::Color::Green;
              reMain->AppendText(os.str().c_str());
              reMain->SelectionColor = System::Drawing::Color::Black;
              reMain->Invalidate();

              ScrollToEnd();
           } 
         }

private: System::Void cbParser_SelectedIndexChanged(System::Object*, System::EventArgs*)
         {
           BoxItem *pItem = static_cast<BoxItem*>(cbParser->SelectedItem);

           m_pParser = pItem->GetParser();
           reMain->SelectionColor = System::Drawing::Color::Green;
           reMain->AppendText( "\nSetting parser to:  " );
           reMain->AppendText( pItem->ToString() );
           reMain->AppendText( "\n" );
           reMain->SelectionColor = System::Drawing::Color::Black;

           ScrollToEnd();
         }

}; // end of class

} // end of namespace 


