/*	TEditDoc.cpp
 *
 *		The document object; this manages the interface between the
 *	document data and the file
 */

/*  XT - An example text editor application built with the YAAF library
 *
 *	PUBLIC DOMAIN: The source kit of 'xt' has been placed into the
 *	public domain by the author, William Edward Woody, on the hope
 *	that the source kit will provide a useful example of using the
 *	YAAF Library.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <string.h>
#include <stdio.h>
#include <XAutoPtr.h>
#include <XDataUtil.h>
#include <XWindow.h>
#include <XApplication.h>

#include "TEditDoc.h"
#include "XOpenDialog.h"

/************************************************************************/
/*																		*/
/*	Globals																*/
/*																		*/
/************************************************************************/

static long GCount = 0;

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

/*	TEditDoc::TEditDoc
 *
 *		Create this thing
 */

TEditDoc::TEditDoc()
{
	fDirty = false;
	if (GCount == 0) {
		strcpy(fName,"untitled");
		GCount++;
	} else {
		sprintf(fName,"untitled %ld",++GCount);
	}
	fFile = NULL;
}

/*	TEditDoc::~TEditDoc
 *
 *		Delete this
 */

TEditDoc::~TEditDoc()
{
	if (fFile) delete fFile;
}

/************************************************************************/
/*																		*/
/*	Construction Support												*/
/*																		*/
/************************************************************************/

/*	TEditDoc::NewDocument
 *
 *		New document routine
 */

TEditDoc *TEditDoc::NewDocument()
{
	autoptr<TEditDoc> doc;
	
	XGDispatch::SetCTorDispatch(XGAppCore::GetApplication());
	doc = new TEditDoc;
	return doc.Return();
}

/*	TEditDoc::OpenDocument
 *
 *		Handle opening a new document
 */

TEditDoc *TEditDoc::OpenDocument()
{
	autoptr<TEditDoc> doc;
	
	XGDispatch::SetCTorDispatch(XGAppCore::GetApplication());
	doc = new TEditDoc;
	if (!doc->DoOpenDialog()) return NULL;
	return doc.Return();
}

#if OPT_MACOS

TEditDoc *TEditDoc::OpenDocument(FSSpec *f)
{
	autoptr<TEditDoc> doc;
	autoptr<TFile> file;
	
	XGDispatch::SetCTorDispatch(XGAppCore::GetApplication());
	doc = new TEditDoc;
	file = new TFile(f);
	doc->fFile = file.Return();
	cvtp2c(doc->fName,f->name);
	doc->DoDocumentRevert();
	return doc.Return();
}

#endif

#if OPT_WINOS || OPT_XWIN

TEditDoc *TEditDoc::OpenDocument(char *f)
{
	autoptr<TEditDoc> doc;
	autoptr<TFile> file;
	char *x,*y;
	
	XGDispatch::SetCTorDispatch(XGAppCore::GetApplication());
	doc = new TEditDoc;
	file = new TFile(f);
	doc->fFile = file.Return();

	y = f;							// pull just the file name
	for (x = f; *x != 0; x++) {
		if ((*x == ':') || (*x == '\\') || (*x == '/')) {
			y = x + 1;
		}
	}
	strcpy(doc->fName,y);

	doc->DoDocumentRevert();
	return doc.Return();
}

#endif

/************************************************************************/
/*																		*/
/*	Document Save/Restore												*/
/*																		*/
/************************************************************************/

/*	TEditDoc::IsDocumentNamed
 *
 *		Is this named?
 */

bool TEditDoc::IsDocumentNamed()
{
	return (fFile != NULL) ? true : false;
}

/*	TEditDoc::IsDocumentDirty
 *
 *		Is this dirty?
 */

bool TEditDoc::IsDocumentDirty()
{
	return fDirty;
}

/*	TEditDoc::GetDocumentName
 *
 *		Get my name
 */

void TEditDoc::GetDocumentName(char *name)
{
	strcpy(name,fName);
}

/*	TEditDoc::DoDocumentSave
 *
 *		Save this thing
 */

