/////////////////////////////////////////////////////////////////////////////
// Name:        tex2rtf.cpp
// Purpose:     Converts Latex to linear/WinHelp RTF, HTML, wxHelp.
// Author:      Julian Smart
// Modified by: Wlodzimiez ABX Skiba 2003/2004 Unicode support
//              Ron Lee
// Created:     7.9.93
// RCS-ID:      $Id: tex2rtf.cpp,v 1.58 2006/08/28 10:29:23 VZ Exp $
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#if defined(__WXMSW__)
    #include "wx/msw/wrapwin.h"
#endif

#ifndef WX_PRECOMP
    #ifndef NO_GUI
        #include "wx/menu.h"
        #include "wx/textctrl.h"
        #include "wx/filedlg.h"
        #include "wx/msgdlg.h"
        #include "wx/icon.h"
    #endif
#endif

#include "wx/log.h"

#ifndef NO_GUI
    #include "wx/timer.h"
    #include "wx/help.h"
    #include "wx/cshelp.h"
    #include "wx/helphtml.h"
    #ifdef __WXMSW__
        #include "wx/msw/helpchm.h"
    #else
        #include "wx/html/helpctrl.h"
    #endif
#endif // !NO_GUI

#include "wx/utils.h"

#if wxUSE_IOSTREAMH
#include <iostream.h>
#include <fstream.h>
#else
#include <iostream>
#include <fstream>
#endif

#include <ctype.h>
#include <stdlib.h>
#include "tex2any.h"
#include "tex2rtf.h"
#include "rtfutils.h"
#include "symbols.h"

#if (defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXX11__) || defined(__WXMGL__)) && !defined(NO_GUI)
#include "tex2rtf.xpm"
#endif

#if !WXWIN_COMPATIBILITY_2_4
static inline wxChar* copystring(const wxChar* s)
    { return wxStrcpy(new wxChar[wxStrlen(s) + 1], s); }
#endif

const float versionNo = float(TEX2RTF_VERSION_NUMBER);

TexChunk *currentMember = NULL;
bool startedSections = false;
wxChar *contentsString = NULL;
bool suppressNameDecoration = false;
bool OkToClose = true;
int passNumber = 1;
unsigned long errorCount = 0;

#ifndef NO_GUI

extern wxChar *BigBuffer;
extern wxChar *TexFileRoot;
extern wxChar *TexBibName;         // Bibliography output file name
extern wxChar *TexTmpBibName;      // Temporary bibliography output file name
extern wxList ColourTable;
extern TexChunk *TopLevel;

#if wxUSE_HELP
wxHelpControllerBase *HelpInstance = NULL;
#endif // wxUSE_HELP

#ifdef __WXMSW__
static wxChar *ipc_buffer = NULL;
static wxChar Tex2RTFLastStatus[100];
Tex2RTFServer *TheTex2RTFServer = NULL;
#endif // __WXMSW__

#endif // !NO_GUI

wxChar *bulletFile = NULL;

FILE *Contents = NULL;   // Contents page
FILE *Chapters = NULL;   // Chapters (WinHelp RTF) or rest of file (linear RTF)
FILE *Sections = NULL;
FILE *Subsections = NULL;
FILE *Subsubsections = NULL;
FILE *Popups = NULL;
FILE *WinHelpContentsFile = NULL;

wxString InputFile;
wxString OutputFile;
wxChar *MacroFile = copystring(_T("tex2rtf.ini"));

wxChar *FileRoot = NULL;
wxChar *ContentsName = NULL;    // Contents page from last time around
wxChar *TmpContentsName = NULL; // Current contents page
wxChar *TmpFrameContentsName = NULL; // Current frame contents page
wxChar *WinHelpContentsFileName = NULL; // WinHelp .cnt file
wxChar *RefFileName = NULL;         // Reference file name

wxChar *RTFCharset = copystring(_T("ansi"));

#ifdef __WXMSW__
int BufSize = 100;             // Size of buffer in K
#else
int BufSize = 500;
#endif

bool Go(void);
void ShowOptions(void);

wxChar wxTex2RTFBuffer[1500];

#ifdef NO_GUI
    IMPLEMENT_APP_CONSOLE(MyApp)
#else
    wxMenuBar *menuBar = NULL;
    MyFrame *frame = NULL;
    // DECLARE_APP(MyApp)
    IMPLEMENT_APP(MyApp)
#endif

