/* 
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
 */
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>

#include "header.h"
#include <ctype.h>

extern int making;
extern enum DebugStates uState;
extern HWND hwndToolEdit, hwndToolDebug, hwndToolBuild;
extern LOGFONT EditFont;
extern HINSTANCE hInstance;
extern HWND hwndClient, hwndStatus, hwndFrame;
extern char szTargetFilter[], szWorkspaceFilter[], szSourceFilter[], szProjectFilter[] ;
extern HWND hwndTab, hwndWatch;
extern HWND hwndTabCtrl;
extern int browseInfo;
extern char szInstallPath[];

HANDLE projectSem;
HWND hwndProject;
int changedProject;
PROJLIST *projectList;
char szWorkspaceName[MAX_PATH] = "Default.cws";
char szWorkspaceTitle[MAX_PATH];
int defaultWorkspace = TRUE;

static int noworkspace = TRUE;
static HTREEITEM projectRoot = TVI_ROOT ;
static char szProjectClassName[] = "xccProjectClass";
static HWND treeWindow;
static HBITMAP flh, flasm, flres, flfiles, flc, fldll, fllib, flexe, flcws;
static int ilh, ilasm, ilres, ilfiles, ilc, ildll, illib, ilexe, ilcws;
static HBITMAP folderClose, folderOpen;
static int ilfolderClose, ilfolderOpen;
static HIMAGELIST treeIml;
static int treeViewSelected;
static HTREEITEM selectedItem;
static LOGFONT fontdata = 
{
    14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH
        | FF_MODERN | FF_DONTCARE, "Arial"
};
static HFONT projFont;
static HANDLE initSem ;

#ifndef __CCDL__
    #ifndef _WIN32_IE
        typedef struct tagTVKEYDOWN
        {
            NMHDR hdr;
            WORD wVKey;
            UINT flags;
        } NMTVKEYDOWN, FAR *LPNMTVKEYDOWN;
    #endif 
#endif 
void RefreshDepends(HWND hTree, PROJLIST *projlist);
void FindModuleName(char *out, char *in)
{
    PROJLIST *l = projectList;
    int i = 0;
    while (l)
    {
        int j = 0;
        FILELIST *m = l->sourceFiles;
        while (m)
        {
            if (!xstricmpz(in, m->name))
            {
                strcpy(out, in);
                return ;
            }
            if (!xstricmpz(in, m->title))
            {
                strcpy(out, m->name);
                return ;
            }
            m = m->next;
        }
        l = l->next;
    }
}

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

int imageof(char *name)
{
    name = strrchr(name, '.');
    if (!name)
        return ilfolderClose;
    if (!xstricmpz(name, ".asm"))
        return ilasm;
    if (!xstricmpz(name, ".c") || !xstricmpz(name, ".cpp"))
        return ilc;
    if (!xstricmpz(name, ".rc"))
        return ilres;
    if (!xstricmpz(name, ".h"))
        return ilh;
    if (!xstricmpz(name, ".exe"))
        return ilexe;
    if (!xstricmpz(name, ".lib"))
        return illib;
    if (!xstricmpz(name, ".dll"))
        return ildll;
    if (!xstricmpz(name, ".cws"))
        return ilcws;
    return ilfiles;
}

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

TREEDATA *getTreeData(HTREEITEM *item)
{
    TV_ITEM xx ;
    if (!item)
        return NULL;
    xx.hItem = item;
    xx.mask = TVIF_PARAM ;
    if (SendMessage(treeWindow, TVM_GETITEM,0 ,(LPARAM)&xx))
        return (TREEDATA *)xx.lParam ;
    return NULL;
}

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

HTREEITEM TVInitInsert(HWND hTree, HTREEITEM hParent, HTREEITEM after, char
    *title, int toexpand, enum td_type type, LPVOID data)
{
    HTREEITEM rv;
    TV_INSERTSTRUCT t;
    TREEDATA *itemData = calloc(1,sizeof(TREEDATA));
    if (itemData) 
    {
        itemData->t_type = type;
        itemData->x.data = data ;
    }
    memset(&t, 0, sizeof(t));
    t.hParent = hParent;
    t.hInsertAfter = after;
    #if !defined( _WIN32_IE) && !defined(__CCDL__)
        t.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
        t.item.hItem = 0;
        t.item.pszText = title;
        t.item.cchTextMax = strlen(title);
        t.item.iImage = t.item.iSelectedImage = imageof(title);
        t.item.lParam = itemData ;
    #else 
        t.u.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
        t.u.item.hItem = 0;
        t.u.item.pszText = title;
        t.u.item.cchTextMax = strlen(title);
        t.u.item.iImage = t.u.item.iSelectedImage = imageof(title);
        t.u.item.lParam = itemData ;
    #endif 
    rv = TreeView_InsertItem(hTree, &t);
    if (toexpand)
        TreeView_Expand(treeWindow, hParent, TVE_EXPAND);
    return rv;
}

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

void AddFileInternal(HTREEITEM treeHandle, 
        PROJLIST *l, FILELIST **p, char *name, char *title)
{
    FILELIST *x = *p;
    while (x)
    {
        if (!xstricmp(x->name, name))
            return ;
        x = x->next;
    }
    x = calloc(1,sizeof(FILELIST));
    memset(x, 0, sizeof(*x));
    if (x)
    {
        FILELIST **y = p;
        int i;
        HTREEITEM item = TVI_FIRST;
        
        while (*y)
        {
            if (stricmp((*y)->title, title) > 0)
                break;
            item = (*y)->treeHandle;
            y = &(*y)->next;
        }
        x->next = (*y);

        *y = x;
        strcpy(x->name, name);
        strcpy(x->title, title);
        x->parent = l ;
        x->treeHandle = TVInitInsert(treeWindow, treeHandle, 
            item, x->title, TRUE, treeFile, x);
    }
}

static int inList(HTREEITEM item, FILELIST *l)
{
    while (l)
    {
        if (l->treeHandle == item)
            return TRUE ;
        l = l->next;
    }
    return FALSE;
}
//-------------------------------------------------------------------------