bool TEditDoc::DoDocumentSave()
{
	unsigned long len;
	XGHandle h;
	unsigned long i;
	char c;
	
	if (NULL == fFile) return DoDocumentSaveAs();
	
	/*
	 *	This is the save routine
	 */
	
	try {
		/*
		 *	Try to convert the handle in memory
		 */
		
		len = fText.GetSize();
		for (i = 0; i < len; i++) {
			c = fText.GetChar(i);
			if ((c == 0x0D) || (c == 0x0A)) {

#if OPT_MACOS || OPT_WINOS
				c = 0x0D;
				h.Append(1,(void *)&c);
#endif

#if OPT_XWIN || OPT_WINOS
				c = 0x0A;
				h.Append(1,(void *)&c);
#endif
			} else {
				h.Append(1,(void *)&c);
			}
		}

		/*
		 *	Now write the handle
		 */
		
		h.Lock();
		fFile->SetEOF(0);
		fFile->Write((long)h.GetSize(),*h);
		h.Unlock();
	}
	catch (...) {
		/*
		 *	Unable to convert? Write the data directly
		 */
		
		h.SetSize(0);
		len = fText.GetSize();
		for (i = 0; i < len; i++) {
			c = fText.GetChar(i);
			if ((c == 0x0D) || (c == 0x0A)) {

#if OPT_MACOS || OPT_WINOS
				c = 0x0D;
				fFile->Write(1,(void *)&c);
#endif

#if OPT_XWIN || OPT_WINOS
				c = 0x0A;
				fFile->Write(1,(void *)&c);
#endif
			} else {
				fFile->Write(1,(void *)&c);
			}
		}
	}
	
	DocumentSaved();
	fDirty = false;
	return true;
}

/*	TEditDoc::DoDocumentSaveAs
 *
 *		Handle the save as operation
 */

bool TEditDoc::DoDocumentSaveAs()
{
	if (!DoSaveDialog()) return false;
	return DoDocumentSave();
}

/*	TEditDoc::DoDocumentRevert
 *
 *		handle the document revert/document read operation
 */

void TEditDoc::DoDocumentRevert()
{
	long l;
	long x;
	char *t;
	long ptr;
	XGWindow *w;
	
	/*
	 *	Read the file
	 */
	
	l = fFile->GetEOF();
	fText.SetSize((unsigned long)l);
	
	fText.Lock();
	fFile->Read(l,*fText);
	fText.Unlock();
	
	/*
	 *	Now scan forward
	 */
	
	x = 0;
	t = (char *)*fText;
	for (ptr = 0; ptr < l; ptr++) {
		if ((t[ptr] == 0x0D) || (t[ptr] == 0x0A)) {
			if (ptr+1 < l) {
				if (t[ptr+1] != t[ptr]) {
					if ((t[ptr+1] == 0x0D) || (t[ptr+1] == 0x0A)) {
						ptr++;
					}
				}
			}
			t[x++] = '\n';
		} else {
			t[x++] = t[ptr];
		}
	}
	
	if (x < l) fText.SetSize((unsigned long)x);
	
	/*
	 *	And let the forms know that I changed
	 */
	
	l = GetNumAttachWindows();
	for (x = 0; x < l; x++) {
		w = GetAttachedWindow(x);
		w->DoDispatch(KRevertDoc,0,NULL);
	}
	
	/*
	 *	Clear my dirty bit
	 */
	
	fDirty = false;
}

/************************************************************************/
/*																		*/
/*	Dialogs																*/
/*																		*/
/************************************************************************/

/*	TEditDoc::DoOpenDialog
 *
 *		Handle the open dialog. Once open, this fills out and
 *	creates a file object and remembers the name.
 */