// `Main program' equivalent, creating windows and returning main app frame
bool MyApp::OnInit()
{
  // Use default list of macros defined in tex2any.cc
  DefineDefaultMacros();
  AddMacroDef(ltHARDY, _T("hardy"), 0);

  FileRoot = new wxChar[300];
  ContentsName = new wxChar[300];
  TmpContentsName = new wxChar[300];
  TmpFrameContentsName = new wxChar[300];
  WinHelpContentsFileName = new wxChar[300];
  RefFileName = new wxChar[300];

  WX_CLEAR_LIST(wxList,ColourTable);

  int n = 1;

  // Read input/output files
  if (argc > 1)
  {
      if (argv[1][0] != _T('-'))
      {
          InputFile = argv[1];
          n ++;

          if (argc > 2)
          {
              if (argv[2][0] != _T('-'))
              {
                  OutputFile = argv[2];
                  n ++;
              }
          }
      }
  }

  TexPathList.Add(::wxGetCwd());

#ifdef NO_GUI
  if (InputFile.empty() || OutputFile.empty())
  {
      wxSTD cout << "Tex2RTF: input or output file is missing.\n";
      ShowOptions();
      exit(1);
  }
#endif

  if (!InputFile.empty())
  {
      TexPathList.EnsureFileAccessible(InputFile);
  }
  if (InputFile.empty() || OutputFile.empty())
      isInteractive = true;

  int i;
  for (i = n; i < argc;)
  {
    if (wxStrcmp(argv[i], _T("-winhelp")) == 0)
    {
      i ++;
      convertMode = TEX_RTF;
      winHelp = true;
    }
#ifndef NO_GUI
    else if (wxStrcmp(argv[i], _T("-interactive")) == 0)
    {
      i ++;
      isInteractive = true;
    }
#endif
    else if (wxStrcmp(argv[i], _T("-sync")) == 0)  // Don't yield
    {
      i ++;
      isSync = true;
    }
    else if (wxStrcmp(argv[i], _T("-rtf")) == 0)
    {
      i ++;
      convertMode = TEX_RTF;
    }
    else if (wxStrcmp(argv[i], _T("-html")) == 0)
    {
      i ++;
      convertMode = TEX_HTML;
    }
    else if (wxStrcmp(argv[i], _T("-xlp")) == 0)
    {
      i ++;
      convertMode = TEX_XLP;
    }
    else if (wxStrcmp(argv[i], _T("-twice")) == 0)
    {
      i ++;
      runTwice = true;
    }
    else if (wxStrcmp(argv[i], _T("-macros")) == 0)
    {
      i ++;
      if (i < argc)
      {
        MacroFile = copystring(argv[i]);
        i ++;
      }
    }
    else if (wxStrcmp(argv[i], _T("-bufsize")) == 0)
    {
      i ++;
      if (i < argc)
      {
        BufSize = wxAtoi(argv[i]);
        i ++;
      }
    }
    else if (wxStrcmp(argv[i], _T("-charset")) == 0)
    {
      i ++;
      if (i < argc)
      {
        wxChar *s = argv[i];
        i ++;
        if (wxStrcmp(s, _T("ansi")) == 0 || wxStrcmp(s, _T("pc")) == 0 || wxStrcmp(s, _T("mac")) == 0 ||
            wxStrcmp(s, _T("pca")) == 0)
          RTFCharset = copystring(s);
        else
        {
          OnError(_T("Incorrect argument for -charset"));
          return false;
        }
      }
    }
    else if (wxStrcmp(argv[i], _T("-checkcurlybraces")) == 0)
    {
      i ++;
      checkCurlyBraces = true;
    }
    else if (wxStrcmp(argv[i], _T("-checkcurleybraces")) == 0)
    {
      // Support the old, incorrectly spelled version of -checkcurlybraces
      // so that old scripts which run tex2rtf -checkcurleybraces still work.
      i ++;
      checkCurlyBraces = true;
    }
    else if (wxStrcmp(argv[i], _T("-checksyntax")) == 0)
    {
      i ++;
      checkSyntax = true;
    }
    else
    {
      wxString buf;
      buf.Printf(_T("Invalid switch %s.\n"), argv[i]);
      OnError((wxChar *)buf.c_str());
#ifdef NO_GUI
      ShowOptions();
      exit(1);
#else
      return false;
#endif
    }
  }

#if defined(__WXMSW__) && !defined(NO_GUI)
  wxDDEInitialize();
  Tex2RTFLastStatus[0] = 0; // DDE connection return value
  TheTex2RTFServer = new Tex2RTFServer;
  TheTex2RTFServer->Create(_T("TEX2RTF"));
#endif

  TexInitialize(BufSize);
  ResetContentsLevels(0);

#ifndef NO_GUI

  if (isInteractive)
  {
    // Create the main frame window
    frame = new MyFrame(NULL, wxID_ANY, _T("Tex2RTF"), wxDefaultPosition, wxSize(400, 300));
#if wxUSE_STATUSBAR
    frame->CreateStatusBar(2);
#endif // wxUSE_STATUSBAR

    // Give it an icon
    // TODO: uncomment this when we have tex2rtf.xpm
    frame->SetIcon(wxICON(tex2rtf));

    if (!InputFile.empty())
    {
        wxString title;
        title.Printf( _T("Tex2RTF [%s]"), wxFileNameFromPath(InputFile).c_str());
        frame->SetTitle(title);
    }

    // Make a menubar
    wxMenu *file_menu = new wxMenu;
    file_menu->Append(TEX_GO, _T("&Go"), _T("Run converter"));
    file_menu->Append(TEX_SET_INPUT, _T("Set &Input File"), _T("Set the LaTeX input file"));
    file_menu->Append(TEX_SET_OUTPUT, _T("Set &Output File"), _T("Set the output file"));
    file_menu->AppendSeparator();
    file_menu->Append(TEX_VIEW_LATEX, _T("View &LaTeX File"), _T("View the LaTeX input file"));
    file_menu->Append(TEX_VIEW_OUTPUT, _T("View Output &File"), _T("View output file"));
    file_menu->Append(TEX_SAVE_FILE, _T("&Save log file"), _T("Save displayed text into file"));
    file_menu->AppendSeparator();
    file_menu->Append(TEX_QUIT, _T("E&xit"), _T("Exit Tex2RTF"));

    wxMenu *macro_menu = new wxMenu;

    macro_menu->Append(TEX_LOAD_CUSTOM_MACROS, _T("&Load Custom Macros"), _T("Load custom LaTeX macro file"));
    macro_menu->Append(TEX_VIEW_CUSTOM_MACROS, _T("View &Custom Macros"), _T("View custom LaTeX macros"));

    wxMenu *mode_menu = new wxMenu;

    mode_menu->Append(TEX_MODE_RTF, _T("Output linear &RTF"), _T("Wordprocessor-compatible RTF"));
    mode_menu->Append(TEX_MODE_WINHELP, _T("Output &WinHelp RTF"), _T("WinHelp-compatible RTF"));
    mode_menu->Append(TEX_MODE_HTML, _T("Output &HTML"), _T("HTML World Wide Web hypertext file"));
    mode_menu->Append(TEX_MODE_XLP, _T("Output &XLP"), _T("wxHelp hypertext help file"));

    wxMenu *options_menu = new wxMenu;

    options_menu->Append(TEX_OPTIONS_CURLY_BRACE, _T("Curly brace matching"), _T("Checks for mismatched curly braces"),true);
    options_menu->Append(TEX_OPTIONS_SYNTAX_CHECKING, _T("Syntax checking"), _T("Syntax checking for common errors"),true);

    options_menu->Check(TEX_OPTIONS_CURLY_BRACE, checkCurlyBraces);
    options_menu->Check(TEX_OPTIONS_SYNTAX_CHECKING, checkSyntax);

    wxMenu *help_menu = new wxMenu;

    help_menu->Append(TEX_HELP, _T("&Help"), _T("Tex2RTF Contents Page"));
    help_menu->Append(TEX_ABOUT, _T("&About Tex2RTF"), _T("About Tex2RTF"));

    menuBar = new wxMenuBar;
    menuBar->Append(file_menu, _T("&File"));
    menuBar->Append(macro_menu, _T("&Macros"));
    menuBar->Append(mode_menu, _T("&Conversion Mode"));
    menuBar->Append(options_menu, _T("&Options"));
    menuBar->Append(help_menu, _T("&Help"));

    frame->SetMenuBar(menuBar);
    frame->textWindow = new wxTextCtrl(frame, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY|wxTE_MULTILINE);

    (*frame->textWindow) << _T("Welcome to Tex2RTF.\n");
//    ShowOptions();

#if wxUSE_HELP
#if wxUSE_MS_HTML_HELP && !defined(__WXUNIVERSAL__)
    HelpInstance = new wxCHMHelpController;
#else
    HelpInstance = new wxHelpController;
#endif
    HelpInstance->Initialize(_T("tex2rtf"));
#endif // wxUSE_HELP

    /*
     * Read macro/initialisation file
     *
     */

    wxString path = TexPathList.FindValidPath(MacroFile);
    if (!path.empty())
        ReadCustomMacros(path);

#if wxUSE_STATUSBAR
    wxString inStr(_T("In "));
    switch (convertMode)
    {
        case TEX_RTF:
            if(winHelp)
                inStr += _T("WinHelp RTF");
            else
                inStr += _T("linear RTF");
            break;

        case TEX_HTML:
            inStr += _T("HTML");
            break;

        case TEX_XLP:
            inStr += _T("XLP");
            break;

        default:
            inStr += _T("unknown");
            break;
    }
    inStr += _T(" mode.");
    frame->SetStatusText(inStr, 1);
#endif // wxUSE_STATUSBAR

    frame->Show(true);
    return true;
  }
  else
#endif // NO_GUI
  {
    /*
     * Read macro/initialisation file
     *
     */

    wxString path = TexPathList.FindValidPath(MacroFile);
    if (!path.empty())
        ReadCustomMacros(path);

    bool rc = Go();
    if ( rc && runTwice )
    {
        rc = Go();
    }
#ifdef NO_GUI
    return rc;
#else
    OnExit(); // Do cleanup since OnExit won't be called now
    return false;
#endif
  }
}