void ProjectAddFile(HTREEITEM item)
{
    TREEDATA *data = getTreeData(item);
    if (hwndProject && data && data->t_type != treeDepend)
    {
        OPENFILENAME ofn;
        if (OpenFileDialog(&ofn, 0, hwndProject, FALSE, TRUE, szSourceFilter, 
            "Select Source Files"))
        {
            char *q = ofn.lpstrFile;
            char path[256];
            char filename[256],  *r;
            PROJLIST *p ;
            FILELIST **l;
            HTREEITEM handle ;
            if (data->t_type == treeProject)
            {
                p = data->x.project;
            }
            else
                p = data->x.file->parent;
            if (item == p->sourceTreeHandle || inList(item, p->sourceFiles))
            {
                l = &p->sourceFiles;
                handle = p->sourceTreeHandle;
            }
            else if (item == p->resourceTreeHandle || inList(item, p->resourceFiles))
            {
                l = &p->resourceFiles;
                handle = p->resourceTreeHandle;
            }
            else if (item == p->otherTreeHandle || inList(item, p->otherFiles))
            {
                l = &p->otherFiles;
                handle = p->otherTreeHandle;
            }
            else
                return ;
            changedProject = TRUE;
			p->changed = TRUE;
            strcpy(path, q);
            q = q + strlen(q) + 1;
            if (*q)
            {
                while (*q)
                {
                    sprintf(filename, "%s\\%s", path, q);
                    AddFileInternal(handle, p, l, filename, q);
                    q = q + strlen(q) + 1;
                }
            }
            else
            {
                r = strrchr(path, '\\');
                if (!r)
                    r = path;
                else
                    r++;
                AddFileInternal(handle, p, l, path, r);
            }
        }
    }
}

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

void ProjectInsertTarget(HTREEITEM item, char *name)
{
    if (hwndProject)
    {
        OPENFILENAME ofn;
		char buf1[256],buf2[256];
        TREEDATA *data = getTreeData(item);
        char buf[512],  *q;
		if (data && data->t_type == treeWorkspace)
			data = 0;
        else if (data && data->t_type != treeProject)
            return ;

		if (name)
		{
			char *p ;
			ofn.lpstrFile = buf1; 
			ofn.lpstrFileTitle = buf2;
			strcpy(ofn.lpstrFile, name);
			p = strrchr(name, '\\');
			if (p)
				strcpy(ofn.lpstrFileTitle, p+1);
			else
				strcpy(ofn.lpstrFile, name);
		}
			
        if (name || OpenFileDialog(&ofn, 0, hwndProject, TRUE, FALSE, szProjectFilter, 
            "Select Target to Insert"))
        {

            PROJLIST *x = projectList, **y = 0, **z = &projectList;
            PROJLIST **z1 = (PROJLIST **)-1;
            char *names[2] ;
            names[0] = ofn.lpstrFile ;
            names[1] = 0 ;
            while (*z)
            {
                if (!xstricmp((*z)->projectName, ofn.lpstrFile))
                    return ;
                if (data && (*z) == data->x.project)
                    y = z1 ;
                z1 = z ;
                z = &(*z)->next;
            }
            x = ProjectLoadList(names) ;
            if (x)
            {
                int rootproj = FALSE;
                PROJLIST *p;
                changedProject = !defaultWorkspace;
                strcpy(x->name, ofn.lpstrFile);
				// get rid of target extension
				if (!stricmp(x->name + strlen(x->name)-4, ".ctg"))
					x->name[strlen(x->name)-4] = 0;
                if (!projectList)
                {
                    projectList = x;
                }
                else
                {
                    if (!y)
                    {
                        y = &projectList;
                        while (*y)
                            y = &(*y)->next;
                    }
                    if (y == (PROJLIST **)-1)
                    {
                        x->next = projectList ;
                        projectList = x ;
                    }
                    else
                    {
                        x->next = (*y);
                        (*y) = x ;
                    }
                }
                InitItems(treeWindow, projectList);
            }
        }
    }
}

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

void ProjectNewTarget(HTREEITEM item)
{
    if (hwndProject)
    {
        OPENFILENAME ofn;
        TREEDATA *data = getTreeData(item);
        char buf[512],  *q;

        if (OpenFileDialog(&ofn, 0, hwndProject, TRUE, FALSE, szTargetFilter, 
            "Select Target Name"))
        {

            PROJLIST *x = projectList, **y = 0, **z = &projectList;
            PROJLIST **z1 = (PROJLIST **)-1;
            if (!strchr(ofn.lpstrFile, '.'))
            {
                strcat(ofn.lpstrFile, ".exe");
                strcat(ofn.lpstrFileTitle, ".exe");
            }
            while (*z)
            {
                if (!xstricmp((*z)->name, ofn.lpstrFile))
                    return ;
                if (data && (*z) == data->x.project)
                    y = z1 ;
                z1 = z ;
                z = &(*z)->next;
            }
            x = calloc(1,sizeof(PROJLIST));
            memset(x, 0, sizeof(*x));
            if (x)
            {
                int rootproj = FALSE;
                PROJLIST *p;
                changedProject = TRUE;
				x->changed = TRUE;
                strcpy(x->name, ofn.lpstrFile);
                strcpy(x->title, ofn.lpstrFileTitle);
                strcpy(x->projectName, x->name);
                strcat(x->projectName,".ctg");
                if (!projectList)
                {
                    rootproj = TRUE;
                    projectList = x;
                    x->treeHandle = TVInitInsert(treeWindow, projectRoot,
                        TVI_FIRST, ofn.lpstrFileTitle, FALSE, treeProject, x);
                }
                else
                {
                    if (!y)
                    {
                        y = &projectList;
                        while (*y)
                            y = &(*y)->next;
                    }
                    x->treeHandle = TVInitInsert(treeWindow, projectRoot, 
                        y == (PROJLIST **)-1 ? TVI_FIRST : *y == 0 ? TVI_LAST : (*y)->treeHandle, 
                        ofn.lpstrFileTitle, FALSE, treeProject, x);
                    if (y == (PROJLIST **)-1)
                    {
                        x->next = projectList ;
                        projectList = x ;
                    }
                    else
                    {
                        x->next = (*y);
                        (*y) = x ;
                    }
                }
                TreeView_Expand(treeWindow, projectRoot, TVE_EXPAND);
                x->sourceTreeHandle = TVInitInsert(treeWindow, x->treeHandle,
                    TVI_FIRST, "Source Files", FALSE, treeProject, x);
                x->includeTreeHandle = TVInitInsert(treeWindow, x->treeHandle,
                    x->sourceTreeHandle, "Include Files", FALSE, treeProject, x);
                x->resourceTreeHandle = TVInitInsert(treeWindow, x->treeHandle,
                    x->includeTreeHandle, "Resource Files", FALSE, treeProject, x);
                x->otherTreeHandle = TVInitInsert(treeWindow, x->treeHandle,
                    x->resourceTreeHandle, "Other Files", FALSE, treeProject, x);
                if (lstrlen(x->name) > 4)
                    if (!xstricmpz(".dll", x->name + lstrlen(x->name) - 4))
					{
                        x->buildType = BT_DLL;
						x->buildFlags = BF_C99;
					}
                    else if (!xstricmpz(".lib", x->name + lstrlen(x->name) - 4))
					{
                        x->buildType = BT_LIBRARY;
						x->buildFlags = BF_C99;
					}
                    else
                {
                    x->buildType = BT_CONSOLE;
                    x->buildFlags = BF_DEBUGTOOLTIPS | BF_SHOWRETURNCODE |
                        BF_DEBUGINFO | BF_DEBUGEXCEPTION | BF_C99;
                }
                x->dbgview = 1 << DID_WATCHWND;
                x->defineFlags = 0; // DEFINE_TONASM ;
            }
        }
    }
}

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

