/**------------------------------------------------------------------------
 * @file
 *
 * Copyright 2001 by the University of Toronto (UT).
 *
 *                       All Rights Reserved
 * 
 * Permission to copy and modify this software and its documentation 
 * only for internal use in your organization is hereby granted, 
 * provided that this notice is retained thereon and on all copies.  
 * UT makes no representations as to the suitability and operability 
 * of this software for any purpose.  It is provided "as is" without 
 * express or implied warranty.
 *
 * UT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
 * SHALL UT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * No other rights, including for example, the right to redistribute 
 * this software and its documentation or the right to prepare 
 * derivative works, are granted unless specifically provided in a 
 * separate license agreement.
 *
 * Author: Diego Macrini (dmac@cs.toronto.edu)
 * 
 * $Log: VisualDAG.cpp,v $
 * Revision 1.5  2002/06/18 00:40:14  dmac
 * Improved display of SG skeleton.
 *
 * Revision 1.4  2002/06/13 21:49:18  dmac
 * Small changes
 *
 * Revision 1.3  2002/06/10 18:41:33  dmac
 * DAG's label is displayed again.
 *
 * Revision 1.2  2002/05/16 22:51:05  dmac
 * Several bugs fixed and a new DAG-derived class added
 *
 * Revision 1.1.1.1  2002/03/10 07:38:07  dmac
 * Imported sources
 *
 *
 *-----------------------------------------------------------------------*/

#include <LEDA/graphics/graphwin.h>
#include <LEDA/graphics/color.h>
#include <LEDA/graphics/x_window.h>

// VC++6 -> Include CImg before DAG.h
#include "../CImg/CImg.h"

#include "DAG.h"
#include "ShockGraph.h"
#include "VisualDAG.h"

#include <stdio.h>

//#include <CImg/CImg.h>

//#include "UnixFuncPrototypes.h"

// Graph window params
#define GW_LEFT_MARGIN    50
#define GW_RIGHT_MARGIN   50
#define GW_TOP_MARGIN     50
#define GW_BOTTOM_MARGIN  50
#define NODE_WIDTH		  54
#define NODE_HEIGHT		  25
#define NODE_FONT_SIZE	  11

#define HGAP			(NODE_WIDTH / 4)
#define VGAP			(NODE_HEIGHT * 2)

// Skeleton window params
#define SW_LEFT_MARGIN    50
#define SW_RIGHT_MARGIN   50
#define SW_TOP_MARGIN     50
#define SW_BOTTOM_MARGIN  50
/* #define SW_LEFT_MARGIN    5
#define SW_RIGHT_MARGIN   5
#define SW_TOP_MARGIN     5
#define SW_BOTTOM_MARGIN  5 */
#define SW_CENTER_MARGIN  20
#define SW_WIN_WIDTH      800

// matching window parms
#define Y_OFFSET 10

using namespace std;
using namespace dml;
using namespace leda;

unsigned char* ReadPPMFile(const char* szPPMFileName, int* pnRows, int* pnCols);


/* Useful piece of help on leda colors...

	Colors can be created from rgb-values, from names in a color data base (X11), 
	or from the 16 integer constants (enumeration in \<LEDA/incl/impl/x\_window.h\>)
	$black$, $white$, $red$, $green$, $blue$, $yellow$, $violet$, $orange$;
	$cyan$, $brown$, $pink$, $green2$, $blue2$, $grey1$, $grey2$, $grey3$.
*/

void RecomputeTSV(leda_GraphWin& gw, leda_node v)
{
	DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
	
	dag.ComputeTSVs(dag.GetFirstRootNode());
	dag.PrintTSVs();
}

void OnRecomputeTSV(leda_GraphWin& gw, const leda_point& pt)
{
	double x = pt.xcoord(), y = pt.ycoord();
	leda_list<leda_node> nodes = gw.get_nodes_in_area(x, y, x, y);

	RecomputeTSV(gw, nodes.pop());
}

