/*
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 Win.h

#pragma once

// Command line macros: _MSVC98_, _WIN2000_, _MINGW_, _MSVC2010_, _WINDOWS_PLATFORM_

#ifdef _MINGW_
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x501
#ifdef WINVER
#undef WINVER
#endif
#define WINVER 0x501
#endif

#include "../All/resource.h"
#include "../All/Utils.h"
#include <Windows.h>
#include <commctrl.h>
#include <Richedit.h>
#include <deque>
#include <string>

typedef HWND (*WINDOW_BUILDER)(void*);

#define FIND_MAXLENGTH 1024
#define code_escape VK_ESCAPE
#define code_return VK_RETURN
#define idCancel IDCANCEL
#define idNo IDNO
#define idYes IDYES
#define endofline L"\r"
#define MONOSPACE L"Courier New"
#define rgb RGB


enum{ARROW, EAST_WEST, SOUTH_NORTH};

class CMDIFrame;
class CMDIChildFrame;
class CRichEdit;
class CFont;

using namespace std;

extern const wstring appName;
extern const wstring version, version1;
extern const bool liveSplit;

void aboutMessage(const wstring& msg);
void errorMessage(const wstring& msg);
bool yesnoMessage(const wstring& msg);
int yesnocancelMessage(const wstring& msg);

void closeFindDialog(bool enableMenus = false);
void findDialog();
void findReplaceDialog();
void setSearchEdit(CRichEdit* edit);

inline wstring undoShortCut()
{
	return L"ctrl+Z";
}
inline wstring redoShortCut()
{
	return L"ctrl+Y";
}

class CWindow
{
	friend LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
public:
	HWND hWnd;
protected:
	CWindow(void* hInstance, WINDOW_BUILDER wm);
	~CWindow();
	void stopMessages();
private:
	virtual LRESULT wndProc(UINT msg, WPARAM wParam, LPARAM lParam) = 0;
};

class CMDIApp
{
public:    
	bool alreadyExists;

	CMDIApp();
	~CMDIApp();    
	int run(CMDIFrame& frame);
private:
	int argc;
	LPWSTR* argv;
	HANDLE hMutex;
	wstring name;
};

class CMDIFrame : public CWindow
{
	friend class CMDIChildFrame;
	friend class CMDIApp;
	friend class CFont;
	friend HWND makeMDIChildFrame(void* mdiFrame);
public:
	int LeftMargin;
	int TopMargin;
	int RightMargin;
	int BottomMargin;
    
    deque<CMDIChildFrame*> mdiChildren;

	void enableMenuItem(int cmd, bool on);
	void setStatus(int index, const wstring& text);
protected:
	int xDim;
	int yDim;

	bool cascade;
	long frameLeft;
	long frameTop;
	long frameWidth;
	long frameHeight;
	deque<wstring*>* droppedFiles;
	bool Maximized;
	bool StatusBarVisible;
	bool ToolbarVisible;

	CMDIFrame();
	~CMDIFrame();
	void checkMenuItem(int cmd, bool on);
	void colorDialog(unsigned long& color);
	void fontDlg(CFont*& font);
	bool isIconic();
	void moveWindow(int left, int top, int width, int height);
	void onCascadeWindow();
	void onFileClose();
	void onFileExit();
	void onTileWindow();
	bool openFileDialog(wstring& fileName);
	void openIcon();
	void printSetUpDialog(int& leftMargin, int& topMargin, int& rightMargin, int& bottomMargin);
	bool saveFileDialog(wstring& title);
	bool saveFormattedDocumentDialog(wstring& title);
	void setActiveChild(CMDIChildFrame *childFrame);
	void setMenuItemText(int item, const wstring& title, bool enabled);
	void tabDialog(int& spaceNumPerTab);
	void updateFrame();
	virtual void onClose();
private:
	virtual void onCommand(int wParam);
	virtual void onDrop();
	virtual void openFile(const wstring& fileName);
	virtual void openFiles(deque<wstring>& fileName);
	virtual bool reviewChanges();

	HWND hMDIClient;
	HWND hStatus;
	HWND hTool;
	deque<wstring> filePaths;

	void createMDIClient();
	void createMenus();
	void createStatusbar();
	void createToolbar();
	void dropEvent(void* info);
	void enableTBButton(WPARAM command, bool enabled);
	HWND getActiveChild();
	void onDestroy();
	void onNotify(void* lParam);
	void onMove(int left, int top);
	void onOtherInstanceMessage(size_t msg);
	void onSize();
	void setTitle(const wstring& title);
	void showMaximized();
	void update();
	LRESULT wndProc(UINT msg, WPARAM wParam, LPARAM lParam);
};

class CMDIChildFrame : public CWindow
{
public:
	CRichEdit* textEdit;
	wstring title;

	void drawFocusRect(int left, int top, int right, int bottom);
	void getClientSize(int& width, int& height);
	void hide();
	bool isMaximized();
	void setCursor(int cursor);
	void setWindowModified(bool modified);
	void releaseCapture();
	void setCapture();
	void showMaximized();
protected:
	CMDIChildFrame(CMDIFrame* mdiFrame, bool maximized);
	~CMDIChildFrame();
	virtual void onClose();
	virtual void onDestroy();
	void setTitle(const wstring& title);
    void showDefault();
	void showNormal();
	void startTimer();
private:
	virtual void onCommand(int wParam);
	virtual void onEditCopy();
	virtual void onEditCut();
	virtual void onEditPaste();
	virtual void onEditSelectAll();
	virtual void onFileSaveAs();
	virtual void onLeftButtonDown(int x, int y);
	virtual void onLeftButtonUp();
	virtual void onActivate();
	virtual void onMouseMove(int x, int y, bool leftButtonDown);
	virtual void onSize();
	virtual void onTimer();
	virtual bool reviewChange();

	UINT_PTR timerID;

	void onActivate(bool activated);
	void onTimer(int timerID);
	void setDocumentIcon();
	void update();
	LRESULT wndProc(UINT msg, WPARAM wParam, LPARAM lParam);
};

class CHighlighter;

class CRichEdit: public CWindow
{
	friend LRESULT CALLBACK editProcCallback(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam);
	friend BOOL printRTF(CRichEdit* re, bool printSel, HDC hdc);
public:
	bool selectionChanged;
	unsigned long *T;
    unsigned int forecolorCount;
	CHighlighter* highlighter;
    size_t commandStart;
    size_t commandEnd;
    bool inBuffer;

	CRichEdit(CWindow* win);
	~CRichEdit();

	bool appendFile(const wstring& fileName, int encoding);
	void copy();
	void cut();
	void focus();
	size_t getCaretPosition();
	void getSelection(size_t& selStart, size_t& selEnd);
	wstring getText();
	wstring getText(size_t start, size_t length);
	size_t getTextLength();
	void hideSelection();
	size_t lineFirstChar(size_t lineIndex);
	size_t lineFromChar(size_t charIndex);
	bool loadFile(const wstring& fileName, bool guessEnc, int &preferredEncoding);
	void move(int left, int top, int width, int height);
	void paste();
	void printFormattedDialog();
	void replaceAll(const wstring& findWhat, const wstring& replaceWith, unsigned long flags);
	void resumeLayout();
	bool saveFile(const wstring& pszFileName, int encoding);
	void saveFormattedDocument(const wstring& fileName);
	void selectAll();
	void setBackground(unsigned long color);
	void setFont(CFont* font);
	void setReadOnly(bool b = true);
	void setSelectedText(const wstring& s);
	void setTabs(int charSize, int spaceCountPerTab);
	void setText(size_t start, size_t length, const wstring& text, unsigned long color = 0);
	void setTextBackground(size_t a, size_t l, unsigned long backColor);
	void setTextColor(size_t start, size_t length, unsigned long color);
	void setTextDefaultBackground(size_t a, size_t l);
    void setUseTabs(bool IndentWithTabs);
	void setWrapping(bool on);
	void showSelection();
	void suspendLayout();
	void updateCursor();
	void updateView();
	size_t visibleTextEnd();
	size_t visibleTextOffset();
	virtual wstring status();
protected:
	RECT margins;
	virtual void beginPrint();
	virtual void endPrint();
	virtual void setSelection(size_t selStart, size_t selEnd);
    void setColors();
private:
	virtual void onChar(int vKeyCode);
	virtual void onEnterKeyDown();
	virtual void onKeyDown();
	virtual void onKeyUp();
	virtual void onLeftButtonUp(bool ctrlDown);
	virtual void onReplace(const wstring& replaceWith);
	virtual void onReplaceAll(const wstring& findWhat, const wstring& replaceWith, unsigned long flags);
	virtual void onReturnKeyDown();
	virtual void replace(int a, int l, wstring s);

	FINDTEXTEX findTextEx;
	HWND hEdit;
	CHARRANGE scrollPos;
	CHARRANGE selRange;

	LRESULT editProc(UINT msg, WPARAM wParam, LPARAM lParam);
	void find(const wstring& findWhat, unsigned long flags);
	void getSelection(CHARRANGE *cr);
	void onFindClose();
	void onFindNext(const wstring& findWhat, int flags);
	void onFindReplace(LPARAM lParam);
	void onNotify(void* info);
	void setSelection(CHARRANGE cr);
	LRESULT wndProc(UINT msg, WPARAM wParam, LPARAM lParam);
};

class CFont
{
	friend void CMDIFrame::fontDlg(CFont*& font);
	friend void CRichEdit::setFont(CFont* font);
public:
	wstring* fntName;
	int fntSize;
	bool bold;
	bool italic;

	CFont(){hf = NULL; fntName = NULL; fntSize = 0;}
	CFont(const wstring& fontName, int fontSize, bool bold = false, bool italic = false);
	~CFont();
private:
	HFONT hf;
};

class CProcess
{
public:
	CProcess();
	~CProcess();
	string read();
	bool isRunning();
	bool interrupt();
	string readAllStandardOutput();
	bool start(const wstring& commandLine);
	void stop();
	void write(const char* data);
private:
	char* buffer;
	string bA;
	HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr;
	PROCESS_INFORMATION pi;
	STARTUPINFO startInfo;
	DWORD exitCode;

	int readFromPipe(char *data,int len);
	int writeToPipe(const char *data);
};

// class CSplitterBase ---------------------------------------------------------------------------------------------------

#define MINSIZE     2
#define HALFBARWIDTH   2

class CSplitterBase
{
protected:
    CMDIChildFrame* childFrame;
    bool verticalBar;
	int height;
	int width;

    CSplitterBase(CMDIChildFrame*)
    {
    }

    void moveVerticalSash(int)
    {
    }
    
    void moveHorizontalSash(int)
    {
    }
};