void DeleteDepends(DEPENDSLIST *l)
{
    while (l)
    {
        DEPENDSLIST *n = l->next;
        //      if (l->treeHandle)
        //         TreeView_DeleteItem(treeWindow,l->treeHandle) ;
        free(l);
        l = n;
    }
}

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

void DeleteFiles(FILELIST *l)
{
    while (l)
    {
        FILELIST *n = l->next;
        DeleteDepends(l->depends);
        if (l->treeHandle)
            TreeView_DeleteItem(treeWindow, l->treeHandle);
        free(l);
        l = n;
    }
}

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

void ProjectDeleteFile(HTREEITEM item)
{
    if (hwndProject)
    {
        int i;
        FILELIST **y, *x ;
        TREEDATA *data = getTreeData(item);
        PROJLIST *p;
        if (!data || data->t_type != treeFile)
            return ;
        p = data->x.file->parent;
        if (inList(item, p->sourceFiles))
            y = & p->sourceFiles ;
        else if (inList(item, p->resourceFiles))
            y = & p->resourceFiles ;
        else if (inList(item, p->otherFiles))
            y = & p->otherFiles ;
        else 
            return ;
        while (*y && (**y).treeHandle != item)
            y = &(*y)->next;
        if (*y)
        {
            x =  *y;
            *y = (*y)->next;
            changedProject = TRUE;
			p->changed = TRUE;
            DeleteDepends(x->depends);
            TreeView_DeleteItem(treeWindow, x->treeHandle);
            free(x);
        }
    }
}

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

void ProjectDeleteDefines(DEFINES *defines)
{
    while (defines)
    {
        DEFINES *y = defines->next;
        free(defines);
        defines = y;
    }
}

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

void ProjectDeleteTarget(HTREEITEM item)
{
    if (hwndProject)
    {
        int i;
        PROJLIST **y = &projectList,  *x;
        TREEDATA *data = getTreeData(item);
        if (data && data->t_type == treeProject) {
            while (*y &&  *y != data->x.project)
                y = &(*y)->next;
            x =  *y;
            *y = (*y)->next;
			changedProject = TRUE;
			if (selectedItem == x->treeHandle)
				selectedItem = 0;
            DeleteFiles(x->sourceFiles);
            DeleteFiles(x->resourceFiles);
            DeleteFiles(x->otherFiles);
            TreeView_DeleteItem(treeWindow, x->treeHandle);
            ProjectDeleteDefines(x->defines);
            free(x);
        }
    }
}

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

void ProjectFreeList(void)
{
    TagEraseAllEntries();
    hbpInit();
    while (projectList)
    {
        PROJLIST *temp = projectList->next;
        ProjectDeleteTarget(projectList->treeHandle);
        projectList = temp;
    }
    changedProject = FALSE;
    #ifdef HBREAK
        hbpInit();
    #endif 
    SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
	DeleteAllItems(); // empty the watch window
}

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

void ProjectNewList(PROJLIST *list)
{    
    ProjectFreeList(); // safety
    projectList = list;
    InitItems(treeWindow, projectList);
    SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
    changedProject = FALSE;
}

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

static void sortDepends(DEPENDSLIST **aa, int count)
{
    int i, j;
    for (i = 0; i < count - 1; i++)
        for (j = i + 1; j < count; j++)
    if (stricmp(aa[i]->title, aa[j]->title) > 0)
    {
        DEPENDSLIST *l = aa[i];
        aa[i] = aa[j];
        aa[j] = l;
    }
}

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

void RefreshDepends(HWND hTree, PROJLIST *projlist)
{
    PROJLIST *l = projlist;
    DEPENDSLIST **aa = (DEPENDSLIST **)calloc(1,1024 *sizeof(DEPENDSLIST*));
    int max = 256, count = 0;
    int i = 0;
    HTREEITEM h = TVI_FIRST;
    if (l->includeTreeHandle)
        TreeView_DeleteItem(treeWindow, l->includeTreeHandle);
    l->includeTreeHandle = TVInitInsert(treeWindow, l->treeHandle, l
        ->sourceTreeHandle, "Include Files", FALSE, treeProject, l);
    if (!aa)
        return ;
    {
        FILELIST *m = l->sourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            while (n)
            {

                if (count == max)
                {
                    max += 256;
                    aa = realloc(aa, max *sizeof(DEPENDSLIST*));
                    if (!aa)
                        return ;
                }
                aa[count++] = n;
                n = n->next;
            }
            m = m->next;
        }
    }
    sortDepends(aa, count);
    for (i = 0; i < count; i++)
    {
        if (i && !stricmp(aa[i]->name, aa[i - 1]->name))
            aa[i]->treeHandle = aa[i - 1]->treeHandle;
        else
            h = aa[i]->treeHandle = TVInitInsert(treeWindow, l
                ->includeTreeHandle, h, aa[i]->title, FALSE, treeDepend, aa[i]);
    }

    free(aa);
}

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