void OnDisplayNodeEigenSum(leda_GraphWin& gw, const leda_point& pt)
{
	const DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
	double x = pt.xcoord(), y = pt.ycoord();
	leda_node v = gw.get_nodes_in_area(x, y, x, y).pop();

	if (v != nil)
	{
		double n = dag.GetNode(v)->GetEigenLbl();
		char sz[50];
		sprintf(sz, "Eigenvalue Sum = %.4f.", n);
		gw.message(sz);
	}
}

void OnDisplayNodeInfo(leda_GraphWin& gw, const leda_point& pt)
{
	const DAG& dag = dynamic_cast<DAG&>(gw.get_graph());
	double x = pt.xcoord(), y = pt.ycoord();
	leda_node v = gw.get_nodes_in_area(x, y, x, y).pop();

	if (v != nil)
	{
		double n = dag.GetNode(v)->GetEigenLbl();
		char sz[500];
		
		const ShockGraph* pSG = dynamic_cast<const ShockGraph*>(&dag);

		if (pSG) {
			sprintf(sz, "%s %d: DFS index: %d, EigenSum: %.4f, Shock Pts: %d",
				(const char*)pSG->GetObjName(),
				pSG->GetViewNumber(),
				pSG->GetNodeDFSIndex(v),
				n,
				pSG->NodeLength(v));

			cout << endl; pSG->GetSGNode(v)->Print();
			cout << endl; pSG->GetSGNode(v)->m_shocks.Print();
		}
		else
			sprintf(sz, "Label:%s\nEigenSum: %.4f.", (const char*)dag.GetDAGLbl(), n);

		gw.message(sz);
	}
}

void OnShowAdjMatrix(leda_GraphWin& gw, const leda_point& pt)
{
	DAG& dag = dynamic_cast<DAG&>(gw.get_graph());

	dag.PrintAdjMatrix();
}

void OnNewNode(leda_GraphWin& gw, leda_node v)
{
	DAG& dag = dynamic_cast<DAG&>(gw.get_graph());

	dag[v] = dag.CreateNodeObject((const char*)gw.get_label(v));
	RecomputeTSV(gw, v);
}

void OnNewEdge(leda_GraphWin& gw, leda_edge e)
{
	DAG& dag = dynamic_cast<DAG&>(gw.get_graph());

	dag[e] = 1.0;
	RecomputeTSV(gw, dag.source(e));
}

void OnDelNode(leda_GraphWin& gw)
{
	RecomputeTSV(gw, nil);
}

void OnDelEdge(leda_GraphWin& gw)
{
	RecomputeTSV(gw, nil);
}

int CompNumOfLeaves(DAG& g, leda_node v, NodeIndexMap& nodeIdxMap)
{
	if (!nodeIdxMap.defined(v))
	{
		leda_node u;
		int n = 0;
		
		if (g.outdeg(v) == 0)
			n = 1;	
		else
			forall_adj_nodes(u, v)
				n += CompNumOfLeaves(g, u, nodeIdxMap);
			
		return nodeIdxMap[v] = n;
	}
	
	return nodeIdxMap[v];
}

/*!
	@brief Recursive function that sets the position a node and all its children

	Parents position are set to be in an upper level at the center of all their child nodes.
*/
double SetNodePos(leda_GraphWin& gw, DAG& g, leda_node v, dml::POINT top_left, NodeIndexMap& nodeIdxMap)
{
	leda_node u;
	int num_lea = nodeIdxMap[v];
	
	double w = num_lea * NODE_WIDTH + (num_lea - 1) * HGAP;
	
	leda_point pos(top_left.x + w / 2, top_left.y);
	
	gw.set_position(v, pos);
	
	top_left.y -= NODE_HEIGHT + VGAP;
	
	forall_adj_nodes(u, v)
	{
		if (indeg(u) <= 1 || g.GetNodeLevel(u) == g.GetNodeLevel(v) + 1)
			top_left.x += SetNodePos(gw, g, u, top_left, nodeIdxMap) + HGAP;
	}
	
	return w;		
}