#ifndef NO_GUI
int MyApp::OnExit()
{
  wxNode *node = CustomMacroList.GetFirst();
  while (node)
  {
    CustomMacro *macro = (CustomMacro *)node->GetData();
    delete macro;
    delete node;
    node = CustomMacroList.GetFirst();
  }
  MacroDefs.BeginFind();
  wxHashTable::Node* mNode = MacroDefs.Next();
  while (mNode)
  {
    TexMacroDef* def = (TexMacroDef*) mNode->GetData();
    delete def;
    mNode = MacroDefs.Next();
  }
  MacroDefs.Clear();
#ifdef __WXMSW__
  delete TheTex2RTFServer;
  wxDDECleanUp();
#endif

#if wxUSE_HELP
  delete HelpInstance;
#endif // wxUSE_HELP

    if (BigBuffer)
    {
      delete BigBuffer;
      BigBuffer = NULL;
    }
    if (currentArgData)
    {
      delete currentArgData;
      currentArgData = NULL;
    }
    if (TexFileRoot)
    {
      delete TexFileRoot;
      TexFileRoot = NULL;
    }
    if (TexBibName)
    {
      delete TexBibName;
      TexBibName = NULL;
    }
    if (TexTmpBibName)
    {
      delete TexTmpBibName;
      TexTmpBibName = NULL;
    }
    if (FileRoot)
    {
      delete FileRoot;
      FileRoot = NULL;
    }
    if (ContentsName)
    {
      delete ContentsName;
      ContentsName = NULL;
    }
    if (TmpContentsName)
    {
      delete TmpContentsName;
      TmpContentsName = NULL;
    }
    if (TmpFrameContentsName)
    {
      delete TmpFrameContentsName;
      TmpFrameContentsName = NULL;
    }
    if (WinHelpContentsFileName)
    {
      delete WinHelpContentsFileName;
      WinHelpContentsFileName = NULL;
    }
    if (RefFileName)
    {
      delete RefFileName;
      RefFileName = NULL;
    }
    if (TopLevel)
    {
      delete TopLevel;
      TopLevel = NULL;
    }
    if (MacroFile)
    {
      delete MacroFile;
      MacroFile = NULL;
    }
    if (RTFCharset)
    {
      delete RTFCharset;
      RTFCharset = NULL;
    }

    delete [] PageStyle;
    delete [] BibliographyStyleString;
    delete [] DocumentStyleString;
    delete [] bitmapMethod;
    delete [] backgroundColourString;
    delete [] ContentsNameString;
    delete [] AbstractNameString;
    delete [] GlossaryNameString;
    delete [] ReferencesNameString;
    delete [] FiguresNameString;
    delete [] TablesNameString;
    delete [] FigureNameString;
    delete [] TableNameString;
    delete [] IndexNameString;
    delete [] ChapterNameString;
    delete [] SectionNameString;
    delete [] SubsectionNameString;
    delete [] SubsubsectionNameString;
    delete [] UpNameString;
    if (winHelpTitle)
      delete[] winHelpTitle;

  // TODO: this simulates zero-memory leaks!
  // Otherwise there are just too many...
#ifndef __WXGTK__
#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
  wxDebugContext::SetCheckpoint();
#endif
#endif

  return 0;
}
#endif
void ShowOptions(void)
{
    wxChar buf[100];
    wxSnprintf(buf, sizeof(buf), _T("Tex2RTF version %.2f"), versionNo);
    OnInform(buf);
    OnInform(_T("Usage: tex2rtf [input] [output] [switches]\n"));
    OnInform(_T("where valid switches are"));
#ifndef NO_GUI
    OnInform(_T("    -interactive"));
#endif
    OnInform(_T("    -bufsize <size in K>"));
    OnInform(_T("    -charset <pc | pca | ansi | mac> (default ansi)"));
    OnInform(_T("    -twice"));
    OnInform(_T("    -sync"));
    OnInform(_T("    -checkcurlybraces"));
    OnInform(_T("    -checksyntax"));
    OnInform(_T("    -macros <filename>"));
    OnInform(_T("    -winhelp"));
    OnInform(_T("    -rtf"));
    OnInform(_T("    -html"));
    OnInform(_T("    -xlp\n"));
}