static void InitItems(HWND hTree, PROJLIST *projlist)
{
    PROJLIST *l = projlist;
    int i = 0;
    HTREEITEM h = TVI_FIRST;
	WaitForSingleObject(initSem, INFINITE);
    TreeView_DeleteAllItems(hTree);
    SetWorkspaceWindowTitles();
    while (l)
    {
        int j = 0;
        FILELIST *m = l->sourceFiles;
        h = l->treeHandle = TVInitInsert(hTree, projectRoot, h, l->title, FALSE, treeProject, l);
        l->sourceTreeHandle = TVInitInsert(hTree, l->treeHandle, TVI_FIRST, 
            "Source Files", FALSE, treeProject, l);
        l->includeTreeHandle = TVInitInsert(hTree, l->treeHandle, l
            ->sourceTreeHandle, "Include Files", FALSE, treeProject, l);
        l->resourceTreeHandle = TVInitInsert(treeWindow, l->treeHandle,
            l->includeTreeHandle, "Resource Files", FALSE, treeProject, l);
        l->otherTreeHandle = TVInitInsert(treeWindow, l->treeHandle,
            l->resourceTreeHandle, "Other Files", FALSE, treeProject, l);
        m = l->sourceFiles ;
        while (m)
        {
            HTREEITEM k = TVI_FIRST;
	        FILELIST *y = l->sourceFiles;
    	    int i;
        
	        while (y)
	        {
	            if (stricmp((y)->title, m->title) > 0)
	                break;
	            k = (y)->treeHandle;
	            y = (y)->next;
	        }
            m->treeHandle = TVInitInsert(hTree, l->sourceTreeHandle, k, m
                ->title, FALSE, treeFile, m);
            m = m->next;
        }
        m = l->resourceFiles ;
        while (m)
        {
            HTREEITEM k = TVI_FIRST;
	        FILELIST *y = l->resourceFiles;
    	    int i;
        
	        while (y)
	        {
	            if (stricmp((y)->name, m->name) > 0)
	                break;
	            k = (y)->treeHandle;
	            y = (y)->next;
	        }
            m->treeHandle = TVInitInsert(hTree, l->resourceTreeHandle, k, m
                ->title, FALSE, treeFile, m);
            m = m->next;
        }
        m = l->otherFiles ;
        while (m)
        {
            HTREEITEM k = TVI_FIRST;
	        FILELIST *y = l->otherFiles;
    	    int i;
        
	        while (y)
	        {
	            if (stricmp((y)->name, m->name) > 0)
	                break;
	            k = (y)->treeHandle;
	            y = (y)->next;
	        }
            m->treeHandle = TVInitInsert(hTree, l->otherTreeHandle, k, m
                ->title, FALSE, treeFile, m);
            m = m->next;
        }
        RefreshDepends(hTree, l);
		if (l->treeOpenFlags)
		{
			if (l->treeOpenFlags & TFO_SOURCE)
			{
				CollapseExpand(hTree, l->sourceTreeHandle, TVE_EXPAND);
			}
			if (l->treeOpenFlags & TFO_INCLUDE)
			{
				CollapseExpand(hTree, l->includeTreeHandle, TVE_EXPAND);
			}
			if (l->treeOpenFlags & TFO_RESOURCE)
			{
				CollapseExpand(hTree, l->resourceTreeHandle, TVE_EXPAND);
			}
			if (l->treeOpenFlags & TFO_OTHER)
			{
				CollapseExpand(hTree, l->otherTreeHandle, TVE_EXPAND);
			}
			if (l->treeOpenFlags & TFO_MAIN)
			{
				CollapseExpand(hTree, l->treeHandle, TVE_EXPAND);
			}
		}
        l = l->next;
    }
    TreeView_Expand(hTree, projectRoot, TVE_EXPAND);
	ReleaseSemaphore(initSem, 1, NULL);
}

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

int InsideRect(RECT *r, POINT *q)
{
    if (r->left <= q->x && r->top <= q->y)
    if (r->right > q->x && r->bottom > q->y)
    {
        return TRUE;
    }
    return FALSE;
}

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

HTREEITEM FindItemByWind(HWND hwnd)
{
    PROJLIST *l = projectList;
    DWINFO *info = (DWINFO*)GetWindowLong(hwnd, 0);
    if (!info)
        return 0 ;
    while (l)
    {
        FILELIST *m = l->sourceFiles;
        while (m)
        {
            if (!xstricmpz(m->name, info->dwName))
            {
                return m->treeHandle;
            }
            m = m->next;
        }
        l = l->next;
    }
    return 0;
}

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

HTREEITEM FindItemByPoint(HWND hwnd)
{
    HTREEITEM rv = 0 ;
    RECT q;
    PROJLIST *l = projectList;
    GetCursorPos(&q);
    ScreenToClient(hwnd, &q);
    if (!l)
        return rv;
    while (l)
    {
        int i = 0;
        RECT r;
        FILELIST *m ;
        if (TreeView_GetItemRect(treeWindow, l->treeHandle, &r, 0))
        {
            if (InsideRect(&r, &q))
            {
                return l->treeHandle;
            }
        }
        if (TreeView_GetItemRect(treeWindow, l->sourceTreeHandle, &r, 0))
        {
            if (InsideRect(&r, &q))
            {
                return l->sourceTreeHandle;
            }
        }
        if (TreeView_GetItemRect(treeWindow, l->includeTreeHandle, &r, 0))
        {
            if (InsideRect(&r, &q))
            {
                return l->includeTreeHandle;
            }
        }
        if (TreeView_GetItemRect(treeWindow, l->otherTreeHandle, &r, 0))
        {
            if (InsideRect(&r, &q))
            {
                return l->otherTreeHandle;
            }
        }
        if (TreeView_GetItemRect(treeWindow, l->resourceTreeHandle, &r, 0))
        {
            if (InsideRect(&r, &q))
            {
                return l->resourceTreeHandle;
            }
        }
        m = l->sourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            if (TreeView_GetItemRect(treeWindow, m->treeHandle, &r, 0))
            {
                if (InsideRect(&r, &q))
                {
                    return m->treeHandle;
                }
            }
            while (n)
            {
                if (TreeView_GetItemRect(treeWindow, n->treeHandle, &r, 0))
                {
                    if (InsideRect(&r, &q))
                    {
                        return n->treeHandle;
                    }
                }
                n = n->next;
            }
            m = m->next;
        }
        m = l->resourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            if (TreeView_GetItemRect(treeWindow, m->treeHandle, &r, 0))
            {
                if (InsideRect(&r, &q))
                {
                    return m->treeHandle;
                }
            }
            while (n)
            {
                if (TreeView_GetItemRect(treeWindow, n->treeHandle, &r, 0))
                {
                    if (InsideRect(&r, &q))
                    {
                        return n->treeHandle;
                    }
                }
                n = n->next;
            }
            m = m->next;
        }
        m = l->otherFiles;
        while (m)
        {
            if (TreeView_GetItemRect(treeWindow, m->treeHandle, &r, 0))
            {
                if (InsideRect(&r, &q))
                {
                    return m->treeHandle;
                }
            }
            m = m->next;
        }
        l = l->next;
    }

}

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

PROJLIST *ProjectFindSelectedEXE(HTREEITEM *item)
{
    PROJLIST *l = projectList;
    if (!l)
        return 0;

	if (!l->next)
		return l;
		        
    if (!item)
    {
        item = selectedItem ;
    } 
    {
        TREEDATA *td = getTreeData(item);
        if (td)
        {
            switch(td->t_type)
            {
                case treeProject:
                    return td->x.project;
                case treeFile:
                    return td->x.file->parent;
                case treeDepend:
                    return td->x.depend->parent;
                default:
                    return 0;
            }
        }
    }
    return 0;
}

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

