#include "kant build meat.h"
#include "kant build gui.h"
#include "kant build files.h"
#include "text twiddling.h"
#include "util.h"
#include "graphics.h"
#include "window layer.h"

Str15			gRefLeading="\pÈ  &";
Str15			gRefClosedLeading="\pÇ  &";
Str15			gInstantLeading="\p          ";

static	Boolean			gIsRef;
static	Boolean			gRefClosed;
static	unsigned long	gLastMouseUpTime=0L;
static	unsigned long	gLastMouseDownTime=0L;
static	Boolean			gShouldDoDoubleClick=FALSE;

void DealWithBuildMouseUp(WindowPtr theWindow, Point thePoint)
{
	TEHandle		hTE;
	short			selStart, selEnd, newSelStart;
	short			lineNum;
	unsigned char	thisChar;
	
	gLastMouseUpTime=TickCount();
	
	hTE=GetWindowTE(theWindow);
	
	if (gShouldDoDoubleClick)
	{
		lineNum=CurrentLineNumber(hTE);
		selStart=LineStart(hTE, lineNum);
		selEnd=LineStart(hTE, lineNum+1)-1;
		newSelStart=TEGetOffset(thePoint, hTE);
		thisChar=(*(**hTE).hText)[newSelStart];
		if ((newSelStart==selStart) && (RefHighlightedQQ(theWindow)))
		{
			DealWithArrowClick(theWindow, lineNum);
		}
		else if ((newSelStart>=selStart) && (newSelStart<=selEnd))
		{	/* is double-click */
			if (RefHighlightedQQ(theWindow))
				DoEditRef(theWindow);
			else
				DoEditInstantiation(theWindow);
		}
	}
	gShouldDoDoubleClick=FALSE;
}

void DealWithBuildContentClick(WindowPtr theWindow, Point thePoint)
{
	TEHandle		hTE;
	short			selStart;
	short			lineNum;
	
	gLastMouseDownTime=TickCount();
	if (gLastMouseDownTime-gLastMouseUpTime<=LMGetDoubleTime())
		gShouldDoDoubleClick=TRUE;
	
	hTE=GetWindowTE(theWindow);
	
	selStart=TEGetOffset(thePoint, hTE);
	if (((*(**hTE).hText)[selStart])=='\r')
		selStart--;
	lineNum=LineNumberFromOffset(hTE, selStart);
	if (lineNum!=CurrentLineNumber(hTE))
	{
		HighlightLine(hTE, lineNum);
		gLastMouseUpTime=0L;
		gShouldDoDoubleClick=FALSE;
	}
	
	if ((RefHighlightedQQ(theWindow)) && (selStart==LineStart(hTE, lineNum)))
		DealWithArrowClick(theWindow, lineNum);
}

void DealWithArrowClick(WindowPtr theWindow, short lineNum)
{
	TEHandle		hTE;
	ControlHandle	vScrollBar;
	short			selStart, selEnd;
	Str255			refName;
	Boolean			alreadyOpen;
	unsigned char	firstCharOfLine;
	
	hTE=GetWindowTE(theWindow);
	vScrollBar=GetWindowVScrollBar(theWindow);
	selStart=LineStart(hTE, lineNum);
	firstCharOfLine=(*(**hTE).hText)[selStart];
	alreadyOpen=(firstCharOfLine==gRefLeading[1]);
	if (CurrentLineNumber(hTE)!=lineNum)
		HighlightLine(hTE, lineNum);
	
//	ZapDrawHook(hTE);
	
	if (alreadyOpen)
	{
		selStart=LineStart(hTE, lineNum);
		selEnd=GetNextInstantiationOffset(theWindow);
		TESetSelect(selStart, selStart+1, hTE);
		TEDelete(hTE);
		TEInsert(&gRefClosedLeading[1], 1, hTE);
		selStart=LineStart(hTE, lineNum+1);
		TESetSelect(selStart, selEnd, hTE);
		TEDelete(hTE);
		AdjustForEndScroll(vScrollBar, hTE);
		HighlightLine(hTE, lineNum);
		AdjustVScrollBar(vScrollBar, hTE);
	}
	else
	{
		GetHighlightedString(theWindow, refName);
		selStart=LineStart(hTE, lineNum);
		TESetSelect(selStart, selStart+1, hTE);
		TEDelete(hTE);
		TEInsert(&gRefLeading[1], 1, hTE);
		selStart=LineStart(hTE, lineNum+1);
		TESetSelect(selStart, selStart, hTE);
		AddInstantiationsFromFile(GetWindowFS(theWindow), theWindow, refName);
		AdjustForEndScroll(vScrollBar, hTE);
		HighlightLine(hTE, lineNum);
		AdjustVScrollBar(vScrollBar, hTE);
	}
	
//	RestoreDrawHook(hTE);
	InvalRect(&(theWindow->portRect));
}