#ifndef NO_GUI

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_CLOSE(MyFrame::OnCloseWindow)
    EVT_MENU(TEX_QUIT, MyFrame::OnExit)
    EVT_MENU(TEX_GO, MyFrame::OnGo)
    EVT_MENU(TEX_SET_INPUT, MyFrame::OnSetInput)
    EVT_MENU(TEX_SET_OUTPUT, MyFrame::OnSetOutput)
    EVT_MENU(TEX_SAVE_FILE, MyFrame::OnSaveFile)
    EVT_MENU(TEX_VIEW_LATEX, MyFrame::OnViewLatex)
    EVT_MENU(TEX_VIEW_OUTPUT, MyFrame::OnViewOutput)
    EVT_MENU(TEX_VIEW_CUSTOM_MACROS, MyFrame::OnShowMacros)
    EVT_MENU(TEX_LOAD_CUSTOM_MACROS, MyFrame::OnLoadMacros)
    EVT_MENU(TEX_MODE_RTF, MyFrame::OnModeRTF)
    EVT_MENU(TEX_MODE_WINHELP, MyFrame::OnModeWinHelp)
    EVT_MENU(TEX_MODE_HTML, MyFrame::OnModeHTML)
    EVT_MENU(TEX_MODE_XLP, MyFrame::OnModeXLP)
    EVT_MENU(TEX_OPTIONS_CURLY_BRACE, MyFrame::OnOptionsCurlyBrace)
    EVT_MENU(TEX_OPTIONS_SYNTAX_CHECKING, MyFrame::OnOptionsSyntaxChecking)
    EVT_MENU(TEX_HELP, MyFrame::OnHelp)
    EVT_MENU(TEX_ABOUT, MyFrame::OnAbout)
END_EVENT_TABLE()

// My frame constructor
MyFrame::MyFrame(wxFrame *frame, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size):
  wxFrame(frame, id, title, pos, size)
{}

void MyFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
{
  if (!stopRunning && !OkToClose)
  {
    stopRunning = true;
    runTwice = false;
    return;
  }
  else if (OkToClose)
  {
    this->Destroy();
  }
}