void CollapseExpand(HWND wnd, HTREEITEM item, int flag)
{
    if (item)
    {
        PROJLIST *selectedProj = ProjectFindSelectedEXE(item);
        if (item == selectedProj->sourceTreeHandle)
        {
            TreeView_Expand(treeWindow, selectedProj->sourceTreeHandle, flag);
        }
        else if (item == selectedProj->includeTreeHandle)
        {
            TreeView_Expand(treeWindow, selectedProj->includeTreeHandle, flag);
        }
        else if (item == selectedProj->resourceTreeHandle)
        {
            TreeView_Expand(treeWindow, selectedProj->resourceTreeHandle, flag);
        }
        else if (item == selectedProj->otherTreeHandle)
        {
            TreeView_Expand(treeWindow, selectedProj->otherTreeHandle, flag);
        }
        else if (item == selectedProj->treeHandle)
        {
            TreeView_Expand(treeWindow, selectedProj->treeHandle, flag);
        }
        else
        {
            TREEDATA *data = getTreeData(item);
            if (data && data->t_type == treeFile && data->x.file->depends)
                TreeView_Expand(treeWindow, data->x.file->treeHandle, flag);
        }
        {
            NM_TREEVIEW xx;
            xx.action = flag;
            xx.itemNew.hItem = item;
            SendMessage(wnd, WM_NOTIFY, TVN_ITEMEXPANDED, (LPARAM)&xx); 
        }
    }
}

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

