/******************************************************************************
 *
 * Copyright (c) 1999	TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *	TreeViewer.cpp
 *
 *****************************************************************************/

// SOL++2000
// 1999.09.23 Modified
// 2000.02.18


#include <sol\ApplicationView.h>
#include <sol\FileDialog.h>
#include <sol\DrawableTree.h>
#include <sol\clientdc.h>
#include <sol\paintdc.h>
#include "resource.h"


class TreeViewer :public ApplicationView {
	Font		  font;
	int	          range;
	DrawableTree* tree;
	FileDialog    fileSelector;
  protected:
	void	      buildName(DrawableNode* node, char* delim, 
						char* buffer, int len);
	FileDialog*   getFileSelector();
	virtual long  leftButtonDown(Event& event);
	virtual long  leftButtonDoubleClick(Event& event);
	void 	      load(Action& action);
	long 	      paint(Event& event);
	long		  size(Event& event);
	DrawableNode* search(int x, int y);
	void 	      setTree(DrawableTree* tree1);
	void 	      setTreeScrollRange(DC* dev);
	void	      open(Action& action);
  public:
	TreeViewer(Application& applet, const char* caption, Args& args);
	~TreeViewer();
	DrawableTree* getTree() { return tree; }
};


TreeViewer::TreeViewer(Application& applet, const char* caption, Args& args)
	:ApplicationView(applet, caption,
				args.set(XmNexStyle, (ulong)WS_EX_CLIENTEDGE)
		            .set(XmNstyle, (ulong)WS_HSCROLL|WS_VSCROLL))
{
	tree  = NULL;
	range = FALSE;

	Args ar;
	ar.set(XmNfilter, "(Tree *.tre)\0 *.tre\0");
	fileSelector.create(this, "TreeList", ar);

	addCallback(XmNmenuCallback, ID_LOAD, this, (Callback)&TreeViewer::load, NULL);

	addCallback(XmNmenuCallback, ID_EXIT,  this, (Callback)&TreeViewer::exit, NULL);

	addEventHandler(WM_LBUTTONDOWN, this, (Handler)&TreeViewer::leftButtonDown, NULL);
	addEventHandler(WM_LBUTTONDBLCLK, this, (Handler)&TreeViewer::leftButtonDoubleClick, NULL);
	addEventHandler(WM_PAINT, this, (Handler)&TreeViewer::paint, NULL);

	ClientDC dc(this);
	UINT charSet = dc.getTextCharsetInfo(NULL);
	ar.reset();
	ar.set(XmNheight, (-12));
	ar.set(XmNcharSet, (ulong)charSet);//SHIFTJIS_CHARSET);
	ar.set(XmNweight,  FW_BOLD);

	// 1999.09.23
	font.create(ar);
}


void TreeViewer::setTree(DrawableTree* tree1)
{
	if(tree != NULL) {
		delete tree;
	}
	tree  = tree1;
	range = FALSE;

	setScrollPos(HORIZONTAL, 0);
	setScrollPos(VERTICAL, 0);
}


FileDialog* TreeViewer::getFileSelector()
{
	return &fileSelector;
}


TreeViewer::~TreeViewer()
{
	if(tree) delete tree;
}


void TreeViewer::load(Action& action)
{
	if(fileSelector.open()) {
		char* fileName = fileSelector.getFileName();
		char buffer[256];
		DrawableTree* tree1 = new DrawableTree();

		if(tree1 -> load(fileName) == TRUE) {
			sprintf(buffer,"%s - TreeViewer", fileName);
			setText(buffer);
			setTree(tree1);
			// 1999.09.23
			tree1 -> setConnectionPolicy(DrawableNode::ZIGZAG);
			tree1 -> setVertSpacing(10);
			tree1 -> setFont(&font);
			ClientDC dc(this);
			setTreeScrollRange(&dc);
			update(NULL);
		}
		else {
			delete tree1;
		}
	}
}


void TreeViewer::setTreeScrollRange(DC* dc)
{
	int maxx = 0;
	int maxy = 0;
	tree -> computeExtent(dc, &maxx, &maxy);
	maxx = maxx + tree->getLeftMargin();
	maxy = maxy + tree->getTopMargin() ;

	setScrollExtent(maxx, maxy);

	range = TRUE;
}


long TreeViewer::paint(Event& event)
{
	PaintDC pdc(this);
	int x = getScrollPos(HORIZONTAL);
	int y = getScrollPos(VERTICAL);

	if(tree) {
		tree -> draw(&pdc, -x, -y);
	}
	return NULL;
}


long TreeViewer::size(Event& event)
{

	if(tree) {
		ClientDC dc(this);
		setTreeScrollRange(&dc);
	}
	return NULL;
}


DrawableNode* TreeViewer::search(int x, int y)
{
	int x1 = getScrollPos(HORIZONTAL);
	int y1 = getScrollPos(VERTICAL);

	ClientDC cdc(this);
	return tree->search(&cdc, x+x1, y+y1);
}


long TreeViewer::leftButtonDown(Event& event)
{
	if(tree) {
		int  x, y;
		event.getMousePosition(x, y);
		DrawableNode* node = search(x, y);

		if(node) {
			int mx = getScrollPos(HORIZONTAL);
			int my = getScrollPos(VERTICAL);
			ClientDC cdc(this);
			tree -> setActiveNode(node, &cdc, mx, my);
		}
	}
	return NULL;
}


long TreeViewer::leftButtonDoubleClick(Event& event)
{
	if(tree) {
		int  x, y;
		event.getMousePosition(x, y);
		DrawableNode* node = search(x, y);

		if(node) {
			int mx = getScrollPos(HORIZONTAL);
			int my = getScrollPos(VERTICAL);
			ClientDC cdc(this);
			tree -> setActiveNode(node, &cdc, mx, my);
	
			char buffer[512];
			buffer[0] = NULL;

			buildName(node, "-", buffer, 512);
			MessageBox(getWindow(),	buffer,
					node->getName(),
					MB_OK);
		}
	}
	return NULL;
}


void TreeViewer::buildName(DrawableNode* node, char* delim, 
			 char* buffer, int len)
{
	char* temp = new char[len];

	strcpy(temp, "");
	strcpy(buffer, "");
	DrawableNode* parent;
	parent = node;

	while(parent) {
		if(strcmp(temp, "") == 0) {
			sprintf(buffer,"%s", parent->getName());
		}
		else {
			sprintf(buffer, "%s%s%s", parent->getName(), 
					  delim,  temp);
		}
		strcpy(temp, buffer);
		parent = (DrawableNode*) parent->getParent();
	}
	delete temp;
}


void	Main(int argc, char** argv)
{
	const char* name = "TreeViewer";
	Application applet(name, argc, argv);

	Args args;
	TreeViewer treev(applet, name, args);
	treev.realize();

	applet.run();
}

