/*
**	Copyright 2000 Be Incorporated. All Rights Reserved.
**	This file may be used under the terms of the Be Sample Code 
**	License.
*/

#include <Control.h>
#include <File.h>
#include <Window.h>
#include <View.h>
#include "main.h"
#include "CadPictureView.h"
#include "CadItem.h"
#include "SegmentItem.h"

#define stateDrawLine 666

CadPictureView::CadPictureView(BRect frame, char *title):
	BControl(frame, title, title, new BMessage(CADVIEW_INVOKED), B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS)
{
	fGridSize=10;
	fGraphState = true;
	fZoomFactor = 1;
}

/****************************************/

CadPictureView::CadPictureView(BMessage *archive):
	BControl(archive)
{
	long int	index=0;
	long int 	numPoints;
	BMessage	thisMessage;
	BArchivable	*thisItem;
	CadItem		*thisCadItem;
	
	type_code typeFound;

	archive->GetInfo("CadItems", &typeFound, &index);

	while (index > 0) {
		archive->FindMessage("CadItems", index -1, &thisMessage);
		thisItem = instantiate_object(&thisMessage);
		if (thisItem) {
			thisCadItem = dynamic_cast<CadItem *>(thisItem);
			if( thisCadItem) {
				fItemList.AddItem( (void *) thisCadItem);
			} else {
				printf("thisCadItem == NULL (coud not cast)\n");
			}			
		} else {
			printf("thisItem == NULL (could not instantiate)\n");
			thisMessage.PrintToStream();
		}
		index--;
	}

	archive->FindBool("fGraphState", &fGraphState);
	archive->FindFloat("fGridSize", &fGridSize);
	archive->FindFloat("fZoomFactor", &fZoomFactor);
}

/****************************************/

status_t
CadPictureView::Archive(BMessage *archive, bool deep = true)
{
	int result;

	archive->what = BECAD_DATA_MESSAGE;

	result = BView::Archive(archive, deep);

	CadItem	*thisItem;
	BMessage *thisMessage;
	int	index;

	if(deep) {
		index = fItemList.CountItems();
		while (index > 0) {
			thisItem = (CadItem *) fItemList.ItemAt(index-1);
			thisMessage = new BMessage();
			thisItem->Archive(thisMessage, true);
			archive->AddMessage("CadItems",thisMessage);
			index--;
		}
	}

	archive->AddBool("fGraphState", fGraphState);
	archive->AddFloat("fGridSize", fGridSize);
	archive->AddFloat("fZoomFactor", fZoomFactor);
	return (result);
}

/****************************************/

CadPictureView
*CadPictureView::Instantiate(BMessage *archive) 
{
	if (validate_instantiation(archive, "CadPictureView")) {
		return new CadPictureView(archive);
	}
	return NULL;
}


/****************************************/

void CadPictureView::AttachedToWindow(void)
{
  SetViewColor(0,0,0,0);
  SetHighColor(255,255,255,0);
  SetLowColor(128,128,128,0);
}

/****************************************/

void 
CadPictureView::SetGraphState(bool nState)
{
	fGraphState = nState;
	Invalidate();
}

/***************************************/

bool 
CadPictureView::GetGraphState(void)
{
	return fGraphState;
}

/***************************************/

void 
CadPictureView::SetGridSize(float nsize)
{
	fGridSize = nsize;
	Invalidate();
}

/***************************************/

float 
CadPictureView::GetGridSize(void)
{
	return(fGridSize);
}

/***************************************/

void 
CadPictureView::SetFileName(const char *filename)
{
	fFileName = filename;
}

/***************************************/

const char *
CadPictureView::GetFileName() const
{
	return fFileName.String();
}

/***************************************/

void
CadPictureView::MouseDown(BPoint pt)
{
	if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) != 0) {
		if(modifiers() & B_CONTROL_KEY) {
			pt.y = pt.y - (long int) pt.y % (long int) fGridSize;
			pt.x = pt.x - (long int) pt.x % (long int) fGridSize;
		}

		fTrackingMovePoint = pt;
		fTrackingStartPoint = pt;
		SetTracking(true);
		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
		return;
	}
}

void 
CadPictureView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg)
{
	if(IsTracking()) {
		if (fTrackingMovePoint != pt) {
			/* handle constraints based on shift key */
			if(modifiers() & B_SHIFT_KEY) {
				if (abs((long int) pt.x - (long int)fTrackingStartPoint.x) > (abs((long int)pt.y - (long int)fTrackingStartPoint.y))) {
					pt.y = fTrackingStartPoint.y;
				} else {
					pt.x = fTrackingStartPoint.x;
				}
			}
			
			if(modifiers() & B_CONTROL_KEY) {
				pt.y = pt.y - (long int) pt.y % (long int) fGridSize;
				pt.x = pt.x - (long int) pt.x % (long int) fGridSize;
			}

			SetDrawingMode(B_OP_INVERT);
			StrokeLine(fTrackingStartPoint, fTrackingMovePoint); // Erase the old line
			StrokeLine(fTrackingStartPoint, pt); //Draw the new one
			fTrackingMovePoint=pt;			
		}
	}
}

void 
CadPictureView::MouseUp(BPoint pt)
{
	if (IsTracking()) {
		if(modifiers() & B_SHIFT_KEY) {
			if (abs((long int) pt.x - (long int)fTrackingStartPoint.x) > (abs((long int)pt.y - (long int)fTrackingStartPoint.y))) {
				pt.y = fTrackingStartPoint.y;
			} else {
				pt.x = fTrackingStartPoint.x;
			}
		}

		if(modifiers() & B_CONTROL_KEY) {
			pt.y = pt.y - (long int) pt.y % (long int) fGridSize;
			pt.x = pt.x - (long int) pt.x % (long int) fGridSize;
		}

		SetDrawingMode(B_OP_COPY); //Go back to copy mode to stroke the actual line
		StrokeLine(fTrackingStartPoint,pt);
		SetTracking(false);
		fItemList.AddItem( (void *) new SegmentItem(fTrackingStartPoint, pt) ); /* ...add the new segment */
	}
}

void 
CadPictureView::KeyDown(const char *bytes, int32 numBytes)
{
	printf("KeyDown\n");
}



/****************************************/

void
CadPictureView::Draw(BRect updaterect)
{
	BView::Draw(updaterect);
	
	float x,y;
	
	SetHighColor(64,64,64);
	SetDrawingMode(B_OP_COPY);
	if (fGraphState == true) {
		for (x=Bounds().left + fGridSize; x <= Bounds().right; x=x + fGridSize) {
			StrokeLine(BPoint(x,Bounds().top) , BPoint(x, Bounds().bottom) );
		}
		for (y=Bounds().top + fGridSize; y <= Bounds().bottom; y=y+fGridSize) {
			StrokeLine(BPoint(Bounds().left, y), BPoint(Bounds().right, y));
		}
	}
	
	CadItem	*thisItem;
	int	index;

	index = fItemList.CountItems();
	while (index > 0) {
		thisItem = (CadItem *) fItemList.ItemAt(index-1);
		thisItem->DrawItem(this);
		index--;
	}

}

/****************************************/

void
CadPictureView::Save(const char *filename)
{
	BMessage ArchiveMessage;
	BFile	*outputFile;
	
	outputFile = new BFile(filename, B_READ_WRITE | B_CREATE_FILE);
	
	Archive(&ArchiveMessage, true);
	ArchiveMessage.Flatten(outputFile);
}