LRESULT CALLBACK _export ProjectProc(HWND hwnd, UINT iMessage, WPARAM wParam,
    LPARAM lParam)
{
    int i;
    PROJLIST *l;
    RECT rs,  *rt;
    PROJLIST *tp;
    NM_TREEVIEW *nm;
    FILELIST *list;
    DWINFO info;
    HMENU menu, popup;
    POINT pos;
    char buf[256];
    OPENFILENAME ofn;
    LPNMTVKEYDOWN key;
    TREEDATA *data;
    switch (iMessage)
    {
        case WM_SYSCOMMAND:
            if (wParam == SC_CLOSE)
                SendMessage(hwnd, WM_CLOSE, 0, 0);
            break;
        case WM_SETTEXT:
            return SendMessage(hwndTab, iMessage, wParam, lParam);
        case WM_LBUTTONDOWN:
        case WM_RBUTTONDOWN:
            SetFocus(hwnd);
            break;
        case WM_NOTIFY:
            nm = (NM_TREEVIEW*)lParam;
            switch (nm->hdr.code)
            {
            case TVN_KEYDOWN:
                key = (LPNMTVKEYDOWN)lParam;
                switch (key->wVKey)
                {
                case VK_INSERT:
                    if (GetKeyState(VK_CONTROL) &0x80000000)
                        CollapseExpand(hwnd, selectedItem, TVE_EXPAND);
                    else if (!(GetKeyState(VK_SHIFT) &0x8000000))
                    {
                        data = getTreeData(selectedItem);
                        if (data && data->t_type == treeFile)
                        {
                            PostMessage(hwnd, WM_COMMAND, IDM_ADDFILES, 0);
                        }
                        else if (data && data->t_type == treeProject && data->x.project->treeHandle == selectedItem)
                        {
                            PostMessage(hwnd, WM_COMMAND, IDM_NEWPROJECT, 0);
                        }
                    }
                    break;
                case VK_DELETE:
                    if (GetKeyState(VK_CONTROL) &0x80000000)
                        CollapseExpand(hwnd, selectedItem, TVE_COLLAPSE)
                            ;
                    else if (!(GetKeyState(VK_SHIFT) &0x8000000))
                    {
                        data = getTreeData(selectedItem);
                        if (data && data->t_type == treeFile)
                        {
                            PostMessage(hwnd, WM_COMMAND, IDM_REMOVEFILES,
                                    0);
                        }
                        else if (data && data->t_type == treeProject && data->x.project->treeHandle == selectedItem)
                        {
                            if (ExtendedMessageBox("Remove Target", MB_YESNO, 
                                "Remove the selected target?") == IDYES)
                                PostMessage(hwnd, WM_COMMAND, IDM_REMOVETARGET,
                                    0);
                        }
                    }
                    break;
                case VK_RETURN:
                    data = getTreeData(selectedItem);
                    if (data && data->t_type != treeProject)
                        SendMessage(hwnd, WM_COMMAND, IDM_OPENFILES, 0);
                    break;
                }
                break;
            case NM_DBLCLK:
                selectedItem = FindItemByPoint(hwnd);
                if (selectedItem == 0)
                    break;
                PostMessage(hwnd, WM_COMMAND, IDM_OPENFILES, 0);
                return 0;
            case NM_RCLICK:
                selectedItem = FindItemByPoint(hwnd) ;
				
                if (selectedItem)
                    TreeView_SelectItem(treeWindow, selectedItem);
                if (selectedItem == projectRoot)
                    break ;
                menu = LoadMenu(hInstance, "PROJECTMENU");
                popup = GetSubMenu(menu, 0);
                data = getTreeData(selectedItem);
                if (!data)
                {
					EnableMenuItem(menu, IDM_STARTDEBUGGING, MF_GRAYED);
                    EnableMenuItem(menu, IDM_OPENFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVETARGET, MF_GRAYED);
                    EnableMenuItem(menu, IDM_ADDFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVEFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_COMPILEVIAPROJ, MF_GRAYED);
                    EnableMenuItem(menu, IDM_CALCDEPENDS, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVETARGET, MF_GRAYED);
                    EnableMenuItem(menu, IDM_BUILDSELECTED, MF_GRAYED);
//                    EnableMenuItem(menu, IDM_PROJECTPROPERTIES, MF_GRAYED);
                }
                else if (data->t_type == treeProject && data->x.project->treeHandle == selectedItem)
                {
                    EnableMenuItem(menu, IDM_ADDFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVEFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_OPENFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_COMPILEVIAPROJ, MF_GRAYED);
                }
                else if (data->t_type == treeProject && data->x.project->otherTreeHandle == selectedItem)
                {
                    EnableMenuItem(menu, IDM_OPENFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVEFILES, MF_GRAYED);
//                    EnableMenuItem(menu, IDM_PROJECTPROPERTIES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_CALCDEPENDS, MF_GRAYED);
                    EnableMenuItem(menu, IDM_NEWPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_INSERTPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVETARGET, MF_GRAYED);
                    EnableMenuItem(menu, IDM_COMPILEVIAPROJ, MF_GRAYED);
                    EnableMenuItem(menu, IDM_BUILDALL, MF_GRAYED);
                    EnableMenuItem(menu, IDM_BUILDSELECTED, MF_GRAYED);
                    EnableMenuItem(menu, IDM_MAKE, MF_GRAYED);
                }
                else if (data->t_type == treeProject && data->x.project->includeTreeHandle != selectedItem)
                {
                    EnableMenuItem(menu, IDM_OPENFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVEFILES, MF_GRAYED);
//                    EnableMenuItem(menu, IDM_PROJECTPROPERTIES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_CALCDEPENDS, MF_GRAYED);
                    EnableMenuItem(menu, IDM_NEWPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_INSERTPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVETARGET, MF_GRAYED);
                    EnableMenuItem(menu, IDM_COMPILEVIAPROJ, MF_GRAYED);
                }
                else if (data->t_type == treeProject && data->x.project->includeTreeHandle == selectedItem)
                {
                    EnableMenuItem(menu, IDM_NEWPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_INSERTPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_OPENFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVETARGET, MF_GRAYED);
                    EnableMenuItem(menu, IDM_ADDFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVEFILES, MF_GRAYED);
                    EnableMenuItem(menu, IDM_COMPILEVIAPROJ, MF_GRAYED);
//                    EnableMenuItem(menu, IDM_PROJECTPROPERTIES, MF_GRAYED);
                }
                else
                {
                    EnableMenuItem(menu, IDM_CALCDEPENDS, MF_GRAYED);
                    EnableMenuItem(menu, IDM_NEWPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_INSERTPROJECT, MF_GRAYED);
                    EnableMenuItem(menu, IDM_REMOVETARGET, MF_GRAYED);
//                    EnableMenuItem(menu, IDM_PROJECTPROPERTIES, MF_GRAYED);
                    if (data->t_type == treeDepend)
                    {
                        EnableMenuItem(menu, IDM_ADDFILES, MF_GRAYED);
                        EnableMenuItem(menu, IDM_REMOVEFILES, MF_GRAYED);
                    }
                    if (!inList(selectedItem, data->x.file->parent->sourceFiles) &&
                        !inList(selectedItem, data->x.file->parent->resourceFiles))
                        EnableMenuItem(menu, IDM_COMPILEVIAPROJ, MF_GRAYED);
                }
                GetCursorPos(&pos);
				InsertBitmapsInMenu(popup);
                TrackPopupMenuEx(popup, TPM_BOTTOMALIGN | TPM_LEFTBUTTON, pos.x,
                    pos.y, hwndFrame, NULL);
                DestroyMenu(menu);
                break;
            case TVN_SELCHANGED:
                nm = (NM_TREEVIEW*)lParam;
                selectedItem = nm->itemNew.hItem;
                break;
            case TVN_ITEMEXPANDED:
                nm = (NM_TREEVIEW *)lParam;
                data = getTreeData(nm->itemNew.hItem);
                if (data && data->t_type == treeProject)
                {
                    int mode = 0;
                    if (data->x.project->treeHandle == nm->itemNew.hItem)
                        mode = TFO_MAIN;
                    else if (data->x.project->sourceTreeHandle == nm->itemNew.hItem)
                        mode = TFO_SOURCE;
                    else if (data->x.project->includeTreeHandle == nm->itemNew.hItem)
                        mode = TFO_INCLUDE;
                    else if (data->x.project->resourceTreeHandle == nm->itemNew.hItem)
                        mode = TFO_RESOURCE;
                    else if (data->x.project->otherTreeHandle == nm->itemNew.hItem)
                        mode = TFO_OTHER;
                    if (mode)
                    {
						if (mode != TFO_MAIN)
						{
							TV_ITEM setitem;
							memset(&setitem, 0, sizeof(setitem));
							setitem.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
							setitem.iImage = setitem.iSelectedImage = 
								nm->action == TVE_EXPAND ? ilfolderOpen : ilfolderClose;
							setitem.hItem = nm->itemNew.hItem;
							TreeView_SetItem(treeWindow, &setitem);
						}
                        if (nm->action == TVE_EXPAND)
                            data->x.project->treeOpenFlags |= mode ;
                        else
                            data->x.project->treeOpenFlags &= ~mode ;
						return 0;
                    }
                }
                break;
            case TVN_DELETEITEM:
                nm = (NM_TREEVIEW *)lParam;
                if (nm->itemOld.hItem == selectedItem)
                    selectedItem = 0;
                free((void *)nm->itemOld.lParam);
                break;
            }
            break;
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
			case IDM_DOSWINDOW:
			{
				PROJLIST *proj = projectList;
                if (selectedItem != 0)
					
                    proj = ProjectFindSelectedEXE(selectedItem);
                DosWindow(proj->name, NULL, NULL, NULL, NULL);
			}
				break;
			case IDM_MAKEWINDOW:
			{
                char exec[MAX_PATH];
				PROJLIST *proj = projectList;
                if (selectedItem != 0)
					
                    proj = ProjectFindSelectedEXE(selectedItem);
                sprintf(exec, "%s\\bin\\imake.exe", szInstallPath);
                DosWindow(proj->name, exec, "", "Custom Make", "Make Is Complete.");
			}
				break;
			case IDM_STARTDEBUGGING:
				SendMessage(hwndFrame, iMessage, wParam, lParam);
				break;
            case IDM_CALCDEPENDS:
				data = getTreeData(selectedItem);
				if (data && data->t_type == treeProject)
				{
	                CalcDepends(treeWindow, data->x.project);
				}
                break;
            case IDM_ADDFILES:
                ProjectAddFile(selectedItem);
                SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
                break;
            case IDM_REMOVEFILES:
                ProjectDeleteFile(selectedItem);
                SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
                break;
            case IDM_INSERTPROJECT:
                ProjectInsertTarget(selectedItem, 0);
                SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
                break ;
            case IDM_NEWWS:
                dmgrHideWindow(DID_TABWND, FALSE);
                NewWorkspace();
                break;
            case IDM_OPENWS:
                if (uState != notDebugging)
                {
                    if (ExtendedMessageBox("Workspace", MB_YESNO, 
                        "Workspace Open requires the debugger be stopped.\r\nStop the debugger now?") != IDYES)
                    {
                        break;
                    }
                    abortDebug();
                }
                dmgrHideWindow(DID_TABWND, FALSE);
                OpenWorkspace(0);
                break;
            case IDM_CLOSEWS:
                if (!projectList || making)
                    break;
                if (uState != notDebugging)
                {
                    if (ExtendedMessageBox("Workspace", MB_YESNO, 
                        "Workspace Close requires the debugger be stopped.\r\nStop the debugger now?") != IDYES)
                    {
                        break;
                    }
                    abortDebug();
                }
                CloseWorkspace();
                break;
            case IDM_SAVEWS:
                if (!projectList)
                    break;
                if (QuerySaveAll() == IDCANCEL)
                    ExtendedMessageBox("Canceled", MB_SETFOREGROUND |
                        MB_SYSTEMMODAL, "Workspace Not Saved");
                else
                {
                    SaveCurrentWorkspace();
                }
                break;
            case IDM_NEWPROJECT:
                ProjectNewTarget(selectedItem);
                SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
                break;
            case IDM_REMOVETARGET:
                ProjectDeleteTarget(selectedItem);
                SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
                break;
            case IDM_COMPILEVIAPROJ:
                data = getTreeData(selectedItem);
                if (data)
                {
                    Compiler(data);
                    CheckEditWindowChanged();
                }                    
                break;
            case IDM_GENMAKE:
                if (projectList && projectList->sourceFiles)
                {
                    genMakeFile(projectList);
                }
                else
                    ExtendedMessageBox("Makefile Generation", MB_SETFOREGROUND |
                        MB_SYSTEMMODAL, 
                        "You need a project with targets and source files to generate a make file");
                break;
            case IDM_STOPBUILD:
            case IDM_BUILDALL:
            case IDM_MAKE:
			case IDM_BUILDSELECTED:
                Maker(LOWORD(wParam));
                break;
			case IDM_RUNNODEBUG:
			{
				PROJLIST *proj = projectList;
                if (selectedItem != 0)
					
                    proj = ProjectFindSelectedEXE(selectedItem);
				RunProgram(proj);
				break;
			}
            case IDM_PROJECTPROPERTIES:
                data = getTreeData(selectedItem);
				if (!data)
					PostMessage(hwndFrame, WM_COMMAND, IDM_GENERALPROPERTIES,0);
                else if (data->t_type == treeProject)
                    TargetProperties(hInstance, hwnd, data->x.project);
				else if (data->t_type == treeFile || data->t_type == treeDepend)
					TargetProperties(hInstance, hwnd, data->x.file->parent);
                break;
            case IDM_OPENFILES:
                doopen: 
                data = getTreeData(selectedItem);
                if (data)
                    if (data->t_type == treeFile)
                    {
                        strcpy(info.dwName, data->x.file->name);
                        strcpy(info.dwTitle, data->x.file->title);
                        info.dwLineNo =  - 1;
                        info.logMRU = FALSE;
						info.newFile = FALSE;
                        CreateDrawWindow(&info, TRUE);
                    }
                    else if (data->t_type == treeDepend)
                    {
                        strcpy(info.dwName, data->x.depend->name);
                        strcpy(info.dwTitle, data->x.depend->title);
                        info.dwLineNo =  - 1;
                        info.logMRU = FALSE;
						info.newFile = FALSE;
                        CreateDrawWindow(&info, TRUE);
                    }
                    
                break;
            case IDM_CLOSE:
                SendMessage(hwnd, WM_CLOSE, 0, 0);
                break;
            default:
                return DefMDIChildProc(hwnd, iMessage, wParam, lParam);
            }
            break;
        case WM_SETFOCUS:
            SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
            break;
        case WM_CREATE:
            hwndProject = hwnd;
            GetClientRect(hwnd, &rs);

            treeViewSelected = 0;
/*
            flh = LoadImage(hInstance, "ID_FLH", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            flasm = LoadImage(hInstance, "ID_FLASM", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            flc = LoadImage(hInstance, "ID_FLC", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            flres = LoadImage(hInstance, "ID_FLRES", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            flfiles = LoadImage(hInstance, "ID_FLFILES", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            fllib = LoadImage(hInstance, "ID_FLLIB", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            fldll = LoadImage(hInstance, "ID_FLDLL", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            flexe = LoadImage(hInstance, "ID_FLEXE", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
            flcws = LoadImage(hInstance, "ID_FLCWS", IMAGE_ICON, 16, 16, LR_LOADTRANSPARENT);
*/
            flh = LoadBitmap(hInstance, "ID_FLH");
            flasm = LoadBitmap(hInstance, "ID_FLASM");
            flc = LoadBitmap(hInstance, "ID_FLC");
            flres = LoadBitmap(hInstance, "ID_FLRES");
            flfiles = LoadBitmap(hInstance, "ID_FLFILES");
            fllib = LoadBitmap(hInstance, "ID_FLLIB");
            fldll = LoadBitmap(hInstance, "ID_FLDLL");
            flexe = LoadBitmap(hInstance, "ID_FLEXE");
            flcws = LoadBitmap(hInstance, "ID_FLCWS");
			folderClose = LoadBitmap(hInstance, "ID_FOLDERCLOSE");
			folderOpen = LoadBitmap(hInstance, "ID_FOLDEROPEN");
            treeIml = ImageList_Create(16, 16, FALSE, 8, 0);
            ilh = ImageList_Add(treeIml, flh, 0);
            ilasm = ImageList_Add(treeIml, flasm, 0);
            ilc = ImageList_Add(treeIml, flc, 0);
            ilres = ImageList_Add(treeIml, flres, 0);
            ilfiles = ImageList_Add(treeIml, flfiles, 0);
            illib = ImageList_Add(treeIml, fllib, 0);
            ildll = ImageList_Add(treeIml, fldll, 0);
            ilexe = ImageList_Add(treeIml, flexe, 0);
            ilcws = ImageList_Add(treeIml, flcws, 0);
            ilfolderClose = ImageList_Add(treeIml, folderClose, 0);
            ilfolderOpen = ImageList_Add(treeIml, folderOpen, 0);
            DeleteObject(flh);
            DeleteObject(flasm);
            DeleteObject(flc);
            DeleteObject(flres);
            DeleteObject(flfiles);
            DeleteObject(fllib);
            DeleteObject(fldll);
            DeleteObject(flexe);
            DeleteObject(flcws);
			DeleteObject(folderClose);
			DeleteObject(folderOpen);
            treeWindow = CreateWindowEx(WS_EX_NOPARENTNOTIFY, WC_TREEVIEW, "", WS_VISIBLE |
                WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS |
                WS_BORDER, 0, 0, rs.right, rs.bottom, hwnd, (HMENU)ID_TREEVIEW,
                hInstance, NULL);
            TreeView_SetImageList(treeWindow, treeIml, TVSIL_NORMAL);
            projFont = CreateFontIndirect(&fontdata);
            SendMessage(treeWindow, WM_SETFONT, (WPARAM)projFont, 1);
            return 0;
        case WM_CLOSE:
            break;
        case WM_DESTROY:
            if (defaultWorkspace)
                CloseAll();
            DestroyWindow(treeWindow);
            DeleteObject(projFont);
            hwndProject = 0;
            ProjectFreeList();
            break;
        case WM_SIZE:
            MoveWindow(treeWindow, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            break;
        default:
            break;
    }
    return DefMDIChildProc(hwnd, iMessage, wParam, lParam);
}

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

