/* 
CCIDE
Copyright 2001-2011 David Lindauer.

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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

You may contact the author at:
	mailto::camille@bluegrass.net
 */
#define STRICT 
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>
#include "header.h"

extern HWND hwndSourceTab;
extern HANDLE hInstance;
extern HWND hwndWatch, hwndClient, hwndFrame, hwndTab;

static HWND hwndError;
static int rescroll;
static char szErrorClassName[] = "xccErrorClass";
static WNDPROC oldproc;
static HWND hwndCtrl, hwndTabCtrl;
static int index;
static int wheelIncrement;
static LOGFONT Boldfontdata = 
{
    14, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_MODERN | FF_DONTCARE, "Arial"
};
static LOGFONT Normalfontdata = 
{
    14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_MODERN |
        FF_DONTCARE, "Arial"
};
static char *nameTags[] = 
{
    "Build", "Debug", "Find in Files 1", "Find in Files 2"
};
static char *szErrorTitle = "Information Window";
int getfile(char *start, char *buffer, char end, DWINFO *info)
{
    char *t = buffer, *q;
    int rv;
    rv = atoi(++buffer);
    while (*buffer && isdigit(*buffer))
        buffer++;
    if (*buffer == end)
    {
		/* complexity is to allow white space in file and path names */
		q = strchr(start, ':');
		if (q && q != start)
		{
			char *r = strchr(start, '.');
			if (r && r < q)
			{
				q = r;
				while (q != start && isalnum(q[-1]))
					q--;
			}
			else
				q--;
		}
		else
		{
			q = strchr(start, '\\');
			if (!q)
			{
				q = t;					
		        while (q > start)
		        {
		            if (*(q - 1) == ' ')
		                break;
		            q--;
		        }
			}
			else
			{
				char *r = strchr(start, '.');
				if (r && r < q)
				{
					q = r;
					while (q != start && isalnum(q[-1]))
						q--;
				}
			}
		}
        strncpy(info->dwName, q, t - q);
        info->dwName[t - q] = 0;
        q = strrchr(info->dwName, '\\');
        if (q)
            strcpy(info->dwTitle, q + 1);
        else
            strcpy(info->dwTitle, info->dwName);
        return rv;
    }
    return  - 1;
}

//-------------------------------------------------------------------------

void BumpToEditor(HWND hwnd)
{
    HWND wnd;
    DWINFO info;
    char name[256], title[256], buffer[256],  *t, *q;
    int lineno;
    int start;
    SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, 0);
    lineno = SendMessage(hwnd, EM_EXLINEFROMCHAR, 0, start);
    *(short*)buffer = 255;
    lineno = SendMessage(hwnd, EM_GETLINE, lineno, (LPARAM)buffer);
    buffer[lineno] = 0;
    lineno =  - 1;
	if (index >= 2) /* find in file dialog */
	{
		t = info.dwName;
		q = buffer;
		while (*q && !isspace(*q))
		{
			*t++ = *q++;
		}
		*t = 0;
		while (isspace(*q))
			q++;
		lineno = atoi(q);
        q = strrchr(info.dwName, '\\');
        if (q)
            strcpy(info.dwTitle, q + 1);
        else
            strcpy(info.dwTitle, info.dwName);
	}
    else if ((t = strchr(buffer, '(')) && isdigit(*(t + 1)))
    {
        lineno = getfile(buffer, t, ')', &info);
    }
    else
    {
        t = buffer;
        while (1)
        {
            if (t = strchr(t + 1, ':'))
            {
                if (isdigit(*(t + 1)))
                {
                    lineno = getfile(buffer, t, ':', &info);
                    if (lineno !=  - 1)
                        break;
                }
            }
            else
                break;
        }
    }
    if (lineno !=  - 1)
    {
        info.dwLineNo = lineno;
        info.logMRU = FALSE;
		info.newFile = FALSE;
        CreateDrawWindow(&info, TRUE);
    }

}

//-------------------------------------------------------------------------

void ScanForTags(int tagid, HWND hwnd)
{
    int lines;
    int i, lineno;
    DWINFO info;
    char buffer[256],  *t;
    lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
    for (i = 0; i < lines; i++)
    {
        *(short*)buffer = 255;
        lineno = SendMessage(hwnd, EM_GETLINE, i, (LPARAM)buffer);
        buffer[lineno] = 0;
        lineno =  - 1;
        if ((t = strchr(buffer, '(')) && isdigit(*(t + 1)))
        {
            lineno = getfile(buffer, t, ')', &info);
        }
        else
        {
            t = buffer;
            while (1)
            {
                if (t = strchr(t + 1, ':'))
                {
                    if (isdigit(*(t + 1)))
                    {
                        lineno = getfile(buffer, t, ':', &info);
                        if (lineno !=  - 1)
                            break;
                    }
                }
                else
                    break;
            }
        }
        if (lineno !=  - 1)
        {
            Tag(tagid, info.dwName, lineno, 0, 0, 0, 0);
        }
    }
}

