/* 
CCIDE
Copyright 2001-2006 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 "winconst.h"

extern char szWorkspaceName[];
extern int browseInfo;
extern int changedProject;
extern int defaultWorkspace;

int browsing;

static char **filenames;
static int filecount;
static DWINFO **browsebacklist;
static int browseCount, browseMax;

static int LoadBrowseInfo(FILE *fil)
{
    char buf[12];
    unsigned short count, i;
    fread(buf, 12, 1, fil);
    if (strncmp(buf, "$BRW", 4))
        return 0;
    if (filecount)
        return *(int*)(buf + 4);
    fseek(fil, 32, SEEK_SET);
    fread(&count, 2, 1, fil);
    filecount = count;
    filenames = calloc(count, sizeof(char*));
    if (!filenames)
        return 0;
    for (i = 0; i < count; i++)
    {
        char name[256];
        int len = fgetc(fil);
        fread(name, len, 1, fil);
        name[len] = 0;
        filenames[i] = strdup(name);
        if (!filenames[i])
        {
            for (--i; i >= 0; --i)
            {
                free(filenames[i]);
            }
            free(filenames);
            return 0;
        }
    }

    return *(int*)(buf + 4);
}

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

void FreeBrowseInfo(void)
{
    int i;
    for (i = 0; i < filecount; i++)
        free(filenames[i]);
    free(filenames);
    filenames = 0;
    filecount = 0;
}

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

int FindBrowseInfo(FILE *fil, char *name, int root)
{
    if (*name == 0)
        return 0;
    while (1)
    {
        char buf[128 *9],  *p = buf;
        int count;
        fseek(fil, root, SEEK_SET);
        fread(buf, 128 *9, 1, fil);
        count =  *p++;
        while (count)
        {
            if (*p ==  *name)
            {
                name++;
                if (*name == 0)
                    return *(int*)(p + 5);
                root = *(int*)(p + 1);
                break;
            }
            count--;
            p += 9;
        }
        if (!count)
            return 0;
    }
}

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

static int FindBrowseData(char *filname, int curline, FILE *fil, int ofs, char
    *hint, char *name, int *line, int insertbrowse)
{
    int recsize;
    unsigned char buf[256];
    unsigned char global[256];
    int fileno =  - 1, i;
    int found = FALSE;

    for (i = 0; i < filecount; i++)
    if (!stricmp(filenames[i], filname))
    {
        fileno = i;
        break;
    }
    fseek(fil, ofs, SEEK_SET);
    memset(global, 0, sizeof(global));

    while (1)
    {
        if (fread(buf, 2, 1, fil) <= 0)
            return 0;
        if (*(short*)buf == 0)
            break;
        if (fread(buf + 2, (*(short*)buf) - 2, 1, fil) <= 0)
            return 0;
        if (*(int*)(buf + 6) ==  - 1)
        // -1 = global
            memcpy(global, buf, *(short*)buf);
        if (*(int*)(buf + 10) != fileno)
            continue;
        if (*(int*)(buf + 6) !=  - 1)
            if (*(int*)(buf + 2) <= curline)
        if (*(int*)(buf + 6) > curline || curline ==  - 2)
        {
            // -2 == static
            found = TRUE;
            break;
        }
    }
    if (!found && global)
    {
        memcpy(buf, global, *(short*)global);
        found = TRUE;
    }
    if (!found)
        return 0;
    // *(short *)(buf+15) == charpos eventually...
    if (hint)
    {
        memcpy(hint, buf + 18, buf[17]);
        hint[buf[17]] = 0;
    }
    if (line && name)
    {
        if (*(int*)(buf + 10) >= filecount)
            return 0;
        strcpy(name, filenames[*(int*)(buf + 10)]);
        *line = *(int*)(buf + 2);
        if (insertbrowse)
        {
            DWINFO *info;
            char *p;
            if (browseCount >= browseMax)
            {
                if (browseCount >= 20)
                {
                    memmove(browsebacklist, browsebacklist + 1, (--browseCount)
                        *sizeof(void*));
                }
                else
                {
                    browsebacklist = realloc(browsebacklist, (browseMax += 20)
                        *sizeof(void*));
                    if (!browsebacklist)
                    {
                        browseMax = 0;
                        return 1;
                    }
                }
            }
            info = calloc(sizeof(DWINFO), 1);
            if (!info)
                return 1;
            strcpy(info->dwName, filname);
            info->dwLineNo = curline;
			info->newFile = FALSE;
            p = strrchr(info->dwName, '\\');
            if (p)
                strcpy(info->dwTitle, p + 1);
            browsebacklist[browseCount++] = info;
        }
    }
    return 1;
}

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

void BrowseTo(HWND hwnd, char *msg)
{
    static char name[256];
    int ofs;
    if (defaultWorkspace)
        return ;
    if (!browsing)
    {
        if (msg)
        {
            strcpy(name, msg);
            browsing = TRUE;
        }
        else
            browsing = SendMessage(hwnd, WM_WORDUNDERCURSOR, 0, (LPARAM)name);
        if (!browseInfo && browsing)
        {
            if (ExtendedMessageBox("Browse Info Alert", MB_YESNO, 
                "Browse information not enabled.  Do you want to adjust the workspace settings and rebuild the targets?") == IDYES)
            {
                browsing = TRUE;
                browseInfo = TRUE;
                changedProject = TRUE;
                Maker(IDM_BUILDALL);
                return ;
            }
            else
            {
                browsing = FALSE;
                return ;
            }
        }
    }
    if (browsing)
    {
        char filename[256];
        FILE *fil;
        DWINFO info;
        charinfo charrange;
        int curline;
        char *filname;
        if (msg)
        {
            curline =  - 2;
            filname = "";
        }
        else
        {
            SendDlgItemMessage(hwnd, ID_EDITCHILD, EM_EXGETSEL, (WPARAM)0, 
                (LPARAM) &charrange);
            curline = SendDlgItemMessage(hwnd, ID_EDITCHILD, EM_EXLINEFROMCHAR,
                0, (LPARAM)charrange.min) + 1;
            filname = (char*)SendMessage(hwnd, WM_FILENAME, 0, 0);
        }
        memset(&info, 0, sizeof(info));
        strcpy(filename, szWorkspaceName);
        strcpy(filename + strlen(filename) - 4, ".BRW");
        fil = fopen(filename, "rb");
        if (!fil)
        {
            return ;
        }
        if (!(ofs = LoadBrowseInfo(fil)))
        {
            fclose(fil);
            return ;
        }
        ofs = FindBrowseInfo(fil, name, ofs);
        if (ofs && FindBrowseData(filname, curline, fil, ofs, 0, &info.dwName,
            &info.dwLineNo, TRUE))
        {
            char *p = strrchr(info.dwName, '\\');
            if (p)
                strcpy(info.dwTitle, p + 1);
            info.logMRU = FALSE;
			info.newFile = FALSE;
            CreateDrawWindow(&info, TRUE);
        }
        fclose(fil);
    }
    browsing = FALSE;
}

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

char *BrowseHint(HWND hwnd)
{
    static char hint[256];
    char *rv = 0;
    char name[256];
    int ofs;
    if (!browseInfo || defaultWorkspace)
        return rv;
    if (SendMessage(hwnd, WM_WORDUNDERCURSOR, 0, (LPARAM)name))
    {
        charinfo charrange;
        int curline;
        char filename[256];
        FILE *fil;
        char *filname = (char*)SendMessage(hwnd, WM_FILENAME, 0, 0);
        SendDlgItemMessage(hwnd, ID_EDITCHILD, EM_EXGETSEL, (WPARAM)0, (LPARAM)
            &charrange);
        curline = SendDlgItemMessage(hwnd, ID_EDITCHILD, EM_EXLINEFROMCHAR, 0, 
            (LPARAM)charrange.min) + 1;
        strcpy(filename, szWorkspaceName);
        strcpy(filename + strlen(filename) - 4, ".BRW");
        fil = fopen(filename, "rb");
        if (!fil)
            return rv;
        if (!(ofs = LoadBrowseInfo(fil)))
        {
            fclose(fil);
            return rv;
        }
        ofs = FindBrowseInfo(fil, name, ofs);
        if (ofs && FindBrowseData(filname, curline, fil, ofs, hint, 0, 0, FALSE)
            )
            rv = hint;
        fclose(fil);
    }
    return rv;
}

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

void BrowseBack(void)
{
    if (!browseCount)
        return ;
    browsebacklist[--browseCount]->logMRU = FALSE;
    CreateDrawWindow(browsebacklist[browseCount], TRUE);
    free(browsebacklist[browseCount]);
}