void SetWorkspaceWindowTitles(void)
{
        char buf[256];
        sprintf(buf,"Workspace: %s",szWorkspaceTitle);
        projectRoot = TVInitInsert(treeWindow, TVI_ROOT, TVI_FIRST, buf, TRUE, treeWorkspace, 0);
}

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

void SetWorkspaceMRU(void)
{
    DWINFO info;
    if (szWorkspaceName[0])
    {
        strcpy(info.dwName, szWorkspaceName);
        strcpy(info.dwTitle, szWorkspaceTitle);
        InsertMRU(&info, 1);
        MRUToMenu(1);
    }
}

//-------------------------------------------------------------------------
void GetDefaultWorkspaceName(char *buf)
{
	GetUserDataPath(buf);
    strcat(buf,"default.cws");
}
//-------------------------------------------------------------------------

void SaveCurrentWorkspace(void)
{
	if (noworkspace)
		return;
    WaitForSingleObject(projectSem, INFINITE);
                    if (!defaultWorkspace)
                        SaveWorkspace(szWorkspaceName);
                    else 
                    {
                        char buf[MAX_PATH];
				        OPENFILENAME ofn;
					    if (projectList && changedProject && SaveFileDialog(&ofn, 0, hwndProject, TRUE, szWorkspaceFilter, 
					        "New Workspace"))
						{
						    if (!strchr(ofn.lpstrFile, '.'))
						    {
						        strcat(ofn.lpstrFile, ".cws");
						        strcat(ofn.lpstrFileTitle, ".cws");
						    }
	                        SaveWorkspace(ofn.lpstrFile);
							FreeWorkspace();
							{
						        char *p, *name = ofn.lpstrFile ;
						        strcpy(szWorkspaceName, name);
						        p = strrchr(name,'\\');
						        if (p)
						            strcpy(szWorkspaceTitle, p+1);
						        else
						            strcpy(szWorkspaceTitle, name);
							    if (!strchr(szWorkspaceTitle, '.'))
							    {
							        strcat(szWorkspaceName, ".cws");
							        strcat(szWorkspaceTitle, ".cws");
							    }
							    defaultWorkspace = FALSE;
							    RestoreWorkSpace(szWorkspaceName,TRUE);    
					            FreeBrowseInfo();
								FreeJumpSymbols();
								LoadJumpSymbols();
								noworkspace = FALSE;
							    InitItems(treeWindow, projectList);
							    SetWorkspaceMRU();
							}
						}
						else
						{
	                        GetDefaultWorkspaceName(buf);
	                        SaveWorkspace(buf);
						}
                    }
    ReleaseSemaphore(projectSem, 1, 0);
}