void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event))
{
  Close();
//    this->Destroy();
}

void MyFrame::OnGo(wxCommandEvent& WXUNUSED(event))
{
      passNumber = 1;
      errorCount = 0;
      menuBar->EnableTop(0, false);
      menuBar->EnableTop(1, false);
      menuBar->EnableTop(2, false);
      menuBar->EnableTop(3, false);
      textWindow->Clear();
      Tex2RTFYield(true);
      Go();

      if (stopRunning)
      {
#if wxUSE_STATUSBAR
        SetStatusText(_T("Build aborted!"));
#endif // wxUSE_STATUSBAR
        wxString errBuf;
        errBuf.Printf(_T("\nErrors encountered during this pass: %lu\n"), errorCount);
        OnInform((wxChar *)errBuf.c_str());
      }


      if (runTwice && !stopRunning)
      {
        Tex2RTFYield(true);
        Go();
      }
      menuBar->EnableTop(0, true);
      menuBar->EnableTop(1, true);
      menuBar->EnableTop(2, true);
      menuBar->EnableTop(3, true);
}

void MyFrame::OnSetInput(wxCommandEvent& WXUNUSED(event))
{
      ChooseInputFile(true);
}

void MyFrame::OnSetOutput(wxCommandEvent& WXUNUSED(event))
{
      ChooseOutputFile(true);
}

void MyFrame::OnSaveFile(wxCommandEvent& WXUNUSED(event))
{
#if wxUSE_FILEDLG
    wxString s = wxFileSelector(_T("Save text to file"), wxEmptyString, wxEmptyString, _T("txt"), _T("*.txt"));
    if (!s.empty())
    {
        textWindow->SaveFile(s);
#if wxUSE_STATUSBAR
        wxChar buf[350];
        wxSnprintf(buf, sizeof(buf), _T("Saved text to %s"), (const wxChar*) s.c_str());
        frame->SetStatusText(buf, 0);
#endif // wxUSE_STATUSBAR
    }
#endif // wxUSE_FILEDLG
}

void MyFrame::OnViewOutput(wxCommandEvent& WXUNUSED(event))
{
    ChooseOutputFile();
    if (!OutputFile.empty() && wxFileExists(OutputFile))
    {
        textWindow->LoadFile(OutputFile);
        wxChar buf[300];
        wxString str(wxFileNameFromPath(OutputFile));
        wxSnprintf(buf, sizeof(buf), _T("Tex2RTF [%s]"), (const wxChar*) str.c_str());
        frame->SetTitle(buf);
    }
}

void MyFrame::OnViewLatex(wxCommandEvent& WXUNUSED(event))
{
    ChooseInputFile();
    if (!InputFile.empty() && wxFileExists(InputFile))
    {
        textWindow->LoadFile(InputFile);
        wxChar buf[300];
        wxString str(wxFileNameFromPath(OutputFile));
        wxSnprintf(buf, sizeof(buf), _T("Tex2RTF [%s]"), (const wxChar*) str.c_str());
        frame->SetTitle(buf);
    }
}

void MyFrame::OnLoadMacros(wxCommandEvent& WXUNUSED(event))
{
    textWindow->Clear();
#if wxUSE_FILEDLG
    wxString s = wxFileSelector(_T("Choose custom macro file"), wxPathOnly(MacroFile), wxFileNameFromPath(MacroFile), _T("ini"), _T("*.ini"));
    if (!s.empty() && wxFileExists(s))
    {
        MacroFile = copystring(s);
        ReadCustomMacros(s);
        ShowCustomMacros();
    }
#endif // wxUSE_FILEDLG
}

void MyFrame::OnShowMacros(wxCommandEvent& WXUNUSED(event))
{
    textWindow->Clear();
    Tex2RTFYield(true);
    ShowCustomMacros();
}

void MyFrame::OnModeRTF(wxCommandEvent& WXUNUSED(event))
{
    convertMode = TEX_RTF;
    winHelp = false;
    InputFile = wxEmptyString;
    OutputFile = wxEmptyString;
#if wxUSE_STATUSBAR
    SetStatusText(_T("In linear RTF mode."), 1);
#endif // wxUSE_STATUSBAR
}

void MyFrame::OnModeWinHelp(wxCommandEvent& WXUNUSED(event))
{
    convertMode = TEX_RTF;
    winHelp = true;
    InputFile = wxEmptyString;
    OutputFile = wxEmptyString;
#if wxUSE_STATUSBAR
    SetStatusText(_T("In WinHelp RTF mode."), 1);
#endif // wxUSE_STATUSBAR
}

void MyFrame::OnModeHTML(wxCommandEvent& WXUNUSED(event))
{
    convertMode = TEX_HTML;
    winHelp = false;
    InputFile = wxEmptyString;
    OutputFile = wxEmptyString;
#if wxUSE_STATUSBAR
    SetStatusText(_T("In HTML mode."), 1);
#endif // wxUSE_STATUSBAR
}

void MyFrame::OnModeXLP(wxCommandEvent& WXUNUSED(event))
{
    convertMode = TEX_XLP;
    InputFile = wxEmptyString;
    OutputFile = wxEmptyString;
#if wxUSE_STATUSBAR
    SetStatusText(_T("In XLP mode."), 1);
#endif // wxUSE_STATUSBAR
}