//-------------------------------------------------------------------------

LRESULT CALLBACK _export buildEditProc(HWND hwnd, UINT iMessage, WPARAM wParam,
    LPARAM lParam)

{
    char buffer[256];
    int pos, chars, line, i;
    LRESULT rv;
    POINTL point;
    HBRUSH bk;
    RECT r;
    CHARRANGE s;
    switch (iMessage)
    {
        case WM_CREATE:
            rv = CallWindowProc(oldproc, hwnd, iMessage, wParam, lParam);
            //         SendMessage(hwnd,EM_NOCOLORIZE,0,0) ;
            return rv;
        case WM_LBUTTONDOWN:
            *(short*)buffer = 256;
            point.x = LOWORD(lParam);
            point.y = HIWORD(lParam);
            pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
            line = SendMessage(hwnd, EM_EXLINEFROMCHAR, 0, pos);
            i = SendMessage(hwnd, EM_GETLINE, line, (LPARAM) &buffer);
            chars = 0; // richedit 1.0 was tacking things on the end...
            while (i-- && buffer[chars] > 31)
                chars++;
            pos = SendMessage(hwnd, EM_LINEINDEX, line, 0);
            s.cpMin = pos;
            s.cpMax = pos + chars;
            SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &s);

			SetFocus(hwnd);
            return 0;
        case WM_RBUTTONDOWN:
            {
                HMENU menu = LoadMenu(hInstance, "BUILDMENU");
                HMENU popup = GetSubMenu(menu, 0);
                POINT pos;
                GetCursorPos(&pos);
				InsertBitmapsInMenu(popup);
                TrackPopupMenuEx(popup, TPM_BOTTOMALIGN | TPM_LEFTBUTTON, pos.x,
                    pos.y, hwndFrame, NULL);
                DestroyMenu(menu);
            }
			SetFocus(hwnd);
            return 0;
        case WM_LBUTTONDBLCLK:
            BumpToEditor(hwnd);
			return 0;
        case WM_RBUTTONDBLCLK:
        case WM_LBUTTONUP:
        case WM_RBUTTONUP:
            return 0;
		case WM_MOUSEWHEEL:
			wheelIncrement -= GET_WHEEL_DELTA_WPARAM(wParam);
			if (wheelIncrement < 0)
			{
				while (wheelIncrement <= - WHEEL_DELTA)
				{
					SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
					wheelIncrement += WHEEL_DELTA;
				}
			}
			else
			{
				while (wheelIncrement >= WHEEL_DELTA)
				{
					SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
					wheelIncrement -= WHEEL_DELTA;
				}
			}
			return 0;
		case WM_VSCROLL:
			if (wParam != SB_BOTTOM)
				rescroll= TRUE;
			break;
		case WM_KEYUP:
			switch (wParam)
			{
				case VK_UP:
					SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
					break;
				case VK_DOWN:
					SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
					break;
				case VK_PRIOR:
					SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
					break;
				case VK_NEXT:
					SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
					break;
				case VK_HOME:
					SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0);
					break;
				case VK_END:
					SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);
					break;
			}
			return 0;
		case WM_KEYDOWN:
			return 0;
		case WM_CHAR:
			return 0;
    }
    return CallWindowProc(oldproc, hwnd, iMessage, wParam, lParam);
}

//-------------------------------------------------------------------------