void ShowTree(DAG& g)
{
	leda_node v, r = g.GetFirstRootNode();

	// Compute graph's dimensions. Diameter and height
	int nMaxHeight = 0;
	
	forall_nodes(v, g)
		if (g.GetNodeLevel(v) > nMaxHeight)
			nMaxHeight = g.GetNodeLevel(v);
			
	NodeIndexMap map;
	int nLeaves = CompNumOfLeaves(g, r, map);

	// Set window's dimensions
	int nWinWidth = NODE_WIDTH * nLeaves + HGAP * (nLeaves - 1)
		+ GW_LEFT_MARGIN + GW_RIGHT_MARGIN;

	int nWinHeight = NODE_HEIGHT * (nMaxHeight + 1) + VGAP * nMaxHeight
		+ GW_TOP_MARGIN + GW_BOTTOM_MARGIN;
		
	// Create window
	leda_GraphWin gw(g, nWinWidth, nWinHeight);
	gw.win_init(0, nWinWidth, 0);
	
	// Set node positions
	dml::POINT top_left;
	
	top_left.x = GW_LEFT_MARGIN;
	top_left.y = gw.get_ymax() - GW_TOP_MARGIN - NODE_HEIGHT / 2;	
	
	SetNodePos(gw, g, r, top_left, map);

	// Set nodes' attributes
	forall_nodes(v, g)
	{
		const DAGNodePtr node = g.GetNode(v);

		gw.set_label(v, (const char*)node->GetLblForGraph());
		gw.set_color(v, node->GetColorForGraph());
		gw.set_shape(v, (leda_gw_node_shape)node->GetShapeForGraph());
	}

	gw.set_node_shape(leda_ellipse_node, false);
	gw.set_node_width(NODE_WIDTH, true);
	gw.set_node_height(NODE_HEIGHT, true);

	// Global params
	gw.set_node_label_font(leda_roman_font, NODE_FONT_SIZE);
	gw.set_show_status(false);

	gw.add_node_menu("Recompute TSV", OnRecomputeTSV);
	gw.add_node_menu("Display EigenSum", OnDisplayNodeEigenSum);
	gw.add_node_menu("Display node info", OnDisplayNodeInfo);
	gw.add_node_menu("Show adj matrix", OnShowAdjMatrix);
	gw.set_new_node_handler(OnNewNode);
	gw.set_new_edge_handler(OnNewEdge);
	gw.set_del_node_handler(OnDelNode);
	gw.set_del_edge_handler(OnDelEdge);

	//gw.place_into_win();
	gw.display();
	gw.message((const char*)g.GetDAGLbl());

	gw.edit();
}