void MyFrame::OnOptionsCurlyBrace(wxCommandEvent& WXUNUSED(event))
{
    checkCurlyBraces = !checkCurlyBraces;
#if wxUSE_STATUSBAR
    if (checkCurlyBraces)
    {
        SetStatusText(_T("Checking curly braces: YES"), 1);
    }
    else
    {
        SetStatusText(_T("Checking curly braces: NO"), 1);
    }
#endif // wxUSE_STATUSBAR
}


void MyFrame::OnOptionsSyntaxChecking(wxCommandEvent& WXUNUSED(event))
{
    checkSyntax = !checkSyntax;
#if wxUSE_STATUSBAR
    if (checkSyntax)
    {
        SetStatusText(_T("Checking syntax: YES"), 1);
    }
    else
    {
        SetStatusText(_T("Checking syntax: NO"), 1);
    }
#endif // wxUSE_STATUSBAR
}


void MyFrame::OnHelp(wxCommandEvent& WXUNUSED(event))
{
#if wxUSE_HELP
      HelpInstance->LoadFile();
      HelpInstance->DisplayContents();
#endif // wxUSE_HELP
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
      wxChar buf[300];
      wxString platform = wxGetOsDescription();
      wxSnprintf(buf, sizeof(buf), _T("Tex2RTF Version %.2f %s\nLaTeX to RTF, WinHelp, and HTML Conversion\n\n(c) Julian Smart, George Tasker and others, 1999-2005"), versionNo, platform.c_str());
      wxMessageBox(buf, _T("About Tex2RTF"));
}

void ChooseInputFile(bool force)
{
#if wxUSE_FILEDLG
    if (force || InputFile.empty())
    {
        wxString s = wxFileSelector(_T("Choose LaTeX input file"), wxPathOnly(InputFile), wxFileNameFromPath(InputFile), _T("tex"), _T("*.tex"));
        if (!s.empty())
        {
            // Different file, so clear index entries.
            ClearKeyWordTable();
            ResetContentsLevels(0);
            passNumber = 1;
            errorCount = 0;

            InputFile = s;
            wxString str = wxFileNameFromPath(InputFile);
            wxString buf;
            buf.Printf(_T("Tex2RTF [%s]"), str.c_str());
            frame->SetTitle((wxChar *)buf.c_str());
            OutputFile = wxEmptyString;
        }
    }
#else
    wxUnusedVar(force);
#endif // wxUSE_FILEDLG
}

void ChooseOutputFile(bool force)
{
    wxChar extensionBuf[10];
    wxChar wildBuf[10];
    wxStrcpy(wildBuf, _T("*."));
    wxString path;
    if (!OutputFile.empty())
        path = wxPathOnly(OutputFile);
    else if (!InputFile.empty())
        path = wxPathOnly(InputFile);

    switch (convertMode)
    {
        case TEX_RTF:
        {
            wxStrcpy(extensionBuf, _T("rtf"));
            wxStrcat(wildBuf, _T("rtf"));
            break;
        }
        case TEX_XLP:
        {
            wxStrcpy(extensionBuf, _T("xlp"));
            wxStrcat(wildBuf, _T("xlp"));
            break;
        }
        case TEX_HTML:
        {
            wxStrcpy(extensionBuf, _T("html"));
            wxStrcat(wildBuf, _T("html"));
            break;
        }
    }
#if wxUSE_FILEDLG
    if (force || OutputFile.empty())
    {
        wxString s = wxFileSelector(_T("Choose output file"), path, wxFileNameFromPath(OutputFile),
                                    extensionBuf, wildBuf);
        if (!s.empty())
            OutputFile = s;
    }
#else
    wxUnusedVar(force);
#endif // wxUSE_FILEDLG
}
#endif