LRESULT CALLBACK _export errorProc(HWND hwnd, UINT iMessage, WPARAM wParam,
    LPARAM lParam)
{
    static HWND hsubwnds[4]; // build, debug, find1, find2
    static HFONT tabBoldFont, tabNormalFont;
	CHARFORMAT cfm;
    TC_ITEM tie;
    NMHDR *h;
    DRAWITEMSTRUCT *dr;
	MEASUREITEMSTRUCT *mr;
    HFONT font;
    RECT r, r1,  *pr;
    CHARRANGE s;
	HDC dc ;
	int clr;
	static int colors[4];
	static int forecolor;
    switch (iMessage)
    {
        case WM_MDIACTIVATE:
            SendMessage(hwndCtrl, LCF_SETACTIVE, 0, lParam == (LPARAM)hwnd);
            if (lParam == (LPARAM)hwnd)
                SendMessage(hwndSourceTab, WM_SETACTIVETAB, 0, (LPARAM)hwnd);
            return TRUE;
        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
            {
                SendMessage(hwnd, WM_CLOSE, 0, 0);
            }
            break;
        case WM_NOTIFY:
            h = (NMHDR*)lParam;
            switch (h->code)
            {
            case TCN_SELCHANGE:
                ShowWindow(hsubwnds[index], SW_HIDE);
                index = TabCtrl_GetCurSel(hwndTabCtrl);
                ShowWindow(hsubwnds[index], SW_SHOW);
                break;
            }
            break;
        case WM_COMMAND:
            //			switch(LOWORD(wParam)) {
            //			}
            break;
		case WM_VSCROLL:
				break;
//		case WM_MEASUREITEM:
//          mr = (MEASUREITEMSTRUCT*)lParam;
//			mr->itemWidth = 200;
//			return TRUE;
        case WM_DRAWITEM:
            dr = (DRAWITEMSTRUCT*)lParam;
            if (dr->itemState &ODS_SELECTED)
            {
				FillRect(dr->hDC, &dr->rcItem, (HBRUSH)(COLOR_BTNHIGHLIGHT+1));
                font = tabBoldFont;
				clr = SetBkColor(dr->hDC, GetSysColor(COLOR_BTNHIGHLIGHT));
            }
            else
			{
                font = tabNormalFont;
			}
            font = SelectObject(dr->hDC, font);
            TextOut(dr->hDC, dr->rcItem.left + 4, dr->rcItem.top,
                nameTags[dr->itemID], strlen(nameTags[dr->itemID]));
            font = SelectObject(dr->hDC, font);
            if (dr->itemState &ODS_SELECTED)
			{
				SetBkColor(dr->hDC, clr);
			}
            break;
		case WM_SETCOLOR:
			colors[wParam] = lParam;
			break;
        case WM_SETTEXT2: // well the settexts get aggregated...
            if (!lParam)
			{
                SendMessage(hsubwnds[wParam], WM_SETTEXT, 0, (LPARAM)"");
				rescroll = FALSE;
			}
            else
            {
                int lindex = SendMessage(hsubwnds[wParam], EM_LINEINDEX,
                    0x7fffffff, 0);
				int thumb = SendMessage(hsubwnds[wParam], EM_GETTHUMB, 0, 0);
                SendMessage(hsubwnds[wParam], EM_HIDESELECTION, 1, 0);
                s.cpMin = s.cpMax = lindex;
                SendMessage(hsubwnds[wParam], EM_EXSETSEL, 0, (LPARAM) &s);
				memset(&cfm, 0, sizeof(cfm));
				cfm.cbSize = sizeof(cfm);
				cfm.dwMask = CFM_COLOR;
				cfm.crTextColor = colors[wParam];
                SendMessage(hsubwnds[wParam], EM_REPLACESEL, FALSE, lParam);
				SendMessage(hsubwnds[wParam], EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) & cfm);
                SendMessage(hsubwnds[wParam], EM_HIDESELECTION, 0, 0);
				if (rescroll)
				{
//					SendMessage(hsubwnds[wParam], WM_VSCROLL, MAKELONG(SB_THUMBPOSITION, thumb), 0);
				}
				else
				{
					SendMessage(hsubwnds[wParam], WM_VSCROLL, SB_BOTTOM, 0);
//	                SendMessage(hsubwnds[wParam], EM_SCROLLCARET, 0, 0);
				}
				free((void *)lParam);

            }
			colors[wParam] = GetSysColor(COLOR_WINDOWTEXT);
            return 0;
        case WM_SETFOCUS:
            SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
            SendMessage(hsubwnds[index], WM_SETFOCUS, wParam, lParam);
            break;
		case WM_MOUSEWHEEL:
			SendMessage(hsubwnds[index], iMessage, wParam, lParam);
			return 0;
        case WM_CREATE:
            hwndError = hwnd;
            GetClientRect(hwnd, &r);
            hwndCtrl = CreateControlWindow(DID_ERRORWND, hwnd, &r, (int)(
                (LPMDICREATESTRUCT)(*(int*)lParam))->lParam, szErrorTitle);
            SendMessage(hwndCtrl, LCF_ADJUSTRECT, 0, (LPARAM) &r);
            tabBoldFont = CreateFontIndirect(&Boldfontdata);
            tabNormalFont = CreateFontIndirect(&Normalfontdata);
            #ifndef __CCDL__
                #ifndef TCS_BOTTOM
                    #define TCS_BOTTOM 2
                #endif 
            #endif 
            hwndTabCtrl = CreateWindow(WC_TABCONTROL, 0, WS_CHILD +
                WS_CLIPSIBLINGS + WS_VISIBLE + TCS_OWNERDRAWFIXED
                + TCS_FOCUSNEVER + TCS_FIXEDWIDTH + TCS_BOTTOM, r.left, r.top,
                r.right - r.left, r.bottom - r.top, hwndCtrl, 0, hInstance, 0);
            SendMessage(hwndTabCtrl, WM_SETFONT, (WPARAM)tabNormalFont, 0);
			SendMessage(hwndTabCtrl, TCM_SETITEMSIZE, 0, MAKELPARAM(90,16));
            OffsetRect(&r,  - r.left,  - r.top);
            TabCtrl_AdjustRect(hwndTabCtrl, FALSE, &r);
            hsubwnds[0] = CreateWindowEx(0, "XBUILDEDIT", 0, WS_CHILD +
                WS_VISIBLE + WS_VSCROLL + ES_NOHIDESEL + WS_BORDER + ES_LEFT +
                ES_MULTILINE + ES_READONLY, r.left, r.top, r.right - r.left, r.bottom - r.top,
                hwndTabCtrl, (HMENU)ID_EDITCHILD, hInstance, 0);
            hsubwnds[1] = CreateWindowEx(0, "XBUILDEDIT", 0, WS_CHILD + 
                WS_VSCROLL + ES_NOHIDESEL + WS_BORDER + ES_LEFT + ES_MULTILINE + ES_READONLY,
                r.left, r.top, r.right - r.left, r.bottom - r.top, hwndTabCtrl,
                (HMENU)ID_EDITCHILD, hInstance, 0);
            hsubwnds[2] = CreateWindowEx(0, "XBUILDEDIT", 0, WS_CHILD + 
                WS_VSCROLL + ES_NOHIDESEL + WS_BORDER + ES_LEFT + ES_MULTILINE + ES_READONLY,
                r.left, r.top, r.right - r.left, r.bottom - r.top, hwndTabCtrl,
                (HMENU)ID_EDITCHILD, hInstance, 0);
            hsubwnds[3] = CreateWindowEx(0, "XBUILDEDIT", 0, WS_CHILD + 
                WS_VSCROLL + ES_NOHIDESEL + WS_BORDER + ES_LEFT + ES_MULTILINE + ES_READONLY,
                r.left, r.top, r.right - r.left, r.bottom - r.top, hwndTabCtrl,
                (HMENU)ID_EDITCHILD, hInstance, 0);
			
            SendMessage(hsubwnds[0], EM_LIMITTEXT, 4 *65536, 0);
            SendMessage(hsubwnds[1], EM_LIMITTEXT, 4 *65536, 0);
            SendMessage(hsubwnds[2], EM_LIMITTEXT, 4 *65536, 0);
            SendMessage(hsubwnds[3], EM_LIMITTEXT, 4 *65536, 0);
            SendMessage(hsubwnds[0], WM_SETFONT, (WPARAM)tabNormalFont, 0);
            SendMessage(hsubwnds[1], WM_SETFONT, (WPARAM)tabNormalFont, 0);
            SendMessage(hsubwnds[2], WM_SETFONT, (WPARAM)tabNormalFont, 0);
            SendMessage(hsubwnds[3], WM_SETFONT, (WPARAM)tabNormalFont, 0);
            tie.mask = TCIF_TEXT;
            tie.iImage =  - 1;
            tie.pszText = nameTags[0];
            TabCtrl_InsertItem(hwndTabCtrl, 0, &tie);
            tie.mask = TCIF_TEXT;
            tie.iImage =  - 1;
            tie.pszText = nameTags[1];
            TabCtrl_InsertItem(hwndTabCtrl, 1, &tie);
            tie.mask = TCIF_TEXT;
            tie.iImage =  - 1;
            tie.pszText = nameTags[2];
            TabCtrl_InsertItem(hwndTabCtrl, 2, &tie);
            tie.mask = TCIF_TEXT;
            tie.iImage =  - 1;
            tie.pszText = nameTags[3];
            TabCtrl_InsertItem(hwndTabCtrl, 3, &tie);
			colors[0] = colors[1] = colors[2] = colors[3] = GetSysColor(COLOR_WINDOWTEXT);
            return 0;
        case WM_CLOSE:
            dmgrHideWindow(DID_ERRORWND, TRUE);
            return 0;
        case WM_DESTROY:
            dmgrRemoveClient((CCW_params*)GetWindowLong(hwndCtrl, 0));
            DestroyWindow(hwndTabCtrl);
            DestroyWindow(hsubwnds[0]);
            DestroyWindow(hsubwnds[1]);
            DestroyWindow(hsubwnds[2]);
            DestroyWindow(hsubwnds[3]);
            DestroyWindow(hwndCtrl);
            break;
        case WM_SELERRWINDOW:
			ShowWindow(hsubwnds[index], SW_HIDE);
			index = lParam;
            SendMessage(hwnd, WM_SETTEXT2, index, 0);
            TabCtrl_SetCurSel(hwndTabCtrl, index);
			ShowWindow(hsubwnds[index], SW_SHOW);
            return 0;
        case WM_ERRDONESCAN:
            TagRemoveAll(lParam == ERR_FIND1_WINDOW ? TAG_FIF1 : TAG_FIF2);
            ScanForTags(lParam == ERR_FIND1_WINDOW ? TAG_FIF1 : TAG_FIF2,
                lParam == ERR_FIND1_WINDOW ? hsubwnds[2]: hsubwnds[3]);
            break;
		case WM_MOVE:
			break;
        case WM_SIZE:
//			GetWindowRect(hwnd, &r);
//			ExtendedMessageBox("hi",0,"%d %d %d %d", r.left, r.top, r.right, r.bottom);
            MoveWindow(hwndCtrl, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            r.left = 0;
            r.right = LOWORD(lParam);
            r.top = 0;
            r.bottom = HIWORD(lParam);
            SendMessage(hwndCtrl, LCF_ADJUSTRECT, 0, (LPARAM) &r);
            MoveWindow(hwndTabCtrl, r.left, r.top, r.right - r.left, r.bottom -
                r.top, TRUE);
			OffsetRect(&r, -r.left, -r.top);
			TabCtrl_AdjustRect(hwndTabCtrl, FALSE, &r);
            MoveWindow(hsubwnds[0], r.left, r.top, r.right - r.left, r.bottom -
                r.top, TRUE);
            MoveWindow(hsubwnds[1], r.left, r.top, r.right - r.left, r.bottom -
                r.top, TRUE);
            MoveWindow(hsubwnds[2], r.left, r.top, r.right - r.left, r.bottom -
                r.top, TRUE);
            MoveWindow(hsubwnds[3], r.left, r.top, r.right - r.left, r.bottom -
                r.top, TRUE);
			return 0;
        default:
            break;
    }
    return DefMDIChildProc(hwnd, iMessage, wParam, lParam);
}