bool TEditDoc::DoOpenDialog(void)
{
#if OPT_MACOS
	StandardFileReply reply;
	SFTypeList list;
	TFile *fptr;
	
	/*
	 *	Run the dialog
	 */
	
	list[0] = 'TEXT';
	StandardGetFile(NULL,1,list,&reply);
	if (!reply.sfGood) return false;
	
	/*
	 *	We have the file. Open the file object
	 */
	
	fptr = new TFile(&reply.sfFile);
	if (fFile) delete fFile;
	fFile = fptr;
	cvtp2c(fName,reply.sfFile.name);
	DoDocumentRevert();
	return true;
#endif

#if OPT_WINOS
	OPENFILENAME ofn;
	char buffer[32];
	char *c;
	char name[256];
	char *x,*y;
	TFile *fptr;
	
	memset(&ofn,0,sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = _GMainWindow;
	ofn.hInstance = _GInstance;
	
	strcpy(buffer,"Text File|*.TXT|");
	for (c = buffer; *c; c++) if (*c == '|') *c = '\0';
	ofn.lpstrFilter = buffer;
	
	name[0] = 0;
	ofn.lpstrFile = name;
	ofn.nMaxFile = 256;
	ofn.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES;

	if (!GetOpenFileName(&ofn)) return false;
	
	/*
	 *	Open the file object
	 */
	
	fptr = new TFile(name);
	if (fFile) delete fFile;
	fFile = fptr;
	
	y = name;
	for (x = name; *x != 0; x++) {
		if ((*x == ':') || (*x == '\\') || (*x == '/')) y = x + 1;
	}
	strcpy(fName,y);
	DoDocumentRevert();
	return true;
#endif

#if OPT_XWIN
	char buffer[256];
	char *x,*y;
	TFile *fptr;
	
	buffer[0] = 0;
	if (!OpenFileDialog(buffer)) return false;
	
	fptr = new TFile(buffer);
	if (fFile) delete fFile;
	fFile = fptr;
	
	y = buffer;
	for (x = buffer; *x != 0; x++) {
		if ((*x == ':') || (*x == '\\') || (*x == '/')) y = x + 1;
	}
	strcpy(fName,y);
	DoDocumentRevert();	
	return true;
#endif
}

/*	TEditDoc::DoSaveDialog
 *
 *		Handle the open dialog. Once open, this fills out and
 *	creates a file object and remembers the name.
 */

bool TEditDoc::DoSaveDialog(void)
{
	long i,len;
	
#if OPT_MACOS
	StandardFileReply reply;
	TFile *fptr;
	unsigned char buffer[64];
	
	/*
	 *	Run the dialog
	 */
	
	StandardPutFile("\pSave Text File As",cvtc2p(buffer,fName),&reply);
	if (!reply.sfGood) return false;
	
	/*
	 *	We have the file. Open the file object
	 */
	
	fptr = new TFile(&reply.sfFile);
	if (fFile) delete fFile;
	fFile = fptr;
	cvtp2c(fName,reply.sfFile.name);
	DocumentRenamed();
#endif

#if OPT_WINOS
	OPENFILENAME ofn;
	char buffer[32];
	char *c;
	char name[256];
	TFile *fptr;
	char *x,*y;
	
	memset(&ofn,0,sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = _GMainWindow;
	ofn.hInstance = _GInstance;
	
	strcpy(buffer,"Text File|*.TXT|");
	for (c = buffer; *c; c++) if (*c == '|') *c = '\0';
	ofn.lpstrFilter = buffer;
	
	ofn.lpstrFile = name;
	ofn.nMaxFile = 256;
	ofn.Flags = OFN_OVERWRITEPROMPT | OFN_LONGNAMES;

	if (!GetSaveFileName(&ofn)) return false;

	/*
	 *	Have name. Open file
	 */
	
	fptr = new TFile(name);
	if (fFile) delete fFile;
	fFile = fptr;
	
	y = name;
	for (x = name; *x != 0; x++) {
		if ((*x == ':') || (*x == '\\') || (*x == '/')) y = x + 1;
	}
	strcpy(fName,y);
	DocumentRenamed();
#endif

#if OPT_XWIN
	char buffer[256];
	char *x,*y;
	TFile *fptr;
	
	strcpy(buffer,fName);
	if (!SaveFileDialog(buffer)) return false;
	
	fptr = new TFile(buffer);
	if (fFile) delete fFile;
	fFile = fptr;
	
	y = buffer;
	for (x = buffer; *x != 0; x++) {
		if ((*x == ':') || (*x == '\\') || (*x == '/')) y = x + 1;
	}
	strcpy(fName,y);
	DocumentRenamed();
#endif

	/*
	 *	I've changed my name. Rename window
	 */

	len = GetNumAttachWindows();
	for (i = 0; i < len; i++) {
		GetAttachedWindow(i)->SetTitle(fName);
	}
	return true;
}