bool Go(void)
{
#ifndef NO_GUI
  ChooseInputFile();
  ChooseOutputFile();
#endif

  if (InputFile.empty() || OutputFile.empty() || stopRunning)
    return false;

#ifndef NO_GUI
  if (isInteractive)
  {
    wxChar buf[300];
    wxString str = wxFileNameFromPath(InputFile);

    wxSnprintf(buf, sizeof(buf), _T("Tex2RTF [%s]"), (const wxChar*) str);
    frame->SetTitle(buf);
  }

  wxLongLong localTime = wxGetLocalTimeMillis();
#endif

  // Find extension-less filename
  wxStrcpy(FileRoot, OutputFile.c_str());
  StripExtension(FileRoot);

  if (truncateFilenames && convertMode == TEX_HTML)
  {
    // Truncate to five characters. This ensures that
    // we can generate DOS filenames such as thing999. But 1000 files
    // may not be enough, of course...
    wxChar* sName = wxFileNameFromPath( FileRoot);  // this Julian's method is non-destructive reference

    if(sName)
      if(wxStrlen( sName) > 5)
        sName[5] = '\0';  // that should do!
  }

  wxSnprintf(ContentsName, 300, _T("%s.con"), FileRoot);
  wxSnprintf(TmpContentsName, 300, _T("%s.cn1"), FileRoot);
  wxSnprintf(TmpFrameContentsName, 300, _T("%s.frc"), FileRoot);
  wxSnprintf(WinHelpContentsFileName, 300, _T("%s.cnt"), FileRoot);
  wxSnprintf(RefFileName, 300, _T("%s.ref"), FileRoot);

  TexPathList.EnsureFileAccessible(InputFile);
  if (!bulletFile)
  {
    wxString s = TexPathList.FindValidPath(_T("bullet.bmp"));
    if (!s.empty())
    {
      wxString str = wxFileNameFromPath(s);
      bulletFile = copystring(str);
    }
  }

  if (wxFileExists(RefFileName))
    ReadTexReferences(RefFileName);

  bool success = false;

  if (!InputFile.empty() && !OutputFile.empty())
  {
    if (!wxFileExists(InputFile))
    {
      OnError(_T("Cannot open input file!"));
      TexCleanUp();
      return false;
    }
#if !defined(NO_GUI) && wxUSE_STATUSBAR
    if (isInteractive)
    {
      wxString buf;
      buf.Printf(_T("Working, pass %d...Click CLOSE to abort"), passNumber);
      frame->SetStatusText((wxChar *)buf.c_str());
    }
#endif
    OkToClose = false;
    OnInform(_T("Reading LaTeX file..."));
    TexLoadFile(InputFile);

    if (stopRunning)
    {
        OkToClose = true;
        return false;
    }

    switch (convertMode)
    {
      case TEX_RTF:
      {
        success = RTFGo();
        break;
      }
      case TEX_XLP:
      {
        success = XLPGo();
        break;
      }
      case TEX_HTML:
      {
        success = HTMLGo();
        break;
      }
    }
  }
  if (stopRunning)
  {
    OnInform(_T("*** Aborted by user."));
    success = false;
    stopRunning = false;
    OkToClose = true;
  }

  if (success)
  {
    WriteTexReferences(RefFileName);
    TexCleanUp();
    startedSections = false;

    wxString buf;
#ifndef NO_GUI
    wxLongLong elapsed = wxGetLocalTimeMillis() - localTime;
    buf.Printf(_T("Finished PASS #%d in %ld seconds.\n"), passNumber, (long)(elapsed.GetLo()/1000.0));
    OnInform((wxChar *)buf.c_str());

    if (errorCount)
    {
        buf.Printf(_T("Errors encountered during this pass: %lu\n"), errorCount);
        OnInform((wxChar *)buf.c_str());
    }

#if wxUSE_STATUSBAR
    if (isInteractive)
    {
      buf.Printf(_T("Done, %d %s."), passNumber, (passNumber > 1) ? _T("passes") : _T("pass"));
      frame->SetStatusText((wxChar *)buf.c_str());
    }
#endif // wxUSE_STATUSBAR
#else
    buf.Printf(_T("Done, %d %s."), passNumber, (passNumber > 1) ? _T("passes") : _T("pass"));
    OnInform((wxChar *)buf.c_str());
    if (errorCount)
    {
        buf.Printf(_T("Errors encountered during this pass: %lu\n"), errorCount);
        OnInform((wxChar *)buf.c_str());
    }
#endif
    passNumber ++;
    errorCount = 0;
    OkToClose = true;
    return true;
  }

  TexCleanUp();
  startedSections = false;

#if !defined(NO_GUI) && wxUSE_STATUSBAR
  frame->SetStatusText(_T("Aborted by user."));
#endif // GUI

  OnInform(_T("Sorry, unsuccessful."));
  OkToClose = true;
  return false;
}

void OnError(const wxChar *msg)
{
    wxString msg_string = msg;
    errorCount++;

#ifdef NO_GUI
    wxSTD cerr << "Error: " << msg_string.mb_str() << "\n";
    wxSTD cerr.flush();
#else
    if (isInteractive && frame)
    {
        (*frame->textWindow) << _T("Error: ") << msg << _T("\n");
    }
    else
    {
#if defined(__UNIX__)
        wxSTD cerr << "Error: " << msg_string.mb_str() << "\n";
        wxSTD cerr.flush();
#elif defined(__WXMSW__)
        wxLogError(msg);
#endif
    }

    Tex2RTFYield(true);
#endif // NO_GUI
}

void OnInform(const wxChar *msg)
{
    wxString msg_string = msg;
#ifdef NO_GUI
    wxSTD cout << msg_string.mb_str() << "\n";
    wxSTD cout.flush();
#else
    if (isInteractive && frame)
    {
       (*frame->textWindow) << msg << _T("\n");
    }
    else
    {
#if defined(__UNIX__)
        wxSTD cout << msg_string.mb_str() << "\n";
        wxSTD cout.flush();
#elif defined(__WXMSW__)
        wxLogInfo(msg);
#endif
    }

    if (isInteractive)
    {
        Tex2RTFYield(true);
    }
#endif // NO_GUI
}

void OnMacro(int macroId, int no_args, bool start)
{
  switch (convertMode)
  {
    case TEX_RTF:
    {
      RTFOnMacro(macroId, no_args, start);
      break;
    }
    case TEX_XLP:
    {
      XLPOnMacro(macroId, no_args, start);
      break;
    }
    case TEX_HTML:
    {
      HTMLOnMacro(macroId, no_args, start);
      break;
    }
  }
}

