/*
 Program WinCaml: Graphical User Interface
 for interactive use of Caml-Light and Ocaml.
 Copyright (C) 2005-2015 Jean Mouric 35700 Rennes France
 email: jean.mouric@orange.fr
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

// File CFrame.cpp

#include "CChildFrame.h"
#include "CFrame.h"
#include "CHighlighter.h"
#include "CInput.h"
#include "COutput.h"
#include "CUndoManager.h"
#include <sstream>
#include <fstream>

void camllightHelp();
bool createDirectory(const wstring& path);
void deleteFile(const wstring& fileName);
wstring extension(const wstring& fileName);
wstring fromBytes(const string& str);
bool getConfigFolderPath(wstring& path);
void insertFileMenuItem(int menuID, const wstring& menuTitle);
void insertFileMenuSeparator();
void ocamlHelp();
void removeFileMenuItem(int menuID);
void removeFileMenuSeparator();
void resetOCamlPath();
string toBytes(const wstring& wstr);

//----------------------------------------------------------------------------------------------------------------
bool gIndentWithTabs = false;
bool gIndentAfterIn = true;
bool gIndentFilters = false;
bool gUseOCamlIndenter = false;
int gSpaceNumberPerTab = 3;

bool gCascade = true;
bool gVerticalBar = true;

int gxOrigin = 50;
int gyOrigin = 50;
int gxDim = 800;
int gxSplit = 400;
int gyDim = 600;
int gySplit = 300;

wstring gInputFontName = MONOSPACE;
wstring gOutputFontName = MONOSPACE;
int gInputFontSize = 10;
bool gInputFontBold = false;
bool gInputFontItalic = false;
int gOutputFontSize = 10;
bool gOutputFontBold = false;
bool gOutputFontItalic = false;

bool gWrapInput = false;
bool gWrapOutput = false;

int gSplitterViewMode = VIEW_BOTH;

bool gSyntaxColoring = true;

bool gToolbarVisible = true;
bool gStatusBarVisible = true;

int gOutputMode = OUTPUT_MEDIUM;

unsigned long gCommentColor = rgb(127, 127, 127);
unsigned long gDelimiterColor = rgb(255, 0, 0);
unsigned long gKeywordColor = rgb(127, 0, 127);
unsigned long gNumberColor = rgb(0, 0, 255);
unsigned long gOperatorColor = rgb(35, 110, 35);
unsigned long gStringColor = rgb(150, 100, 50);
unsigned long gInputCommandBackground = rgb(190, 255, 210);
unsigned long gOutputCommandForeground = rgb(0, 0, 255);
unsigned long gInputBufferBackground = rgb(250, 250, 230);
unsigned long gOtherColor = rgb(0, 0, 0);

int gPreferredEncoding = ENCODING_UNIX;
bool gAutomaticEncoding = true;

int gCamlTop = CAMLLIGHT;
bool gStartNow = true;

#ifndef __WXMAC__
bool gMaximized = true;
#else
bool gMaximized = false;
#endif

int gLeftMargin = 10;
int gRightMargin = 10;
int gTopMargin = 10;
int gBottomMargin = 10;

CFont* gFont1 = NULL;
CFont* gFont2 = NULL;

void loadCursors();
void unloadCursors();

//----------------------------------------------------------------------------------------------------------------
CFrame::CFrame()
{
	closing = false;
	restoreDefaults = false;
	font1 = font2 = NULL;
	loadCursors();
	setConfig();
	updateMenus();
	newFileCount = 1;
	moveWindow(frameLeft, frameTop, frameWidth, frameHeight);
	updateFrame();
}
CFrame::~CFrame()
{
	delete font1;
	delete font2;
	if (gFont1 != font1) delete gFont1;
	if (gFont2 != font2) delete gFont2;
	gFont1 = font1 = NULL;
	gFont2 = font2 = NULL;
	unloadCursors();
}
void CFrame::setDefaultSettings()
{
	frameWidth = gxDim;
	frameHeight = gyDim;
    
	IndentWithTabs = gIndentWithTabs;
	IndentAfterIn = gIndentAfterIn;
	IndentFilters = gIndentFilters;
	UseOCamlIndenter = gUseOCamlIndenter;
	SpaceCountPerTab = gSpaceNumberPerTab;
    
	cascade = gCascade;
	VerticalBar = gVerticalBar;
    
	frameLeft = gxOrigin;
	frameTop = gyOrigin;
	xSplit = gxSplit;
	xDim = gxDim;
	ySplit = gySplit;
	yDim = gyDim;
    
	InputFontSize = gInputFontSize;
	InputFontBold = gInputFontBold;
	InputFontItalic = gInputFontItalic;
	OutputFontSize = gOutputFontSize;
	OutputFontBold = gInputFontBold;
	OutputFontItalic = gInputFontItalic;
	InputFontName = gInputFontName;
	OutputFontName = gOutputFontName;
    
	WrapInput = gWrapInput;
	WrapOutput = gWrapOutput;
    
	SplitterViewMode = gSplitterViewMode;
    
	SyntaxColoring = gSyntaxColoring;
    
	ToolbarVisible = gToolbarVisible;
	StatusBarVisible = gStatusBarVisible;
    
	OutputMode = gOutputMode;
    
	CommentColor = gCommentColor;
	DelimiterColor = gDelimiterColor;
	KeywordColor = gKeywordColor;
	NumberColor = gNumberColor;
	OperatorColor = gOperatorColor;
	StringColor = gStringColor;
	InputCommandBackground = gInputCommandBackground;
	OutputCommandForeground = gOutputCommandForeground;
	InputBufferBackground = gInputBufferBackground;
	OtherColor = gOtherColor;
    
	PreferredEncoding = gPreferredEncoding;
	AutomaticEncoding = gAutomaticEncoding;
    
	CamlTop = gCamlTop;
	StartNow = gStartNow;
    
	Maximized = gMaximized;
    
	LeftMargin = gLeftMargin;
	RightMargin = gRightMargin;
	TopMargin = gTopMargin;
	BottomMargin = gBottomMargin;
    
	StatusBarVisible = gStatusBarVisible;
	ToolbarVisible = gToolbarVisible;
    
	if (!gFont1) gFont1 = new CFont(gInputFontName, gInputFontSize);
	if (!gFont2) gFont2 = new CFont(gOutputFontName, gOutputFontSize);
    
	font1 = gFont1;
	font2 = gFont2;
}
void CFrame::setConfig()
{
	setDefaultSettings();
	wstring path;
	if (!getConfigFolderPath(path)) return;
	path += appName +  version + L".txt";
    
	fstream fs(toBytes(path).c_str());
    
	if (!fs.fail())
	{
		fs >> IndentWithTabs;
		fs >> IndentAfterIn;
		fs >> IndentFilters;
		fs >> UseOCamlIndenter;
		fs >> SpaceCountPerTab;
        
		// layout
		fs >> frameLeft;
		fs >> frameTop;
		fs >> frameWidth;
		fs >> frameHeight;
        
		fs >> cascade;
        
		fs >> VerticalBar;
		fs >> xSplit;
		fs >> xDim;
		fs >> ySplit;
		fs >> yDim;
        
		// fonts
		fs >> InputFontSize;
		fs >> InputFontBold;
		fs >> InputFontItalic;
		fs >> OutputFontSize;
		fs >> OutputFontBold;
		fs >> OutputFontItalic;
		fs.get();
		char buffer[256];
		fs.getline(buffer, 256);
		InputFontName = fromBytes(buffer);
		fs.getline(buffer, 256);
		OutputFontName = fromBytes(buffer);
		font1 = new CFont(InputFontName, InputFontSize, InputFontBold, InputFontItalic);
		font2 = new CFont(OutputFontName, OutputFontSize, OutputFontBold, OutputFontItalic);
        
		// wrapping
		fs >> WrapInput;
		fs >> WrapOutput;
        
		// pane visibility
		fs >> SplitterViewMode;
        
		// output mode
		fs >> OutputMode;
        
		// colors
		fs >> SyntaxColoring;
		fs >> CommentColor;
		fs >> DelimiterColor;
		fs >> KeywordColor;
		fs >> NumberColor;
		fs >> OperatorColor;
		fs >> StringColor;
		fs >> InputCommandBackground;
		fs >> OutputCommandForeground;
		fs >> InputBufferBackground;
		fs >> OtherColor;
        
		// encoding
		fs >> PreferredEncoding;
		fs >> AutomaticEncoding;
        
		// toplevel
		fs >> CamlTop;
		fs >> StartNow;
        
		// frame
		fs >> ToolbarVisible;
		fs >> StatusBarVisible;
        
		// child windows
		fs >> Maximized;
        
		// printer margins
		fs >> LeftMargin;
		fs >> RightMargin;
		fs >> TopMargin;
		fs >> BottomMargin;
        
		// recent files
		int n;
		fs >> n;
		fs.get();
		for (int i = 0; i < n && i < 8; i++)
		{
			string s;
			char c;
			while (fs.get(c) && c != L'\r' && c != L'\n')
				s += c;
			recentFiles.push_back(fromBytes(s));
		}
		fs.close();
	}
	updateRecentFilesMenus();
}
void CFrame::setConfig(CChildFrame * childFrame)
{
	IndentWithTabs = childFrame->IndentWithTabs;
	IndentAfterIn = childFrame->IndentAfterIn;
	IndentFilters = childFrame->IndentFilters;
	UseOCamlIndenter = childFrame->UseOCamlIndenter;
	SpaceCountPerTab = childFrame->SpaceCountPerTab;
    
	VerticalBar = childFrame->VerticalBar;
	xSplit = childFrame->xSplit;
	xDim = childFrame->xDim;
	ySplit = childFrame->ySplit;
	yDim = childFrame->yDim;
    
	InputFontSize = childFrame->InputFontSize;
	OutputFontSize = childFrame->OutputFontSize;
	InputFontName = childFrame->InputFontName;
	OutputFontName = childFrame->OutputFontName;
    
	WrapInput = childFrame->WrapInput;
	WrapOutput = childFrame->WrapOutput;
    
	SyntaxColoring = childFrame->SyntaxColoring;
    
	OutputMode = childFrame->OutputMode;
    
	CommentColor = childFrame->CommentColor;
	DelimiterColor = childFrame->DelimiterColor;
	KeywordColor = childFrame->KeywordColor;
	NumberColor = childFrame->NumberColor;
	OperatorColor = childFrame->OperatorColor;
	StringColor = childFrame->StringColor;
	InputCommandBackground = childFrame->InputCommandBackground;
	OutputCommandForeground = childFrame->OutputCommandForeground;
	InputBufferBackground = childFrame->InputBufferBackground;
	OtherColor = childFrame->OtherColor;
    
	PreferredEncoding = childFrame->PreferredEncoding;
	AutomaticEncoding = childFrame->AutomaticEncoding;
    
	StartNow = childFrame->StartNow;
    
	Maximized = childFrame->isMaximized();
    
	font1 = childFrame->font1;
	font2 = childFrame->font2;
}
void CFrame::saveConfig()
{
	wstring path;
	if (!getConfigFolderPath(path)) return;
	if (createDirectory(path))
	{
		path += appName +  version + L".txt";
		fstream fs(toBytes(path).c_str(), fstream::out);
        
		fs << IndentWithTabs << endl;
		fs << IndentAfterIn << endl;
		fs << IndentFilters << endl;
		fs << UseOCamlIndenter << endl;
		fs << SpaceCountPerTab << endl;
        
		// layout
		fs << frameLeft << endl;
		fs << frameTop << endl;
		fs << frameWidth << endl;
		fs << frameHeight << endl;
        
		fs << cascade << endl;
        
		fs << VerticalBar << endl;
		fs << xSplit << endl;
		fs << xDim << endl;
		fs << ySplit << endl;
		fs << yDim << endl;
        
		// fonts
		fs << InputFontSize << endl;
		fs << InputFontBold << endl;
		fs << InputFontItalic << endl;
		fs << OutputFontSize << endl;
		fs << OutputFontBold << endl;
		fs << OutputFontItalic << endl;		
		
		fs << toBytes(InputFontName) << endl;
		fs << toBytes(OutputFontName) << endl;
        
		// wrapping
		fs << WrapInput << endl;
		fs << WrapOutput << endl;
        
		// pane visibility
		fs << SplitterViewMode << endl;
        
		// output mode
		fs << OutputMode << endl;
        
		// colors
		fs << SyntaxColoring << endl;
		fs << CommentColor << endl;
		fs << DelimiterColor << endl;
		fs << KeywordColor << endl;
		fs << NumberColor << endl;
		fs << OperatorColor << endl;
		fs << StringColor << endl;
		fs << InputCommandBackground << endl;
		fs << OutputCommandForeground << endl;
		fs << InputBufferBackground << endl;
		fs << OtherColor << endl;
        
		// encoding
		fs << PreferredEncoding << endl;
		fs << AutomaticEncoding << endl;
        
		// toplevel
		fs << CamlTop << endl;
		fs << StartNow << endl;
        
		// frame
		fs << ToolbarVisible << endl;
		fs << StatusBarVisible << endl;
        
		// child windows
		fs << Maximized << endl;
        
		// printer margins
		fs << LeftMargin << endl;
		fs << RightMargin << endl;
		fs << TopMargin << endl;
		fs << BottomMargin << endl;
        
		// recent files
		fs << recentFiles.size() << endl;
		int sz = (int)recentFiles.size();
        
		for (int i = 0; i < sz; i++)
		{
			fs << toBytes(recentFiles.at(i)) << endl;
		}
        
		fs.close();
	}
}
void CFrame::onCommand(int cmd)
{
	switch(cmd)
	{
        case FILE_NEW:
            onFileNew();
            break;
        case FILE_OPEN1:
            onFileOpen();
            break;
        case FILE_CLOSE:
            onFileClose();
            break;
        case FILE_PRINTSETUP:
            printSetUpDialog(LeftMargin, TopMargin, RightMargin, BottomMargin);
            break;
        case FILE_MRU1: case FILE_MRU2: case FILE_MRU3: case FILE_MRU4: case FILE_MRU5: case FILE_MRU6: case FILE_MRU7: case FILE_MRU8:
            openFile(recentFiles.at(cmd - FILE_MRU1));
            break;
        case FILE_EXIT:
            onFileExit();
            break;
        case EDIT_INDENTMODE:
            IndentWithTabs = !IndentWithTabs;
            checkMenuItem(EDIT_INDENTMODE, IndentWithTabs);
            break;
        case EDIT_TABWIDTH:
            tabDialog(SpaceCountPerTab);
            break;
        case EDIT_INDENTAFTERIN:
            IndentAfterIn = !IndentAfterIn;
            checkMenuItem(EDIT_INDENTAFTERIN, IndentAfterIn);
            break;
        case EDIT_INDENTFILTER:
            IndentFilters = !IndentFilters;
            checkMenuItem(EDIT_INDENTFILTER, IndentFilters);
            break;
        case EDIT_INDENTOCAML:
            UseOCamlIndenter = !UseOCamlIndenter;
            checkMenuItem(EDIT_INDENTOCAML, UseOCamlIndenter);
            break;
        case VIEW_SPLIT:
            VerticalBar = !VerticalBar;
            updateSplitViewMenu();
            break;
        case VIEW_INPUTONLY: case VIEW_OUTPUTONLY: case VIEW_BOTH:
            SplitterViewMode = cmd;
            checkMenuItem(VIEW_INPUTONLY, cmd == VIEW_INPUTONLY);
            checkMenuItem(VIEW_OUTPUTONLY, cmd == VIEW_OUTPUTONLY);
            checkMenuItem(VIEW_BOTH, cmd == VIEW_BOTH);
            break;
        case VIEW_INPUTFONT:
            fontDialog(font1, true);
            break;
        case VIEW_OUTPUTFONT:
            fontDialog(font2, false);
            break;
        case VIEW_WRAPINPUT:
            WrapInput = !WrapInput;
            checkMenuItem(VIEW_WRAPINPUT, WrapInput);
            break;
        case VIEW_WRAPOUTPUT:
            WrapOutput = !WrapOutput;
            checkMenuItem(VIEW_WRAPOUTPUT, WrapOutput);
            break;
        case VIEW_SYNTAXCOLOR:
            SyntaxColoring = !SyntaxColoring;
            checkMenuItem(VIEW_SYNTAXCOLOR, SyntaxColoring);
            break;
        case VIEW_TOOLBAR:
            ToolbarVisible = !ToolbarVisible;
            checkMenuItem(VIEW_TOOLBAR, ToolbarVisible);
            updateFrame();
            break;
        case VIEW_STATUSBAR:
            StatusBarVisible = !StatusBarVisible;
            checkMenuItem(VIEW_STATUSBAR, StatusBarVisible);
            updateFrame();
            break;
        case COLOR_BUFFERBACKGROUND:
            colorDialog(InputBufferBackground);
            break;
        case COLOR_COMMANDBACKGROUND:
            colorDialog(InputCommandBackground);
            break;
        case COLOR_OUTPUT:
            colorDialog(OutputCommandForeground);
            break;
        case COLOR_NUMBER:
            colorDialog(NumberColor);
            break;
        case COLOR_KEYWORD:
            colorDialog(KeywordColor);
            break;
        case COLOR_DELIMITER:
            colorDialog(DelimiterColor);
            break;
        case COLOR_OPERATOR:
            colorDialog(OperatorColor);
            break;
        case COLOR_STRING:
            colorDialog(StringColor);
            break;
        case COLOR_COMMENT:
            colorDialog(CommentColor);
            break;
        case WINDOW_CASCADE:
            onCascadeWindow();
            break;
        case WINDOW_TILE:
            onTileWindow();
            break;
        case ENCODING_UNIX: case ENCODING_MAC: case ENCODING_WIN: case ENCODING_UTF8:
            PreferredEncoding = cmd;
            checkMenuItem(ENCODING_UNIX, cmd == ENCODING_UNIX);
            checkMenuItem(ENCODING_MAC, cmd == ENCODING_MAC);
            checkMenuItem(ENCODING_WIN, cmd == ENCODING_WIN);
            checkMenuItem(ENCODING_UTF8, cmd == ENCODING_UTF8);
            break;
        case ENCODING_AUTO:
            AutomaticEncoding = !AutomaticEncoding;
            enableMenuItem(ENCODING_UNIX, !AutomaticEncoding);
            enableMenuItem(ENCODING_MAC, !AutomaticEncoding);
            enableMenuItem(ENCODING_WIN, !AutomaticEncoding);
            enableMenuItem(ENCODING_UTF8, !AutomaticEncoding);
            checkMenuItem(ENCODING_AUTO, AutomaticEncoding);
            break;
        case CAMLTOP_CAMLLIGHT:
		{
            CamlTop = CAMLLIGHT;
            checkMenuItem(CAMLTOP_CAMLLIGHT, true);
            checkMenuItem(CAMLTOP_OCAML, false);
		}
            break;
        case CAMLTOP_OCAML:
        {
            CamlTop = OCAML;
            checkMenuItem(CAMLTOP_CAMLLIGHT, false);
            checkMenuItem(CAMLTOP_OCAML, true);
        }
            break;
        case CAMLTOP_START:
            StartNow = !StartNow;
            checkMenuItem(CAMLTOP_START, !StartNow);
            break;
        case OUTPUT_SHORT: 	case OUTPUT_MEDIUM: case OUTPUT_LONG:
            updateOutputMenu(cmd);
            break;
        case HELP_CAMLLIGHT:
            camllightHelp();
            break;
        case HELP_OCAML:
            ocamlHelp();
            break;
        case HELP_DEFAULTCONFIG:
#ifdef _MSVC98_
            if (yesnoMessage(L"R\xE9tablir les r\xE9glages d'origine ?"))
#else
                if (yesnoMessage(L"R\u00E9tablir les r\u00E9glages d'origine ?"))
#endif
                {
                    setDefaultSettings();
                    resetOCamlPath();
                    moveWindow(frameLeft, frameTop, frameWidth, frameHeight);
                    updateMenus();
                    restoreDefaults = true;
                }
            break;
        case HELP_ABOUT:
            aboutMessage(appName + L" " + version1 + L", interface graphique interactive pour Caml-Light et OCaml\nCopyright (C) 2005 - 2015 Jean Mouric 35700 Rennes France");
            break;
        default:
            break;
	}
}
void CFrame::onDrop()
{
	size_t sz = droppedFiles->size();
	for (size_t i = 0; i < sz; i++)
	{
		openFile(*(droppedFiles->at(i)));
	}
	droppedFiles->clear();
}
void CFrame::openFiles(deque<wstring>& files)
{
	deque<wstring>::iterator it = files.begin();
	while (it != files.end())
	{
		if (*it == L"init")
		{
			onCommand(HELP_DEFAULTCONFIG);
			if (restoreDefaults)
			{
				if (mdiChildren.size() > 0)
					((CChildFrame*)mdiChildren.at(0))->restore();
				wstring path;
				getConfigFolderPath(path);
				path += appName +  version + L".txt";
				deleteFile(path.c_str());
			}
			return;
		}
		openFile(*it);
		it++;
	}
}
void CFrame::onFileNew()
{
	bool maxi = mdiChildren.size() > 0 ? mdiChildren.at(0)->isMaximized() : Maximized;
	CChildFrame* mdiChildFrame = new CChildFrame(this, maxi);
	mdiChildFrame->newFile();
	mdiChildren.push_front(mdiChildFrame);
}
void CFrame::onFileOpen()
{
	wstring fileName;
	if (openFileDialog(fileName))
	{
		openFile(fileName);
	}
}
void CFrame::openFile(const wstring& fileName)
{
	wstring ext = extension(fileName);
	if (ext != L"ML" && ext != L"OML" && ext != L"MLI") return;
	size_t i = 0;
	while (i < mdiChildren.size())
	{
		if (mdiChildren.at(i)->title == fileName) break;
		i++;
	}
	if (i < mdiChildren.size())
	{
		setActiveChild(mdiChildren.at(i));
		updateRecentFiles(fileName, false);
	}
	else
	{
		bool maxi = mdiChildren.size() > 0 ? mdiChildren.at(0)->isMaximized() : Maximized;
		CChildFrame* mdiChildFrame = new CChildFrame(this, maxi);
        mdiChildren.push_front(mdiChildFrame);
		if (mdiChildFrame->openFile(fileName))
		{
#ifdef _MSVC98_
			setStatus(1, fileName + L"  (enregistr\xE9)");
#else
			setStatus(1, fileName + L"  (enregistr\u00E9)");
#endif
			updateRecentFiles(fileName, false);
		}
		else
		{
			mdiChildFrame->newFile();
			errorMessage(L"Impossible d'ouvrir le fichier!");
			updateRecentFiles(fileName, true);
		}
	}
}
void CFrame::onClose()
{
    CMDIFrame::onClose();
	closing = true;
	for (size_t i = 0; i < mdiChildren.size(); i++)
	{
		CChildFrame* child = (CChildFrame*)mdiChildren.at(i);
		child->cInput->undoManager->stop();
		child->hide();
	}
}
bool CFrame::reviewChanges()
{
	saveConfig();
	for (size_t i = 0; i < mdiChildren.size(); i++)
	{
		if (((CChildFrame*)mdiChildren.at(i))->reviewChange()) return true;
	}
	return false;
}
void CFrame::updateRecentFiles(wstring fileName, bool fileNotFound)
{
	if (fileNotFound)
	{
		size_t sz = recentFiles.size();
		for (size_t i = 0; i < sz; i++)
		{
			wstring ws = recentFiles.at(i);
			if (ws == fileName)
			{
				recentFiles.erase(recentFiles.begin() + i);
				break;
			}
		}
	}
	else
	{
		size_t i;
		bool found = false;
		size_t sz = recentFiles.size();
		for (i = 0; i < sz; i++)
		{
			wstring ws = recentFiles.at(i);
			if (ws == fileName)
			{
				recentFiles.erase(recentFiles.begin() + i);
				found = true;
				break;
			}
		}
		if (!found && sz == 8)
			recentFiles.pop_back();
		recentFiles.push_front(fileName);
	}
	updateRecentFilesMenus();
}
void CFrame::updateRecentFilesMenus()
{
	int n = (int)recentFiles.size();
	if (n > 8) n = 8;
	int i;
	for (i = FILE_MRU1; i <= FILE_MRU8; i++)
	{
		removeFileMenuItem(i);
	}
	removeFileMenuSeparator();
	for (i = 0; i < n; i++)
	{
		wstring ws = recentFiles.at(i);
		insertFileMenuItem(i + FILE_MRU1, ws.substr(ws.find_last_of(L"/\\") + 1));
	}
	if (n > 0) insertFileMenuSeparator();
}
void CFrame::updateSplitViewMenu()
{
	setMenuItemText(VIEW_SPLIT, VerticalBar ? L"Cloison verticale -> horizontale" : L"Cloison: horizontale -> verticale", true);
}
void CFrame::updateOutputMenu(int cmd)
{
	checkMenuItem(OUTPUT_SHORT, OUTPUT_SHORT == cmd);
	enableMenuItem(OUTPUT_SHORT,OUTPUT_SHORT != cmd);
	checkMenuItem(OUTPUT_MEDIUM, OUTPUT_MEDIUM == cmd);
	enableMenuItem(OUTPUT_MEDIUM,OUTPUT_MEDIUM != cmd);
	checkMenuItem(OUTPUT_LONG, OUTPUT_LONG == cmd);
	enableMenuItem(OUTPUT_LONG,OUTPUT_LONG != cmd);
	OutputMode = cmd;
}
void CFrame::updateMenus()
{
	enableMenuItem(FILE_NEW, true);
	enableMenuItem(FILE_INCLUDE, false);
	enableMenuItem(FILE_OPEN1, true);
	enableMenuItem(FILE_CLOSE, false);
	enableMenuItem(FILE_SAVE, false);
	enableMenuItem(FILE_SAVEAS, false);
	enableMenuItem(FILE_SAVEASFORMATTED, false);
	enableMenuItem(FILE_PRINT, false);
	enableMenuItem(FILE_PRINTSETUP, true);
	enableMenuItem(FILE_EXIT, true);
    
	enableMenuItem(EDIT_UNDO, false);
	enableMenuItem(EDIT_REDO, false);
	enableMenuItem(EDIT_CUT, false);
	enableMenuItem(EDIT_COPY, false);
	enableMenuItem(EDIT_PASTE, false);
	enableMenuItem(EDIT_SELECTALL, false);
	enableMenuItem(EDIT_FIND, false);
	enableMenuItem(EDIT_REPLACE, false);
	enableMenuItem(EDIT_INDENTMODE, true);
	checkMenuItem(EDIT_INDENTMODE, IndentWithTabs);
	enableMenuItem(EDIT_TABWIDTH, true);
	enableMenuItem(EDIT_INDENTAFTERIN, true);
	checkMenuItem(EDIT_INDENTAFTERIN, IndentAfterIn);
	enableMenuItem(EDIT_INDENTFILTER, true);
	checkMenuItem(EDIT_INDENTFILTER, IndentFilters);
	enableMenuItem(EDIT_INDENTOCAML, true);
	checkMenuItem(EDIT_INDENTOCAML, UseOCamlIndenter);
	enableMenuItem(EDIT_INDENT, false);
    
	updateSplitViewMenu();
	enableMenuItem(VIEW_INPUTONLY, true);
	checkMenuItem(VIEW_INPUTONLY, SplitterViewMode == VIEW_INPUTONLY);
	enableMenuItem(VIEW_OUTPUTONLY, true);
	checkMenuItem(VIEW_OUTPUTONLY, SplitterViewMode == VIEW_OUTPUTONLY);
	enableMenuItem(VIEW_BOTH, true);
	checkMenuItem(VIEW_BOTH, SplitterViewMode == VIEW_BOTH);
    
	enableMenuItem(VIEW_INPUTFONT, true);
	enableMenuItem(VIEW_OUTPUTFONT, true);
	enableMenuItem(VIEW_WRAPINPUT, true);
	checkMenuItem(VIEW_WRAPINPUT, WrapInput);
	enableMenuItem(VIEW_WRAPOUTPUT, true);
	checkMenuItem(VIEW_WRAPOUTPUT, WrapOutput);
	enableMenuItem(VIEW_SYNTAXCOLOR, true);
	checkMenuItem(VIEW_SYNTAXCOLOR, SyntaxColoring);
	enableMenuItem(VIEW_TOOLBAR, true);
	checkMenuItem(VIEW_TOOLBAR, ToolbarVisible);
	enableMenuItem(VIEW_STATUSBAR, true);
	checkMenuItem(VIEW_STATUSBAR, StatusBarVisible);
	setStatus(0, L"");
	setStatus(1, L"");
    
	enableMenuItem(COLOR_BUFFERBACKGROUND, true);
	enableMenuItem(COLOR_COMMANDBACKGROUND, true);
	enableMenuItem(COLOR_OUTPUT, true);
	enableMenuItem(COLOR_NUMBER, true);
	enableMenuItem(COLOR_KEYWORD, true);
	enableMenuItem(COLOR_DELIMITER, true);
	enableMenuItem(COLOR_OPERATOR, true);
	enableMenuItem(COLOR_STRING, true);
	enableMenuItem(COLOR_COMMENT, true);
    
	enableMenuItem(ENCODING_UNIX, !AutomaticEncoding);
	checkMenuItem(ENCODING_UNIX, PreferredEncoding == ENCODING_UNIX);
	enableMenuItem(ENCODING_MAC, !AutomaticEncoding);
	checkMenuItem(ENCODING_MAC, PreferredEncoding == ENCODING_MAC);
	enableMenuItem(ENCODING_WIN, !PreferredEncoding);
	checkMenuItem(ENCODING_WIN, PreferredEncoding == ENCODING_WIN);
	enableMenuItem(ENCODING_UTF8, !PreferredEncoding);
	checkMenuItem(ENCODING_UTF8, PreferredEncoding == ENCODING_UTF8);
	enableMenuItem(ENCODING_AUTO, true);
	checkMenuItem(ENCODING_AUTO, AutomaticEncoding);
    
	enableMenuItem(CAML_SEND, false);
    enableMenuItem(CAML_SEND_SEL, false);
	enableMenuItem(CAML_INTERRUPT, false);
	enableMenuItem(CAML_STOP, false);
	enableMenuItem(CAML_CLEAROUTPUT, false);
    
    checkMenuItem(CAMLTOP_CAMLLIGHT, CamlTop == CAMLLIGHT);
    checkMenuItem(CAMLTOP_OCAML, CamlTop == OCAML);
	enableMenuItem(CAMLTOP_START, true);
	checkMenuItem(CAMLTOP_START, !StartNow);
    
	updateOutputMenu(OutputMode);
}
void CFrame::clearFont(CFont*& font)
{
	if (!font) return;
	if (font == gFont1 || font == gFont2) return;
	bool found = false;
	size_t sz = mdiChildren.size();
	for (size_t i = 0; i < sz; i++)
	{
		if (font == ((CChildFrame*)mdiChildren.at(i))->font1 || font == ((CChildFrame*)mdiChildren.at(i))->font2)
		{
			found = true;
			break;
		}
	}
	if (!found)
	{
		if (font1 == font) font1 = NULL;
		if (font2 == font) font2 = NULL;
		delete font;
		font = NULL;
	}
}
void CFrame::fontDialog(CFont* font, bool input)
{
	if (!font) return;
	CFont* savedFont = font;
	fontDlg(font);
	if (!font || font == savedFont) return;
	clearFont(savedFont);
	if (input)
	{
		InputFontName = *font->fntName;
		InputFontSize = font->fntSize;
		InputFontBold = font->bold;
		InputFontItalic = font->italic;
		font1 = font;
	}
	else
	{
		OutputFontName = *font->fntName;
		OutputFontSize = font->fntSize;
		OutputFontBold = font->bold;
		OutputFontItalic = font->italic;
		font2 = font;
	}
}