void dml::ShowGraph(DAG& g)
{
	ShowTree(g);
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// SGMatchWnd

SGMatchWnd::SGMatchWnd()
{
	m_pWnd = NULL;
	m_bShowLabels = true;
	m_bShowNodeType = false;
	m_nShowColorLines = 0;
	m_bShowCoords = true;
	
	m_pSGInfo1 = m_pSGInfo2 = NULL;
}

SGMatchWnd::~SGMatchWnd()
{
	if (m_pWnd) delete m_pWnd;
	
	delete m_pSGInfo1;
	delete m_pSGInfo2;
}

bool SGMatchWnd::Create(const ShockGraph* pSG1, const ShockGraph* pSG2, bool bAsyncMode)
{
	ASSERT(pSG1 && pSG2);

	// Set min and max window coordinates
	double xmin = 0;
	double xmax = SW_LEFT_MARGIN + SW_CENTER_MARGIN + SW_RIGHT_MARGIN;
	double ymin = 0;
	double ymax = SW_BOTTOM_MARGIN + SW_TOP_MARGIN;

	xmax += pSG1->Width() + pSG2->Width();
	ymax += (pSG1->Height() > pSG2->Height()) ? pSG1->Height():pSG2->Height();

	// Compute scaling factor
	double width = xmax;
	double height = (ymax - ymin) * width / (xmax - xmin);
	
	double delta_x, delta_y, reflex_y;
	
	// Set SG position info
	delta_x = pSG1->xmin - SW_LEFT_MARGIN;
	delta_y = pSG1->ymin - SW_BOTTOM_MARGIN;
	reflex_y = pSG1->ymax + pSG1->ymin;

	m_pSGInfo1 = new SGInfo(pSG1, delta_x, delta_y, reflex_y);

	delta_x = pSG2->xmin - (SW_LEFT_MARGIN + pSG1->Width() + SW_CENTER_MARGIN);
	delta_y = pSG2->ymin - SW_BOTTOM_MARGIN;
	reflex_y = pSG2->ymax + pSG2->ymin;
	
	m_pSGInfo2 = new SGInfo(pSG2, delta_x, delta_y, reflex_y);

#ifndef WIN32
	// m_pSGInfo1 and m_pSGInfo2 made a copy of pSG1 and pSG2, so
	// we are ready to create the window in an independent process
	if (bAsyncMode && fork() != 0)
	 	return true;
#endif //WIN32

	// Create a window of the desired size
	m_pWnd = new Wnd((int)width, (int)height, "r:redraw, l:labels, t:types, a,b:graphs, q:quit", this);
	m_pWnd->init(xmin, xmax, ymin);
	//m_pWnd->set_show_coordinates(m_bShowCoords);

	m_pWnd->display(0, 0);
	m_pWnd->redraw();

	int val;
	double x, y;
	int event;

	while (true)
	{
		event = m_pWnd->read_event(val, x, y);

		if (event == leda::key_press_event)
		{
			if (val == 'r' || val == 'R')
				m_pWnd->reset_clipping();
			else if (val == 'l' || val == 'L')
				m_bShowLabels = !m_bShowLabels;
			else if (val == 't' || val == 'T')
				m_bShowNodeType = !m_bShowNodeType;
			else if (val == 'a' || val == 'b')
			{
				ShockGraph sg;
				sg = (val == 'a') ? *GetSGInfo1()->pSG:*GetSGInfo2()->pSG;
				ShowGraph(sg);
			}
			else if (val == 'c' || val == 'C')
				m_bShowCoords = !m_bShowCoords;
				//m_pWnd->set_show_coordinates(m_bShowCoords = !m_bShowCoords);
			else if (isdigit(val))
				m_nShowColorLines = val - '0';
			else
				break;

			m_pWnd->redraw();
		}
		else if (event == leda_exposure_event)
			m_pWnd->reset_clipping();
		else if (event == leda_destroy_event)
			break;
	}
#ifndef WIN32	
	if (bAsyncMode)	
		exit(0); // It's a child process
#endif	
	return true;
}

leda_point ReMapPt(const dml::POINT& a, const SGMatchWnd::SGInfo* si)
{
	return leda_point(a.x - si->delta_x, si->reflex_y - a.y - si->delta_y);
}

leda_point ReMapPt(const sg::Point& a, const SGMatchWnd::SGInfo* si)
{
	return leda_point(a.x - si->delta_x, si->reflex_y - a.y - si->delta_y);
}

leda_point ReMapPt(const leda_point& a, const SGMatchWnd::SGInfo* si)
{
	return leda_point(a.xcoord() - si->delta_x, si->reflex_y - a.ycoord() - si->delta_y);
}

void SGMatchWnd::Wnd::OnShowCoord(leda_window* pBaseWnd, double x, double y)
{
    Wnd* pWnd = dynamic_cast<Wnd*>(pBaseWnd);
    SGMatchWnd* pSGWnd = pWnd->m_pParent;

    double centerPt = SW_LEFT_MARGIN + pSGWnd->GetSGInfo1()->pSG->Width() + SW_CENTER_MARGIN / 2.0;
    	
    leda_point pt = ReMapPt(leda_point(-x, y), (x <= centerPt) ? pSGWnd->GetSGInfo1():pSGWnd->GetSGInfo2());
    	
    x = pWnd->xmin();
    y = pWnd->ymax();
    pWnd->draw_box(x, y - 30, x + 100, y, leda_white);

    if (pSGWnd->m_bShowCoords)
    {
    	char szTxt[100];
    	sprintf(szTxt, "%.1f %.1f", -pt.xcoord(), pt.ycoord());
    	pWnd->draw_text(x + 10, y - 10, szTxt);
    }
}

void SGMatchWnd::Wnd::OnDraw(leda_window* pBaseWnd)
{
	Wnd* pWnd = dynamic_cast<Wnd*>(pBaseWnd);
	ASSERT(pWnd);
	
	SGMatchWnd* pSGWnd = pWnd->m_pParent;

	//w.start_buffering();

	//	pWnd->clear(leda_black);

	pSGWnd->DrawSG();
	pSGWnd->DrawMatchingLines();
	
	//pWnd->draw_segment(pWnd->xmin(), pWnd->ymin() + BOTTOM_MARGIN, pWnd->xmax(),
	//pWnd->ymin() + BOTTOM_MARGIN, leda_color(255, 0, 0));

	//w.flush_buffer();
	//w.stop_buffering();

}

/*! 
	Draw the contour. It gives priority to the boundary data points
	returnd by GetBoundaryPts() over those in the DDSkeleton.
*/
bool SGMatchWnd::DrawSkeleton(const SGInfo* si) const
{
	leda_list<leda_point> pts;
	const POINTS& sgpts = si->pSG->GetBoundaryPts();

	if (sgpts.GetSize() > 0)
	{
		for(int i = 0; i < sgpts.GetSize(); i++)
			pts.push(ReMapPt(sgpts[i], si));
	
		m_pWnd->draw_polygon(pts);
		m_pWnd->draw_segment(ReMapPt(sgpts[sgpts.GetSize() - 1], si), ReMapPt(sgpts[0], si));
	}
	else if (si->pSG->GetSkeleton() != NULL)
	{
		sg::DDSkeleton* sk = ((McGillSkeleton*)si->pSG->GetSkeleton())->GetSkeleton();
	
		if (sk  != NULL)
		{
			sg::Curve *c = sk->getShape()->getCurves()->front();
			const double step = 0.5;
			double t=0;
			sg::Point p1, p2;
			
			for(t = 0; t < c->getLength() - 2 * step; t += step)
				pts.push(ReMapPt(c->atT(t), si));
			
			m_pWnd->draw_polygon(pts);
			// Close first and last points
			m_pWnd->draw_segment(ReMapPt(c->atT(t), si), ReMapPt(c->atT(0), si));
		}
	}
	
	// New functionality (6/Jun/2006)
	/*if (si->pSG->GetSkeleton() != NULL)
	{
		const SmartArray<SEGMENTS> skelSegments = si->pSG->GetSkeleton()->GerApproximation();
		int i, j, w = m_pWnd->set_line_width(4);
		
		for (i = 0; i < skelSegments.GetSize(); i++)
			for (j = 0; j < skelSegments[i].GetSize(); j++)
				m_pWnd->draw_segment(ReMapPt(skelSegments[i][j].GetP0(), si), ReMapPt(skelSegments[i][j].GetP1(), si));

		m_pWnd->set_line_width(w);
	}*/
	
	return true;
}

void SGMatchWnd::DrawSG() const
{
	const SGNode* pNode;
	leda_node v;
	int i, j, size;
	const SGInfo* info[] = {GetSGInfo1(), GetSGInfo2()};
	double x1, y1, m;
	char cEndPt;
	leda_color c;
	int t, colorIdx;

	// define possible pixel colors
	leda_color color[] = {leda_black, leda_red, leda_brown, leda_blue, leda_violet, leda_grey3};

	m_pWnd->start_buffering();

	m_pWnd->clear(leda_white);
	
	for (i = 0; i < 2; i++)
	{
		FILE* fp = fopen(info[i]->pSG->GetDAGLbl(), "r");
		
		if (fp != NULL)
		{
			fclose(fp);
		
			cimg_library::CImg<float> shapeImg(info[i]->pSG->GetDAGLbl());

			if (shapeImg.dimy() > 0 && shapeImg.dimx() > 0)//(!shapeImg.is_empty())
			{
				int r,c;
				
				for (r = 0; r < shapeImg.dimy(); r++)
					for (c = 0; c < shapeImg.dimx(); c++) 
						if (shapeImg(c,r) == 0)
							m_pWnd->draw_pixel(ReMapPt(leda_point(c, r), info[i]), leda_grey1);
			}
		}
    	
    		DrawSkeleton(info[i]);

		colorIdx = 0;

		forall_nodes(v, *(info[i]->pSG))
		{
			pNode = info[i]->pSG->GetSGNode(v);
			cEndPt = pNode->GetEndPt();

			t = pNode->m_nType;

			if (t == SHOCK_1 || t == SHOCK_2 || t == SHOCK_3 || t == SHOCK_4)
			{
					size = pNode->m_shocks.GetSize();

					if (size == 0)
					{
						//WARNING(pNode->m_shocks.GetSize() == 0, "Node has no shocks");
						continue;
					}

					const ShockInfo& s0 = pNode->m_shocks[0];
					const ShockInfo& sN = pNode->m_shocks[size - 1];

					if (s0.xcoord != sN.xcoord)
						m = (s0.ycoord - sN.ycoord) / (s0.xcoord - sN.xcoord);
					else
						m = 1;

					for (j = 0; j < size; j++)
					{
						const ShockInfo& s1 = pNode->m_shocks[j];

						x1 = s1.xcoord - info[i]->delta_x;
						y1 = (info[i]->reflex_y - s1.ycoord) - info[i]->delta_y;
						c = color[colorIdx % (sizeof(color) / sizeof(color[0]))];

						m_pWnd->draw_pixel(x1, y1, c);

						if (m_bShowLabels)
						{
							if ((cEndPt == 'a' && j == 0) ||
								(cEndPt == 'b' && j == 0) ||
								(cEndPt != 'a' && cEndPt != 'b' && j == size / 2))
							{
								/*if (m < 0 || m == 1)
									x1 += 4;
								else if (m > 0)
									x1 -= 12;*/
								
								if (m_bShowNodeType)
									m_pWnd->draw_text(x1, y1, (const char*)info[i]->pSG->GetNodeLbl(v),
										c/*leda_color(255, 0, 0)*/);
								else
									m_pWnd->draw_text(x1, y1, (const char*)((const DAG*)(const ShockGraph*)info[i]->pSG)->GetNodeLbl(v),
										c/*leda_color(255, 0, 0)*/);									
							}
						}
					}

					colorIdx++;

					/*for (j = 0; j < size - 1; j++)
					{
						const ShockInfo& s1 = pNode->m_shocks[j];
						const ShockInfo& s2 = pNode->m_shocks[j + 1];

						x1 = s1.xcoord - info[i]->delta_x;
						y1 = (info[i]->reflex_y - s1.ycoord) - info[i]->delta_y;
						x2 = s2.xcoord - info[i]->delta_x;
						y2 = (info[i]->reflex_y - s2.ycoord) - info[i]->delta_y;

						m_pWnd->draw_segment(x1, y1, x2, y2);

						if (j == size / 2)
							m_pWnd->draw_text(x1, y1, info[i]->pSG->GetNodeLbl(v), leda_color(255, 0, 0));
					}*/
			}
			else if (t != ROOT) // There's no info in the root
				cerr << "\nERROR: Unknown node type." << endl;
		}
	}

	m_pWnd->flush_buffer();
	m_pWnd->stop_buffering();
}

void SGMatchWnd::DrawMatchingLines() const
{
	DAGNodePtr ptr;
	const SGNode* pNode1, *pNode2;
	leda::color color[] = {leda::yellow, leda::pink, leda::grey1, leda::grey2, leda::grey3,
						  leda::black, leda::violet, leda::red, leda::blue, leda::green};
	
	const int NCOLORS = sizeof(color) / sizeof(color[0]);

	int color_index = 0, c;
	double arc_x,arc_y;

	unsigned int i = 0;

	if (m_matchMap.empty())
		return;

	forall_defined(ptr, m_matchMap)
	{
		pNode1 = dynamic_cast<const SGNode*>((const DAGNode*) ptr);
		pNode2 = dynamic_cast<const SGNode*>((const DAGNode*) m_matchMap[ptr]);

		if (pNode1->GetShockCount() > 0 && pNode2->GetShockCount() > 0)
		{
			const ShockInfo& s1 = pNode1->m_shocks[pNode1->GetShockCount()/2];
			const ShockInfo& s2 = pNode2->m_shocks[pNode2->GetShockCount()/2];

			/* arc will go from s1 to s2, but will pass along the way through s3,
			   where s3 is midway between s1 and s2 and up a fixed amount. */
			leda_point start(s1.xcoord - GetSGInfo1()->delta_x,
					 (GetSGInfo1()->reflex_y - s1.ycoord) - GetSGInfo1()->delta_y);
			leda_point end(s2.xcoord - GetSGInfo2()->delta_x,
				       (GetSGInfo2()->reflex_y - s2.ycoord) - GetSGInfo2()->delta_y);
			arc_x = (start.xcoord() + end.xcoord())/2;
			arc_y = (start.ycoord() + end.ycoord())/2 + fabs(start.xcoord() - end.xcoord()) * (Y_OFFSET / 100.0);
			if (arc_y >= (start.ycoord() + end.ycoord())/2 + Y_OFFSET)
			  {
			    arc_y = (start.ycoord() + end.ycoord())/2 + Y_OFFSET;
			  }
			
			leda_point mid(arc_x, arc_y);			

			//c = color_index++ % NCOLORS;
			c = int(pNode2->GetSimilarity() * NCOLORS - 1);
			if (c < 0) c = 0;

			if (m_nShowColorLines == 0 || m_nShowColorLines - 1 == c)
				m_pWnd->draw_arc(start, mid, end, color[c]);

			/*	m_pWnd->draw_segment(
				s1.xcoord - GetSGInfo1()->delta_x,
				(GetSGInfo1()->reflex_y - s1.ycoord) - GetSGInfo1()->delta_y,
				s2.xcoord - GetSGInfo2()->delta_x,
				(GetSGInfo2()->reflex_y - s2.ycoord) - GetSGInfo2()->delta_y,
				c[(pNode1->GetType() - 1) % NCOLORS)]);
			*/
		}
	}
}

void SGMatchWnd::SetMatchMap(const DAGNodeMap& matchMap) 
{ 
	m_matchMap = matchMap;

	/*bool bFisrtTime = true; 
	int val;
	double x, y;

	//m_pWnd->redraw();

	while (true) 
	{
		 if (m_pWnd->read_event(val, x, y) == key_release_event)
		 {
			if (bFisrtTime)
			{
				m_matchMap = matchMap; 
				m_pWnd->redraw();
				bFisrtTime = false;
			}
			else
				break;
		 }
	}*/
}

/*!
	@brief Reads a ppm file

	Call delete[] with the eturned pointer when done!!!!
*/
unsigned char* ReadPPMFile(const char* szPPMFileName, int* pnRows, int* pnCols)
{
	/*FILE* fp;

	if ((fp = fopen(szPPMFileName, "r")) == NULL)
		return NULL;

	pixel** img;
	pixval maxval;
	int i, j, k;
	char r, g, b;

	img = ppm_readppm(fp, pnCols, pnRows, &maxval);
	fclose(fp);

	unsigned char* arr = new unsigned char[(*pnRows)*(*pnCols)];
	
	for(i = 0, k = 0; i < *pnRows; i++)
		for(j = 0; j < *pnCols; j++, k++)
		{
			r = (0xff * PPM_GETR(img[i][j])) / maxval;
			g = (0xff * PPM_GETG(img[i][j])) / maxval;
			b = (0xff * PPM_GETB(img[i][j])) / maxval;
			
			arr[k] = (r==0 && b==0 && g==0) ? 0:1; //or 0xff;
		}

	ppm_freearray(img, *pnRows);

	return arr;*/
	return NULL;
}

