/*
 Program WinCaml: Graphical User Interface
 for interactive use of Caml-Light and Ocaml.
 Copyright (C) 2005-2017 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 Qt/Paths.cpp

#include "Qt.h"

#ifndef Q_OS_WIN
#include <sys/stat.h>
#include <fstream>

string toBytes(const wstring&);
wstring setOCamlPath();
wstring getOCamlPath();
void ldconf(wstring ocamlPath);
void resetOCamlPath();

bool getConfigFolderPath(wstring& path)
{
    path = (qApp->applicationDirPath() + "/." + QDir(QDir::homePath()).dirName() + "/").toStdWString();
    return true;
}
void ldconf(wstring ocamlPath)
{
	wstring ldconfPath = ocamlPath +  L"/lib/ocaml/ld.conf";
	string toBytes(const wstring& wstr);
	wfstream wfs(toBytes(ldconfPath).c_str(), wfstream::out);
	if (!wfs.fail())
	{
		wfs << (ocamlPath + L"/lib/ocaml/stublibs").c_str() << endl;
		wfs.close();
	}
}
wstring setOCamlPath()
{
    wstring path;
    wstring s;
    if (getConfigFolderPath(s))
    {
        path = QFileDialog::getExistingDirectory(NULL, "Emplacement d'OCaml ?", "", QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly).toStdWString();
        s += L"ocamlbase.txt";
        string toBytes(const wstring& wstr);
        wfstream wfs(toBytes(s).c_str(), wfstream::out);
        if (!wfs.fail())
        {
            wfs << path << endl;
            wfs.close();
        }
    }
    return path;
}
wstring getOCamlPath()
{
    wstring cfp;
    QString ocamlPath;
    if (getConfigFolderPath(cfp))
    {
        cfp += L"ocamlbase.txt";
		string toBytes(const wstring& wstr);
		wfstream wfs(toBytes(cfp).c_str(), wfstream::in);
        if (!wfs.fail())
        {
            wchar_t c;
            while (wfs.get(c) && c != L'\r' && c != L'\n')
                ocamlPath += c;
            
            wfs.close();
        }
    }
    return ocamlPath.toStdWString();
}
void resetOCamlPath()
{
    wstring s;
    if (getConfigFolderPath(s))
    {
        void deleteFile(const wstring& fileName);
        s += L"ocamlbase.txt";
        QFileInfo fi = QString::fromStdWString(s);
        if (fi.exists())
        {
            deleteFile(s);
        }
    }    
}
CProcess* startCaml(bool ocaml)
{
#ifdef Q_OS_MAC
    QDir::setCurrent(qApp->applicationDirPath() + "/../../..");
#endif
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("PATH", env.value("PATH") + ":/usr/local/bin");
    if (ocaml)
    {
        QString ocamlPath = "/usr/local";
        QFileInfo fi1 = QString("/usr/local/bin/ocamlrun");
        QFileInfo fi2 = QString("/usr/local/bin/ocaml");
        if (!fi1.exists() || !fi2.exists() || !fi1.isExecutable())
        {
            ocamlPath = "/usr";
            fi1 = QString("/usr/bin/ocamlrun");
            fi2 = QString("/usr/bin/ocaml");
            if (!fi1.exists() || !fi2.exists() || !fi1.isExecutable())
            {
                QString path = QString::fromStdWString(getOCamlPath());
                QFileInfo fi3 = path + "/bin/ocamlrun";
                QFileInfo fi4 = path + "/bin/ocaml";
                if (!fi3.exists() || !fi4.exists() || !fi3.isExecutable())
                {
                    ocamlPath = QString::fromStdWString(setOCamlPath());
                    QFileInfo fi6 = ocamlPath + "/bin/ocamlrun";
                    QFileInfo fi7 = ocamlPath + "/bin/ocaml";
                    if (!fi6.exists() || !fi7.exists() || !fi6.isExecutable())
                    {
                        return NULL;
                    }
                }
                else
                {
                    ocamlPath = path;
                }
            }
        }
        fstream fs(toBytes(ocamlPath.toStdWString()+ L"/bin/ocamlrun").c_str(), fstream::in | fstream::binary);
        char c[5] = {0};
        fs.seekg (0, fs.end);
        streamoff length = fs.tellg();
        fs.seekg (0, fs.beg);
        for (int i = 0; i < 4 && i < length; i++)
        {
            fs.get(c[i]);
        }
        fs.close();
#ifdef Q_OS_MAC
        uint32_t magic = *(uint32_t*)c;
        if (magic != 0xfeedface && magic != 0xfeedfacf)
#else
        string magic = ((char*)c) + 1;
        if (c[0] != 0x7f  || magic != "ELF")
#endif
        {
            resetOCamlPath();
            return NULL;
        }
        env.insert("OCAMLLIB", ocamlPath + "/lib/ocaml");
        env.insert("PATH", ocamlPath + "/bin");
        ldconf(ocamlPath.toStdWString());
        CProcess* process = new CProcess();
        process->setProcessEnvironment(env);
#ifdef Q_OS_LINUX
        QString graphlib = QSysInfo::WordSize == 64 ? qApp->applicationDirPath() + "/ocaml/linux/ocaml64" : qApp->applicationDirPath() + "/ocaml/linux/ocaml32";
        QStringList args = (QStringList(ocamlPath + "/bin/ocaml") << "-I" << graphlib);
#else
        QString graphlib = QSysInfo::WordSize == 64 ? qApp->applicationDirPath() + "/ocaml/mac/ocaml64" : qApp->applicationDirPath() + "/ocaml/mac/ocaml32";
        QStringList args = (QStringList(ocamlPath + "/bin/ocaml") << "-I" << graphlib);
#endif
        process->start(ocamlPath + "/bin/ocamlrun", args);
        return process;
    }
    else
    {
#ifdef Q_OS_LINUX
        QString toplevel = QSysInfo::WordSize == 64 ? qApp->applicationDirPath() + "/caml-light/bin/lintoplevel64" : qApp->applicationDirPath() + "/caml-light/bin/lintoplevel32";
#else
        QString toplevel = QSysInfo::WordSize == 64 ? qApp->applicationDirPath() + "/caml-light/bin/mactoplevel64" : qApp->applicationDirPath() + "/caml-light/bin/mactoplevel32";
#endif
        QFileInfo fi = toplevel;
        if (! fi.exists())
        {
			errorMessage(L"caml light toplevel absent");
            return NULL;
        }
        if (! fi.isExecutable())
        {
            if (chmod(toBytes(toplevel.toStdWString()).c_str(), S_IRWXU))
            {
				errorMessage(L"caml light toplevel non ex\xE9""cutable");
                return NULL;
            }
        }
        QString locale = QLocale::system().name().mid(0, 2);
        QStringList args = (QStringList() << "-stdlib" << qApp->applicationDirPath() + "/caml-light/lib" << "-lang" << locale);
        CProcess* process = new CProcess();
        process->setProcessEnvironment(env);
        process->start(toplevel, args);
        return process;
    }
}
void camllightHelp()
{
#ifdef Q_OS_MAC
    QStringList args = (QStringList() << "-a" << "safari.app" << qApp->applicationDirPath() + "/caml-light/man-caml/index.html");
    QProcess::startDetached("open", args);
#else
#ifdef Q_OS_LINUX
    QStringList args = (QStringList() << qApp->applicationDirPath() + "/caml-light/man-caml/index.html");
    QProcess::startDetached("/usr/bin/firefox", args);
#endif
#endif
}
void ocamlHelp()
{
#ifdef Q_OS_MAC
    QStringList args = (QStringList() << "-a" << "safari.app" << qApp->applicationDirPath() + "/ocaml/htmlman/index.html");
    QProcess::startDetached("open", args);
#else
#ifdef Q_OS_LINUX
    QStringList args = (QStringList() << qApp->applicationDirPath() + "/ocaml/htmlman/index.html");
    QProcess::startDetached("/usr/bin/firefox", args);
#endif
#endif
}
#endif

#ifdef Q_OS_WIN
#include <Shlobj.h>
#include "Shlwapi.h"
bool getConfigFolderPath(wstring& path)
{
    wchar_t szPath[MAX_PATH];
    if (::SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, szPath) == S_OK)
    {
        path = szPath;
        path += L"\\" + appName + L"\\";
        return true;
    }
    return false;
}
wstring applicationDirectoryPath()
{
    
    wchar_t appPath[MAX_PATH];
    ::GetModuleFileName(0, appPath, sizeof(appPath)-1);
    wstring appDirPath = appPath;
    return appDirPath.substr(0, appDirPath.find_last_of(L"\\"));
}
#ifdef QT4_7
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, BOOL*);
LPFN_ISWOW64PROCESS fnIsWow64Process;
static bool IsWow64()
{
    BOOL bIsWow64 = FALSE;
    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.
    fnIsWow64Process = (LPFN_ISWOW64PROCESS) ::GetProcAddress(::GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
    if(NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(::GetCurrentProcess(),&bIsWow64))
        {
            //handle error
        }
    }
    return bIsWow64 == TRUE;
}
static bool architecture64()
{
    return IsWow64();
}
#else
static bool architecture64()
{
	SYSTEM_INFO sysInfo;
	::GetNativeSystemInfo(&sysInfo);
	return sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
}
#endif
enum{OCAML64_LOCAL, OCAML64, OCAML32_64, OCAML32_64A, OCAML32, OCAML32A, OCAML32B, CAMLLIGHT64, CAMLLIGHT64A, CAMLLIGHT32, CAMLLIGHT32A, OCAMLNOTFOUND};
#include <fstream>
string toBytes(const wstring& wstr);
extern CMDIFrame* mainFrame;
void ldconf(wstring& ocamlPath)
{
    wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
    if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; }
    
    wstring ldconfPath = ocamlLibPath +  L"\\ld.conf";
    
#if defined(_MINGW_) || defined(_MSVC98_)
    string toBytes(const wstring& wstr);
    wfstream fs(toBytes(ldconfPath).c_str(), wfstream::out);
#else
    wfstream fs(ldconfPath.c_str(), wfstream::out);
#endif
    if (!fs.fail())
    {
        //		wstring s = ocamlPath + L"\\lib\\ocaml\\stublibs";
        wstring s = ocamlLibPath + L"\\stublibs";
        fs << s.c_str() << endl;
        fs.close();
    }
}
wstring setOCamlPath()
{
    WCHAR path[MAX_PATH];
	memset(path, 0, sizeof(path));
    BROWSEINFO bi = {0};
    bi.lpszTitle = (L"Emplacement d'OCaml ?");
	bi.hwndOwner = (HWND)mainFrame->winId();
    LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
    if (pidl != 0)
    {
        SHGetPathFromIDList (pidl, path);
		wstring s;
		if (getConfigFolderPath(s))
		{
			s += L"ocamlbase.txt";
#if defined(_MINGW_) || defined(_MSVC98_) || defined(QT4_7)
			string toBytes(const wstring& wstr);
			wfstream wfs(toBytes(s).c_str(), wfstream::out);
#else
			wfstream wfs(s.c_str(), wfstream::out);
#endif			
			if (!wfs.fail())
			{
				wfs << path << endl;
				wfs.close();
			}
		}
        IMalloc* p = NULL;
        if ( SUCCEEDED(SHGetMalloc(&p)))
        {
            p->Free (pidl);
            p->Release();
        }
	}
	return path;
}
wstring getOCamlPath()
{
    wstring cfp;
    wstring ocamlPath;
    if (getConfigFolderPath(cfp))
    {
        cfp += L"ocamlbase.txt";
 #if defined(_MINGW_) || defined(_MSVC98_) || defined(QT4_7) 
		string toBytes(const wstring& wstr);
		wfstream wfs(toBytes(cfp).c_str(), wfstream::in);
#else
		wfstream wfs(cfp.c_str(), wfstream::in);
#endif			
       if (!wfs.fail())
        {
            wchar_t c;
            while (wfs.get(c) && c != L'\r' && c != L'\n')
                ocamlPath += c;
            
            wfs.close();
        }
    }
    return ocamlPath;
}
void resetOCamlPath()
{
    wstring s;
    if (getConfigFolderPath(s))
    {
        s += L"ocamlbase.txt";
        if (PathFileExists(s.c_str()))
        {
			void deleteFile(const wstring& path);
            deleteFile(s);
        }
    }
}
wstring commandLine(int option, const wstring& dirPath)
{
    wstring cmdl;
    switch(option)
    {
        case OCAML64_LOCAL:
        {
            wstring ocamlPath = dirPath + L"\\ocaml\\windows\\ocaml64\\miniocaml";
            wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
            wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
            if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
            wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
            cmdl = ocamlrun  + L" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
            ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), ocamlLibPath.c_str());
            ldconf(ocamlPath);
            break;
        }
        case OCAML64:
        {
            wstring ocamlPath = L"C:\\Program Files\\Objective Caml";
            wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
            wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
            if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
            wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
            
            cmdl = ocamlrun + L" -I \"" + dirPath + L"\\ocaml\\windows\\ocaml64\"" + L" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
            ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), ocamlLibPath.c_str());
            ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            break;
        }
        case OCAML32_64:
        {
            wstring ocamlPath = L"C:\\Program Files (x86)\\Objective Caml";
            wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
            wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
            if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
            wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
            
            cmdl = ocamlrun + L" -I \"" + dirPath + L"\\ocaml\\windows\\ocaml32" + L"\" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
            ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), (ocamlLibPath).c_str());
            ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            break;
        }
        case OCAML32_64A:
        {
            wstring ocamlPath = L"C:\\OCaml";
            wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
            wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
            if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
            wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
            
            cmdl = ocamlrun + L" -I \"" + dirPath + L"\\ocaml\\windows\\ocaml32" + L"\" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
            ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), (ocamlLibPath).c_str());
            ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            break;
        }
        case OCAML32:
        {
            wstring ocamlPath = L"C:\\Program Files\\Objective Caml";
            wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
            wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
            if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
            wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
            
            cmdl = ocamlrun + L" -I \"" + dirPath + L"\\ocaml\\windows\\ocaml32" + L"\" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
            ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), (ocamlLibPath).c_str());
            ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            break;
        }
        case OCAML32A:
        {
            wstring ocamlPath = L"C:\\OCaml";
            wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
            wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
            if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
            wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
            
            cmdl = ocamlrun + L" -I \"" + dirPath + L"\\ocaml\\windows\\ocaml32" + L"\" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
            ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), (ocamlLibPath).c_str());
            ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            break;
        }
        case OCAML32B:
        {
            wstring ocamlPath = getOCamlPath();
            if (ocamlPath == L"")
            {
                cmdl = L"";
            }
            else
            {
                ldconf(ocamlPath);
                DWORD binaryType;
                wstring libgraphDirPath = dirPath;
                if (GetBinaryType(LPCTSTR((ocamlPath + L"\\bin\\ocamlrun.exe").c_str()), (LPDWORD)&binaryType)) {
                    if (binaryType  == SCS_32BIT_BINARY)
                    {
                        libgraphDirPath +=  L"\\ocaml\\windows\\ocaml32";
                    }
                    else if (binaryType  == SCS_64BIT_BINARY)
                    {
                        libgraphDirPath +=  L"\\ocaml\\windows\\ocaml64";
                    }
                }
                wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
                wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
                if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
                wstring libgraphDirPath1 = ocamlLibPath + L"\\WinCaml";
                wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
                
                cmdl = ocamlrun + L" -I \"" + libgraphDirPath1 + L"\" -I \"" + libgraphDirPath + L"\" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
                ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), ocamlLibPath.c_str());
                ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            }
            break;
        }
        case OCAMLNOTFOUND:
        {
            wstring ocamlPath = setOCamlPath();
            if (ocamlPath == L"")
            {
                cmdl = L"";
            }
            else
            {
                ldconf(ocamlPath);
                DWORD binaryType;
                wstring libgraphDirPath = dirPath;
                if (GetBinaryType(LPCTSTR((ocamlPath + L"\\bin\\ocamlrun.exe").c_str()), (LPDWORD)&binaryType)) {
                    if (binaryType  == SCS_32BIT_BINARY)
                    {
                        libgraphDirPath +=  L"\\ocaml\\windows\\ocaml32";
                    }
                    else if (binaryType  == SCS_64BIT_BINARY)
                    {
                        libgraphDirPath +=  L"\\ocaml\\windows\\ocaml64";
                    }
                }
                wstring ocamlLibPath = ocamlPath + L"\\lib\\ocaml";
                wstring ocamlStublibsPath = ocamlPath + L"\\lib\\ocaml\\stublibs";
                if (!PathFileExists(ocamlLibPath.c_str())) { ocamlLibPath = ocamlPath + L"\\lib"; ocamlStublibsPath = ocamlPath + L"\\lib\\stublibs"; }
                wstring libgraphDirPath1 = ocamlLibPath + L"\\WinCaml";
                wstring ocamlrun = L"\"" + ocamlPath + L"\\bin\\ocamlrun.exe\"" + L" \"" + ocamlPath + L"\\bin\\ocaml\"";
                
                cmdl = ocamlrun + L" -I \"" + libgraphDirPath1 + L"\" -I \"" + libgraphDirPath + L"\" -I \"" + ocamlLibPath + L"\" -I \"" + ocamlStublibsPath + L"\"";
                ::SetEnvironmentVariable(wstring(L"OCAMLLIB").c_str(), ocamlLibPath.c_str());
                ::SetEnvironmentVariable(wstring(L"PATH").c_str(), (ocamlPath + L"\\bin").c_str());
            }
            break;
        }
        case CAMLLIGHT64:
        {
            wstring locale = L"fr";
            wstring dirPath1 = dirPath;
            for(size_t i = 0; i < dirPath1.length(); i++)
            {
                if (dirPath1[i] == L'\\') dirPath1.replace(i, 1, L"/");
            }
            dirPath1 = L"/cygdrive/" + dirPath1.substr(0, 1) + dirPath1.substr(2);
            cmdl = L"\"" + dirPath + L"\\caml-light\\bin\\camltoplevel64cygwin.exe\"" + L" -stdlib \"" + dirPath1 + L"/caml-light/lib\"" + L" -lang \"" + locale + L"\"";
            break;
        }
        case CAMLLIGHT64A:
        {
            wstring locale = L"fr";
            cmdl = L"\"" + dirPath + L"\\caml-light\\bin\\camltoplevel64.exe\"" + L" -stdlib \"" + dirPath + L"\\caml-light\\lib\"" + L" -lang \"" + locale + L"\"";
            break;
        }
        case CAMLLIGHT32:
        {
            wstring locale = L"fr";
            wstring dirPath1 = dirPath;
            for(size_t i = 0; i < dirPath1.length(); i++)
            {
                if (dirPath1[i] == L'\\') dirPath1.replace(i, 1, L"/");
            }
            dirPath1 = L"/cygdrive/" + dirPath1.substr(0, 1) + dirPath1.substr(2);
            cmdl = L"\"" + dirPath + L"\\caml-light\\bin\\camltoplevel32cygwin.exe\"" + L" -stdlib \"" + dirPath1 + L"/caml-light/lib\"" + L" -lang \"" + locale + L"\"";
            break;
        }
        case CAMLLIGHT32A:
        {
            wstring locale = L"fr";
            cmdl = L"\"" + dirPath + L"\\caml-light\\bin\\camltoplevel32.exe\"" + L" -stdlib \"" + dirPath + L"\\caml-light\\lib\"" + L" -lang \"" + locale + L"\"";
            break;
        }
        default:
            cmdl = L"";
            break;
    }
    return cmdl;
}
CProcess* startCaml(bool ocaml)
{
    bool arch64 = architecture64();
    int option;
    if (ocaml && arch64) {option = OCAML64_LOCAL;}
    else if (ocaml && !arch64) {option = OCAML32A;}
    else if (!ocaml&& arch64) {option = CAMLLIGHT64;}
	else {option = CAMLLIGHT32;}
    
	wstring appDirPath = applicationDirectoryPath();
   
	CProcess* camlProcess = new CProcess();

start:
	wstring cmdl = commandLine(option, appDirPath);
	if (cmdl == L"")
	{
		if (ocaml && option != OCAMLNOTFOUND)
		{
			option = OCAMLNOTFOUND;
			goto start;
		}
		else
		{
			delete camlProcess;
			return NULL;
		}
	}
	if (camlProcess->start(cmdl))
	{
		return camlProcess;
	}
	switch(option)
	{
        case OCAML64_LOCAL:
		{
			option = OCAML64;
			goto start;
		}
        case OCAML64:
		{
			option = OCAML32_64A;
			goto start;
		}
        case OCAML32_64A:
		{
			option = OCAML32_64;
			goto start;
		}
        case OCAML32_64:
		{
			option = OCAML32B;
			goto start;
		}
        case OCAML32A:
		{
			option = OCAML32;
			goto start;
		}
        case OCAML32:
		{
			option = OCAML32B;
			goto start;
		}
		case OCAML32B:
		{
			option = OCAMLNOTFOUND;
			goto start;
		}
        case CAMLLIGHT64:
		{
			option = CAMLLIGHT64A;
			goto start;
		}
        case CAMLLIGHT64A:
		{
			option = CAMLLIGHT32;
			goto start;
		}
        case CAMLLIGHT32:
		{
			option = CAMLLIGHT32A;
			goto start;
		}
        case CAMLLIGHT32A:
		{
			delete camlProcess;
			return NULL;
		}
        default:
		{
			delete camlProcess;
			return NULL;
		}
	}
}
void camllightHelp()
{
    wstring appDirPath = applicationDirectoryPath();
    wstring docPath = appDirPath + L"\\caml-light\\man-caml\\index.html";
    ::ShellExecute(NULL, L"open", docPath.c_str(), NULL, appDirPath.c_str(), SW_SHOW);
}
void ocamlHelp()
{
    wstring appDirPath = applicationDirectoryPath();
    wstring docPath = appDirPath;
    docPath += L"\\ocaml\\htmlman\\index.html";
    if (32 >= (size_t)::ShellExecute(NULL, L"open", docPath.c_str(), NULL, appDirPath.c_str(), SW_SHOW))
    {
        if (32 >= (size_t)::ShellExecute(NULL, L"open", L"C:\\Program Files\\Objective Caml\\htmlman\\index.html", NULL, L"C:\\Program Files\\Objective Caml\\htmlman", SW_SHOW))
            ::ShellExecute(NULL, L"open", L"C:\\Program Files (x86)\\Objective Caml\\htmlman\\index.html", NULL, L"C:\\Program Files (x86)\\Objective Caml\\htmlman", SW_SHOW);
    }
}
#endif