bool OnArgument(int macroId, int arg_no, bool start)
{
  switch (convertMode)
  {
    case TEX_RTF:
    {
      return RTFOnArgument(macroId, arg_no, start);
      // break;
    }
    case TEX_XLP:
    {
      return XLPOnArgument(macroId, arg_no, start);
      // break;
    }
    case TEX_HTML:
    {
      return HTMLOnArgument(macroId, arg_no, start);
      // break;
    }
  }
  return true;
}

/*
 * DDE Stuff
 */
#if defined(__WXMSW__) && !defined(NO_GUI)

/*
 * Server
 */

wxConnectionBase *Tex2RTFServer::OnAcceptConnection(const wxString& topic)
{
  if (topic == _T("TEX2RTF"))
  {
    if (!ipc_buffer)
      ipc_buffer = new wxChar[1000];

    return new Tex2RTFConnection(ipc_buffer, 4000);
  }
  else
    return NULL;
}

 /*
  * Connection
  */

Tex2RTFConnection::Tex2RTFConnection(wxChar *buf, int size):wxDDEConnection(buf, size)
{
}

bool SplitCommand(wxChar *data, wxChar *firstArg, wxChar *secondArg)
{
  firstArg[0] = 0;
  secondArg[0] = 0;
  int i = 0;
  bool stop = false;
  // Find first argument (command name)
  while (!stop)
  {
    if (data[i] == ' ' || data[i] == 0)
      stop = true;
    else
    {
      firstArg[i] = data[i];
      i ++;
    }
  }
  firstArg[i] = 0;
  if (data[i] == ' ')
  {
    // Find second argument
    i ++;
    int j = 0;
    while (data[i] != 0)
    {
      secondArg[j] = data[i];
      i ++;
      j ++;
    }
    secondArg[j] = 0;
  }
  return true;
}

bool Tex2RTFConnection::OnExecute(const wxString& WXUNUSED(topic), wxChar *data, int WXUNUSED(size), wxIPCFormat WXUNUSED(format))
{
  wxStrcpy(Tex2RTFLastStatus, _T("OK"));

  wxChar firstArg[50];
  wxChar secondArg[300];
  if (SplitCommand(data, firstArg, secondArg))
  {
    bool hasArg = (wxStrlen(secondArg) > 0);
    if (wxStrcmp(firstArg, _T("INPUT")) == 0 && hasArg)
    {
        InputFile = secondArg;
        if (frame)
        {
            wxChar buf[100];
            wxString str = wxFileNameFromPath(InputFile);
            wxSnprintf(buf, sizeof(buf), _T("Tex2RTF [%s]"), (const wxChar*) str);
            frame->SetTitle(buf);
        }
    }
    else if (wxStrcmp(firstArg, _T("OUTPUT")) == 0 && hasArg)
    {
        OutputFile = secondArg;
    }
    else if (wxStrcmp(firstArg, _T("GO")) == 0)
    {
      wxStrcpy(Tex2RTFLastStatus, _T("WORKING"));
      if (!Go())
        wxStrcpy(Tex2RTFLastStatus, _T("CONVERSION ERROR"));
      else
        wxStrcpy(Tex2RTFLastStatus, _T("OK"));
    }
    else if (wxStrcmp(firstArg, _T("EXIT")) == 0)
    {
      if (frame) frame->Close();
    }
    else if (wxStrcmp(firstArg, _T("MINIMIZE")) == 0 || wxStrcmp(firstArg, _T("ICONIZE")) == 0)
    {
      if (frame)
        frame->Iconize(true);
    }
    else if (wxStrcmp(firstArg, _T("SHOW")) == 0 || wxStrcmp(firstArg, _T("RESTORE")) == 0)
    {
      if (frame)
      {
        frame->Iconize(false);
        frame->Show(true);
      }
    }
    else
    {
      // Try for a setting
      wxStrcpy(Tex2RTFLastStatus, RegisterSetting(firstArg, secondArg, false));
#if !defined(NO_GUI) && wxUSE_STATUSBAR
      if (frame && wxStrcmp(firstArg, _T("conversionMode")) == 0)
      {
        wxChar buf[100];
        wxStrcpy(buf, _T("In "));

        if (winHelp && (convertMode == TEX_RTF))
          wxStrcat(buf, _T("WinHelp RTF"));
        else if (!winHelp && (convertMode == TEX_RTF))
          wxStrcat(buf, _T("linear RTF"));
        else if (convertMode == TEX_HTML) wxStrcat(buf, _T("HTML"));
        else if (convertMode == TEX_XLP) wxStrcat(buf, _T("XLP"));
          wxStrcat(buf, _T(" mode."));
        frame->SetStatusText(buf, 1);
      }
#endif
    }
  }
  return true;
}

wxChar *Tex2RTFConnection::OnRequest(const wxString& WXUNUSED(topic), const wxString& WXUNUSED(item), int *WXUNUSED(size), wxIPCFormat WXUNUSED(format))
{
  return Tex2RTFLastStatus;
}

#endif

#ifndef NO_GUI
#ifndef __WXGTK__
//void wxObject::Dump(wxSTD ostream& str)
//{
//  if (GetClassInfo() && GetClassInfo()->GetClassName())
//    str << GetClassInfo()->GetClassName();
//  else
//    str << "unknown object class";
//}
#endif
#endif