//-------------------------------------------------------------------------

void RegisterErrorWindow(void)
{
    WNDCLASS wc;
    memset(&wc, 0, sizeof(wc));
    wc.style = 0;
    wc.lpfnWndProc = &errorProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = szErrorClassName;
    RegisterClass(&wc);

    GetClassInfo(0, "richedit", &wc);
    oldproc = wc.lpfnWndProc;
    wc.lpfnWndProc = &buildEditProc;
    wc.lpszClassName = "XBUILDEDIT";
    wc.hInstance = hInstance;
    wc.hbrBackground = 0;
    RegisterClass(&wc);


}

//-------------------------------------------------------------------------

void CreateErrorWindow(void)
{
    MDICREATESTRUCT mc;
    RECT r;
    if (hwndError)
        return ;
    mc.szClass = szErrorClassName;
    mc.szTitle = szErrorTitle;
    mc.hOwner = hInstance;
    mc.x = CW_USEDEFAULT;
    mc.y = CW_USEDEFAULT;
    mc.cx = 200;
    mc.cy = 200;
    mc.style = WS_CHILD | WS_DLGFRAME | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    mc.lParam = (LPARAM)0;
    hwndError = (HWND)SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM) &mc);
}
void SetErrorColor(int window, DWORD color)
{
	PostMessage(hwndError, WM_SETCOLOR, window, color);
}
void SelectErrorWindow(int window)
{
    PostMessage(hwndError, WM_SELERRWINDOW, 0, window);
    PostMessage(hwndClient, WM_MDIACTIVATE, (WPARAM)hwndError, 0);
}
void SendErrorMessage(int window, char *buf)
{
	char *p ;
	if (buf)
		p = strdup(buf);
	else
		p = buf;
    PostMessage(hwndError, WM_SETTEXT2, window, (LPARAM)p);
}
void SendErrorDone(int window)
{
    PostMessage(hwndError, WM_ERRDONESCAN, 0, window);
}