void DoShowHideAll(WindowPtr theWindow, Boolean isShow)
{
	TEHandle		hTE;
	short			lineNum;
	short			numLines;
	short			selStart;
	unsigned char	firstCharOfLine;
	unsigned char	charToMatch;
	
	hTE=GetWindowTE(theWindow);
	numLines=TotalNumberOfLines(hTE);
	charToMatch=isShow ? gRefClosedLeading[1] : gRefLeading[1];
	
	lineNum=0;
	while (lineNum<TotalNumberOfLines(hTE))
	/* note that TotalNumberOfLines may change if we hide or show anything */
	{
		selStart=LineStart(hTE, lineNum);
		firstCharOfLine=(*(**hTE).hText)[selStart];
		if (firstCharOfLine==charToMatch)
		{
			DealWithArrowClick(theWindow, lineNum);
			UpdateTheWindow(theWindow);
		}
		lineNum++;
	}
}

void HighlightLine(TEHandle hTE, short lineNum)
{
	short			startOfLine;
	unsigned char	firstCharOfLine;
	
	startOfLine=(**hTE).lineStarts[lineNum];
	firstCharOfLine=(*((**hTE).hText))[startOfLine];
	gIsRef=(firstCharOfLine!=gInstantLeading[1]);
	TESetSelect(startOfLine+(gIsRef ? 3 : 5), (**hTE).lineStarts[lineNum+1], hTE);
	gRefClosed=gIsRef && (firstCharOfLine==gRefClosedLeading[1]);
}

Boolean RefHighlightedQQ(WindowPtr theWindow)
{
	if (theWindow==0L)
		return TRUE;
	
	return (AnyHighlightedQQ(theWindow)) ? gIsRef : TRUE;
}

Boolean RefClosedQQ(WindowPtr theWindow)
{
	if (theWindow==0L)
		return FALSE;
	
	return (AnyHighlightedQQ(theWindow)) ? gRefClosed : FALSE;
}

Boolean AddNameToTE(TEHandle hTE, Str255 theName, Boolean isRef)
/* returns FALSE if no room left to insert */
{
	long			len, leadingLen;
	unsigned char	returnChar='\r';
	
	len=theName[0];
	leadingLen=(isRef ? gRefLeading[0] : gInstantLeading[0]);
	if ((**hTE).teLength+len+leadingLen+1>32767)
		return FALSE;
	
	if (isRef)
		TEInsert(&gRefLeading[1], gRefLeading[0], hTE);
	else
		TEInsert(&gInstantLeading[1], gInstantLeading[0], hTE);
	TEInsert(&theName[1], len, hTE);
	TEInsert(&returnChar, 1, hTE);
	
	return TRUE;
}

short GetNextInstantiationOffset(WindowPtr theWindow)
{
	TEHandle		hTE;
	short			lineNum;
	
	hTE=GetWindowTE(theWindow);
	lineNum=CurrentLineNumber(hTE);
	do {}
	while ((*(**hTE).hText)[(**hTE).lineStarts[++lineNum]]==gInstantLeading[1]);
	
	if (((**hTE).lineStarts[lineNum])==0)
		return (**hTE).teLength;
	
	return (**hTE).lineStarts[lineNum];
}

void GetHighlightedString(WindowPtr theWindow, Str255 theStr)
{
	GetStringFromLine(theWindow, theStr, CurrentLineNumber(GetWindowTE(theWindow)));
}

void GetStringFromLine(WindowPtr theWindow, Str255 theStr, short lineNum)
{
	TEHandle		hTE;
	short			selStart, selEnd;
	Boolean			isRef;
	
	hTE=GetWindowTE(theWindow);
	selStart=(**hTE).lineStarts[lineNum];
	selEnd=(**hTE).lineStarts[lineNum+1]-1;
	isRef=((*(**hTE).hText)[selStart]!=gInstantLeading[1]);
	selStart+=isRef ? gRefLeading[0] : gInstantLeading[0];
	Mymemcpy((Ptr)&theStr[1], (Ptr)((unsigned long)(*(**hTE).hText)+selStart), selEnd-selStart);
	theStr[0]=selEnd-selStart;
}

void GetRefNameFromInstantiation(WindowPtr theWindow, Str255 refName, short *stringIndex)
{
	short			index;
	short			lineNum;
	TEHandle		hTE;
	short			offset;
	unsigned char	firstChar;
	
	hTE=GetWindowTE(theWindow);
	index=0;
	lineNum=CurrentLineNumber(hTE);
	do
	{
		index++;
		offset=(**hTE).lineStarts[--lineNum];
		firstChar=(*((**hTE).hText))[offset];
	}
	while (firstChar==gInstantLeading[1]);
	
	GetStringFromLine(theWindow, refName, lineNum);
	*stringIndex=index;
}