int LoadDefaultWorkspace(void)
{
    char buf[MAX_PATH];
	int rv ;
    WaitForSingleObject(projectSem, INFINITE);
    FreeWorkspace();
    defaultWorkspace = TRUE;
    strcpy(szWorkspaceTitle,"Default.cws");
    GetDefaultWorkspaceName(buf);
    rv = RestoreWorkSpace(buf,FALSE);
	noworkspace = FALSE;
    InitItems(treeWindow, projectList);
    FreeBrowseInfo();
	FreeJumpSymbols();
	LoadJumpSymbols();
    ReleaseSemaphore(projectSem, 1, 0);
	return rv ;
}

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

void FreeWorkspace(void)
{
    ProjectFreeList();
    strcpy(szWorkspaceName,"default");
    defaultWorkspace = TRUE ;
    projectRoot = TVI_ROOT ;
}

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

void CloseWorkspace(void)
{
    SaveCurrentWorkspace();
    WaitForSingleObject(projectSem, INFINITE);
    FreeWorkspace();
    ReleaseSemaphore(projectSem, 1, 0);
    LoadDefaultWorkspace();
    SendMessage(hwndTab, WM_CLOSE, 0, 0);
}

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

void OpenWorkspace(char *name)
{
    OPENFILENAME ofn;
    PROJLIST *list = 0;
    RECT rect;
    char buf[256];
    SaveCurrentWorkspace();
    WaitForSingleObject(projectSem, INFINITE);
    FreeWorkspace();
    if (!name) {
        if (!(OpenFileDialog(&ofn, defaultWorkspace ? NULL : szWorkspaceName, hwndClient, TRUE, FALSE, szWorkspaceFilter,
            "Open Workspace"))) 
        {
            ReleaseSemaphore(projectSem, 1, 0);
            return ;
        }
        strcpy(szWorkspaceTitle, ofn.lpstrFileTitle);
        strcpy(szWorkspaceName, ofn.lpstrFile);
    }
    else
    {
        char *p ;
        strcpy(szWorkspaceName, name);
        p = strrchr(name,'\\');
        if (p)
            strcpy(szWorkspaceTitle, p+1);
        else
            strcpy(szWorkspaceTitle, name);
    }
    if (!strchr(szWorkspaceTitle, '.'))
    {
        strcat(szWorkspaceName, ".cws");
        strcat(szWorkspaceTitle, ".cws");
    }

    defaultWorkspace = FALSE;
    RestoreWorkSpace(szWorkspaceName,TRUE);    
    FreeBrowseInfo();
	FreeJumpSymbols();
	LoadJumpSymbols();
	noworkspace = FALSE;
    InitItems(treeWindow, projectList);
    SetWorkspaceMRU();
    ReleaseSemaphore(projectSem, 1, 0);
}

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

void NewWorkspace(void)
{
    OPENFILENAME ofn;
    PROJLIST *list = 0;
    RECT rect;
    char buf[256];
    SaveCurrentWorkspace();

    if (!SaveFileDialog(&ofn, 0, hwndProject, TRUE, szWorkspaceFilter, "New Workspace"))
        return ;
    if (!strchr(ofn.lpstrFile, '.'))
    {
        strcat(ofn.lpstrFile, ".cws");
        strcat(ofn.lpstrFileTitle, ".cws");
    }
    WaitForSingleObject(projectSem, INFINITE);
    FreeWorkspace();
    strcpy(szWorkspaceTitle, ofn.lpstrFileTitle);
    strcpy(szWorkspaceName, ofn.lpstrFile);
    defaultWorkspace = FALSE ;
    InitItems(treeWindow, projectList);
    SetWorkspaceMRU();
    ReleaseSemaphore(projectSem, 1, 0);
}

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

void IndirectProjectThread(DWINFO *info)
{	
    OpenWorkspace(info->dwName);
}

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

void IndirectProjectWindow(DWINFO *info)
{
    DWORD handle;
	MSG msg;
    dmgrHideWindow(DID_TABWND, FALSE);
	IndirectProjectThread(info);
		
 	return;
    CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)
        IndirectProjectThread, (LPVOID)info, 0, &handle));
}

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

void RegisterProjectWindow(void)
{
    WNDCLASS wc;
    memset(&wc, 0, sizeof(wc));
    wc.style = CS_DBLCLKS;
    wc.lpfnWndProc = &ProjectProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = sizeof(void*);
    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 = szProjectClassName;
    RegisterClass(&wc);
	
	initSem = CreateSemaphore(0,1,1,0);
}

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

void CreateProjectWindow(void)
{
    RECT rect;
    HWND parent;
    parent = hwndTabCtrl;
    changedProject = FALSE;
    GetTabRect(&rect);
    hwndProject = CreateWindow(szProjectClassName, szWorkspaceTitle,
        WS_VISIBLE | WS_CHILD, rect.left, rect.top, rect.right - rect.left,
        rect.bottom - rect.top, parent, 0, hInstance, 0);
}

