/*************************************************************************
 * Copyright (c) 2011 AT&T Intellectual Property 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors: Details at https://graphviz.org
 *************************************************************************/

#pragma once

#include <map>
#include <memory>
#include <vector>

#include <common/types.h>

#include "VisioGraphic.h"
#include "VisioText.h"

namespace Visio
{
	using NodeIds = std::map<Agnode_t*, unsigned int>;
	using Graphics = std::vector<std::unique_ptr<Graphic>>;
	using Texts = std::vector<Text>;
	using Hyperlinks = std::vector<Hyperlink>;

	/* object wrapper for render function callback */
	class Render
	{
	public:
		/* render hierarchy */
		void BeginGraph(GVJ_t* job);
		void EndGraph(GVJ_t* job);
		void BeginPage(GVJ_t* job);
		void EndPage(GVJ_t* job);
		void BeginNode(GVJ_t* job);
		void EndNode(GVJ_t* job);
		void BeginEdge(GVJ_t* job);
		void EndEdge(GVJ_t* job);
		
		/* render graphic + text */
		void AddEllipse(GVJ_t* job, pointf* A, bool filled);
		void AddBezier(GVJ_t* job, pointf* A, int n, bool arrow_at_start, bool arrow_at_end, bool filled);
		void AddPolygon(GVJ_t* job, pointf* A, int n, bool filled);
		void AddPolyline(GVJ_t* job, pointf* A, int n);
		void AddText(GVJ_t *job, pointf p, textspan_t *span);
		void AddAnchor(GVJ_t *job, char *url, char *tooltip, char *target, char *id);
		
	private:
		/* graphics and texts maintenance */
		void ClearGraphicsAndTexts();
		void AddGraphic(GVJ_t* job, Graphic* graphic);
		void AddText(GVJ_t* job, const Text &text);
		void AddHyperlink(GVJ_t* job, const Hyperlink &hyperlink);
		
		/* output the graphic as top level shape */
		void PrintOuterShape(GVJ_t* job, const Graphic &graphic);
		
		/* output the graphic as a subshape of a top level shape, given its id and bounds */
		void PrintInnerShape(GVJ_t* job, const Graphic& graphic, unsigned int outerId, boxf outerBounds);
		
		/* output the graphic as an edge connector, given the start and end node ids */
		bool PrintEdgeShape(GVJ_t* job, const Graphic &graphic, unsigned int beginId, unsigned int endId, int edgeType);
		
		/* output all the collected texts */
		void PrintTexts(GVJ_t* job);

		/* output all the collected hyperlinks */
		void PrintHyperlinks(GVJ_t* job);

		unsigned int _pageId = 0;	/* sequential page id, starting from 1 */
		unsigned int _shapeId = 0;	/* sequential shape id, starting from 1 */
		unsigned int _hyperlinkId = 0;	/* sequential shape id, starting from 1 */
		
		bool _inComponent = false;		/* whether we currently inside a node/edge, or not */
		
		Graphics _graphics;		/* currently collected graphics within a component */
		Texts _texts;			/* currently collected texts within a component */
		Hyperlinks _hyperlinks;	/* currently collected hyperlinks within a component */
		
		NodeIds _nodeIds;		/* mapping nodes to assigned shape id */
	};
}
