#ifdef ORCAD_TESTER
#	include "tester/read_fio.h"
#else
#	include "read_fio.h"
#endif

#include "read_common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static void indent_impl(FILE* const out, int indent)
{
	while(0<(indent--))
	{
		fputs("  ", out);
	}
}

#define indent_printf \
	indent_impl(stdout, indent), printf

#define indent_u(field) \
	indent_printf("%s: %lu\n", #field, (unsigned long)node->field)

#define indent_i(field) \
	indent_printf("%s: %li\n", #field, (long)node->field)

#define indent_x(field) \
	indent_printf("%s: 0x%lx\n", #field, (unsigned long)node->field)

#define indent_s(field) \
	indent_printf("%s: \"%s\"\n", #field, node->field)

#define dump_node_array(tag) \
	do \
	{ \
		indent_u(num_##tag##s); \
		orcad_dump_node_array((struct orcad_node**)node->tag##s, \
			node->num_##tag##s, indent); \
	} \
	while(0)

static void orcad_dump_node(struct orcad_node* const node, int indent);
static void orcad_dump_prim(struct orcad_prim* const prim, int indent);

static void orcad_dump_node_array(struct orcad_node** array, size_t count,
	int indent)
{
	while(0<(count--))
	{
		orcad_dump_node(*array++, indent);
	}
}

static void orcad_dump_node_common(struct orcad_node* const node, int indent)
{
	orcad_uint16_t i;

	indent_printf("num_namemappings: %u\n",
		(unsigned int)node->num_namemappings);

	for(i=0;i<node->num_namemappings;++i)
	{
		indent_printf("namemappings[%u]: %u -> %u\n", (unsigned int)i,
			(unsigned int)node->namemappings[i].name_idx,
			(unsigned int)node->namemappings[i].value_idx);
	}
}

static void orcad_dump_bitmap_prim(struct orcad_bitmap_prim* const node,
	int indent)
{
	indent_printf("begin bitmap\n");
	++indent;

	indent_i(x);
	indent_i(y);
	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);
	indent_u(bmp_width);
	indent_u(bmp_height);
	indent_u(bmp_datasize);

	--indent;
	indent_printf("end bitmap\n");
}

static void orcad_dump_text_prim(struct orcad_text_prim* const node,
	int indent)
{
	indent_printf("begin text\n");
	++indent;

	indent_i(x);
	indent_i(y);
	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);
	indent_u(font_id);
	indent_u(unknown_0);
	indent_s(text);

	--indent;
	indent_printf("end text\n");
}

static void orcad_dump_line_prim(struct orcad_line_prim* const node,
	int indent)
{
	indent_printf("begin line\n");
	++indent;

	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	--indent;
	indent_printf("end line\n");
}

static void orcad_dump_rect_prim(struct orcad_rect_prim* const node,
	int indent)
{
	indent_printf("begin rect\n");
	++indent;

	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	if(node->have_fill_style)
	{
		indent_u(fill_style);
		indent_u(hatch_style);
	}

	--indent;
	indent_printf("end rect\n");
}

static void orcad_dump_ellipse_prim(struct orcad_ellipse_prim* const node,
	int indent)
{
	indent_printf("begin ellipse\n");
	++indent;

	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	if(node->have_fill_style)
	{
		indent_u(fill_style);
		indent_u(hatch_style);
	}

	--indent;
	indent_printf("end ellipse\n");
}

static void orcad_dump_arc_prim(struct orcad_arc_prim* const node, int indent)
{
	indent_printf("begin arc\n");
	++indent;

	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);
	indent_i(start_x);
	indent_i(start_y);
	indent_i(end_x);
	indent_i(end_y);

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	--indent;
	indent_printf("end arc\n");
}

static void orcad_dump_polygon_prim(struct orcad_polygon_prim* const node,
	int indent)
{
	orcad_uint32_t i;

	indent_printf("begin polygon\n");
	++indent;

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	if(node->have_fill_style)
	{
		indent_u(fill_style);
		indent_u(hatch_style);
	}

	indent_u(num_points);

	for(i=0;i<node->num_points;++i)
	{
		indent_printf("point[%lu]: {%li, %li}\n", (unsigned long)i,
			(long)node->points[i].x,
			(long)node->points[i].y);
	}

	--indent;
	indent_printf("end polygon\n");
}

static void orcad_dump_polyline_prim(struct orcad_polyline_prim* const node,
	int indent)
{
	orcad_uint32_t i;

	indent_printf("begin polyline\n");
	++indent;

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	indent_u(num_points);

	for(i=0;i<node->num_points;++i)
	{
		indent_printf("point[%lu]: {%li, %li}\n", (unsigned long)i,
			(long)node->points[i].x,
			(long)node->points[i].y);
	}

	--indent;
	indent_printf("end polyline\n");
}

static void orcad_dump_bezier_prim(struct orcad_bezier_prim* const node,
	int indent)
{
	orcad_uint32_t i;

	indent_printf("begin bezier\n");
	++indent;

	if(node->have_line_style)
	{
		indent_u(line_style);
		indent_u(line_width);
	}

	indent_u(num_segments);

	for(i=0;i<node->num_segments;++i)
	{
		struct orcad_bsegment* const seg = &node->segments[i];

		indent_printf(
			"segment[%lu]: {%li, %li}, {%li, %li}, {%li, %li}, {%li, %li}\n",
			(unsigned long)i,
			(long)seg->p1.x, (long)seg->p1.y,
			(long)seg->p2.x, (long)seg->p2.y,
			(long)seg->p3.x, (long)seg->p3.y,
			(long)seg->p4.x, (long)seg->p4.y);
	}

	--indent;
	indent_printf("end bezier\n");
}

static void orcad_dump_symbolvector_prim(
	struct orcad_symbolvector_prim* const node, int indent)
{
	orcad_uint32_t i;

	indent_printf("begin symbolvector\n");
	++indent;

	indent_i(x);
	indent_i(y);

	indent_u(num_primitives);

	for(i=0;i<node->num_primitives;++i)
	{
		orcad_dump_prim(node->primitives[i], indent);
	}

	indent_s(name);

	--indent;
	indent_printf("end symbolvector\n");
}

static void orcad_dump_prim(struct orcad_prim* const prim, int indent)
{
	switch(prim->type)
	{
	case ORCAD_PRIMITIVE_RECT:
		orcad_dump_rect_prim((struct orcad_rect_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_LINE:
		orcad_dump_line_prim((struct orcad_line_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_ARC:
		orcad_dump_arc_prim((struct orcad_arc_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_ELLIPSE:
		orcad_dump_ellipse_prim((struct orcad_ellipse_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_POLYGON:
		orcad_dump_polygon_prim((struct orcad_polygon_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_POLYLINE:
		orcad_dump_polyline_prim((struct orcad_polyline_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_TEXT:
		orcad_dump_text_prim((struct orcad_text_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_BITMAP:
		orcad_dump_bitmap_prim((struct orcad_bitmap_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_BEZIER:
		orcad_dump_bezier_prim((struct orcad_bezier_prim*)prim, indent);
		break;

	case ORCAD_PRIMITIVE_SYMBOLVECTOR:
		orcad_dump_symbolvector_prim((struct orcad_symbolvector_prim*)prim,
			indent);
		break;

	default:
		fprintf(stderr, "Error: Primitive 0x%x is not handled!\n",
			(unsigned int)prim->type);
		break;
	}
}

static void orcad_dump_alias(struct orcad_alias_node* const node,
	int indent)
{
	indent_printf("begin alias\n");
	++indent;

	indent_u(x);
	indent_u(y);
	indent_u(color);
	indent_u(rotation);
	indent_u(mirrored);
	indent_u(unknown_0);
	indent_u(font_id);
	indent_u(unknown_1);
	indent_s(name);

	--indent;
	indent_printf("end alias\n");
}

static void orcad_dump_xnetalias(struct orcad_xnetalias_node* const node,
	int indent)
{
	indent_printf("begin x-netalias\n");
	++indent;

	indent_s(alias);
	indent_u(net_id);

	--indent;
	indent_printf("end x-netalias\n");
}

static void orcad_dump_netprop(struct orcad_netprop_node* const node,
	int indent)
{
	indent_printf("begin netprop\n");
	++indent;

	indent_u(net_id);
	indent_x(unknown[0]);
	indent_x(unknown[1]);
	indent_x(unknown[2]);
	indent_x(unknown[3]);
	indent_x(unknown[4]);
	indent_x(unknown[5]);
	indent_x(unknown[6]);
	indent_u(color);
	indent_u(line_width);
	indent_u(line_style);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end netprop\n");
}

static void orcad_dump_busprop(struct orcad_busprop_node* const node,
	int indent)
{
	orcad_uint16_t i;

	indent_printf("begin busprop\n");
	++indent;

	indent_u(net_id);
	indent_x(unknown[0]);
	indent_x(unknown[1]);
	indent_x(unknown[2]);
	indent_x(unknown[3]);
	indent_x(unknown[4]);
	indent_x(unknown[5]);
	indent_x(unknown[6]);
	indent_u(color);
	indent_u(line_width);
	indent_u(line_style);
	indent_u(num_busnetids);

	for(i=0;i<node->num_busnetids;++i)
	{
		indent_printf("busnetids[%i]: %lu\n", (unsigned int)i,
			(unsigned long)node->busnetids[i]);
	}

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end busprop\n");
}

static void orcad_dump_wire(struct orcad_wire_node* const node, int indent)
{
	indent_printf("begin wire\n");
	++indent;

	indent_u(wire_id);
	indent_u(net_id);
	indent_u(color);
	indent_u(start_x);
	indent_u(start_y);
	indent_u(end_x);
	indent_u(end_y);
	indent_x(unknown_0);

	dump_node_array(aliase);
	dump_node_array(displayprop);

	indent_u(line_width);
	indent_u(line_style);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end wire\n");
}

static void orcad_dump_pinconnection(
	struct orcad_pinconnection_node* const node, int indent)
{
	indent_printf("begin pinconnection\n");
	++indent;

	indent_i(nc);
	indent_i(idx);
	indent_u(x);
	indent_u(y);
	indent_i(wire_id);
	indent_u(net_id);

	dump_node_array(displayprop);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end pinconnection\n");
}

static void orcad_dump_symbolpin(struct orcad_symbolpin_node* const node,
	int indent)
{
	indent_printf("begin symbolpin\n");
	++indent;

	indent_s(pin_name);
	indent_i(start_x);
	indent_i(start_y);
	indent_i(hotpt_x);
	indent_i(hotpt_y);
	indent_u(pin_shape);
	indent_x(unknown_0);
	indent_u(port_type);
	indent_x(unknown_1);
	indent_x(unknown_2);

	dump_node_array(displayprop);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end symbolpin\n");
}

static void orcad_dump_pinidxmapping(
	struct orcad_pinidxmapping_node* const node, int indent)
{
	orcad_uint16_t i;

	indent_printf("begin pinidxmapping\n");
	++indent;

	indent_s(unit_ref);
	indent_s(symname);
	indent_u(num_pins);

	for(i=0;i<node->num_pins;++i)
	{
		struct orcad_pin* const pin = node->pins[i];

		indent_printf("begin pin[%i]\n", i);
		++indent;

		if(NULL==pin)
		{
			indent_printf("empty/missing\n");
		}
		else
		{
			indent_printf("pin_name: \"%s\"\n", pin->pin_name);
			indent_printf("pin_ignore: %u\n", (unsigned int)pin->pin_ignore);

			if(0<=pin->pin_group)
			{
				indent_printf("pin_group: %u\n", (unsigned int)pin->pin_group);
			}
			else
			{
				indent_printf("pin_group: empty\n");
			}
		}

		--indent;
		indent_printf("end pin[%i]\n", i);
	}

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end pinidxmapping\n");
}

static void orcad_dump_pagesettings__(
	const struct orcad_pagesettings* const settings, int indent)
{
	time_t tim;

	indent_printf("begin pagesettings\n");
	++indent;

	tim = settings->ctime;
	indent_printf("ctime: %s", ctime(&tim));

	tim = settings->mtime;
	indent_printf("mtime: %s", ctime(&tim));

	indent_printf("unknown_0: 0x%x\n", (unsigned int)settings->unknown_0);
	indent_printf("unknown_1: 0x%x\n", (unsigned int)settings->unknown_1);
	indent_printf("unknown_2: 0x%x\n", (unsigned int)settings->unknown_2);
	indent_printf("unknown_3: 0x%x\n", (unsigned int)settings->unknown_3);
	indent_printf("width: %lu\n", (unsigned long)settings->width);
	indent_printf("height: %lu\n", (unsigned long)settings->height);
	indent_printf("pin_to_pin: %u\n", (unsigned int)settings->pin_to_pin);
	indent_printf("unknown_4: 0x%x\n", (unsigned int)settings->unknown_4);
	indent_printf("horiz_count: %u\n", (unsigned int)settings->horiz_count);
	indent_printf("vert_count: %u\n", (unsigned int)settings->vert_count);
	indent_printf("unknown_5: 0x%x\n", (unsigned int)settings->unknown_5);
	indent_printf("horiz_width: %u\n", (unsigned int)settings->horiz_width);
	indent_printf("vert_width: %u\n", (unsigned int)settings->vert_width);
	indent_printf("unknown_6: 0x%x\n", (unsigned int)settings->unknown_6);
	indent_printf("unknown_7: 0x%x\n", (unsigned int)settings->unknown_7);
	indent_printf("unknown_8: 0x%x\n", (unsigned int)settings->unknown_8);
	indent_printf("unknown_9: 0x%x\n", (unsigned int)settings->unknown_9);
	indent_printf("unknown_10: 0x%x\n", (unsigned int)settings->unknown_10);
	indent_printf("unknown_11: 0x%x\n", (unsigned int)settings->unknown_11);
	indent_printf("unknown_12: 0x%x\n", (unsigned int)settings->unknown_12);
	indent_printf("unknown_13: 0x%x\n", (unsigned int)settings->unknown_13);
	indent_printf("unknown_14: 0x%x\n", (unsigned int)settings->unknown_14);
	indent_printf("unknown_15: 0x%x\n", (unsigned int)settings->unknown_15);
	indent_printf("unknown_16: 0x%x\n", (unsigned int)settings->unknown_16);
	indent_printf("unknown_17: 0x%x\n", (unsigned int)settings->unknown_17);
	indent_printf("horiz_char: %u\n", (unsigned int)settings->horiz_char);
	indent_printf("unknown_18: 0x%x\n", (unsigned int)settings->unknown_18);
	indent_printf("horiz_ascending: %u\n", (unsigned int)settings->horiz_ascending);
	indent_printf("vert_char: %u\n", (unsigned int)settings->vert_char);
	indent_printf("unknown_19: 0x%x\n", (unsigned int)settings->unknown_19);
	indent_printf("vert_ascending: %u\n", (unsigned int)settings->vert_ascending);
	indent_printf("is_metric: %u\n", (unsigned int)settings->is_metric);
	indent_printf("border_displayed: %u\n", (unsigned int)settings->border_displayed);
	indent_printf("border_printed: %u\n", (unsigned int)settings->border_printed);
	indent_printf("gridref_displayed: %u\n", (unsigned int)settings->gridref_displayed);
	indent_printf("gridref_printed: %u\n", (unsigned int)settings->gridref_printed);
	indent_printf("titleblock_displayed: %u\n", (unsigned int)settings->titleblock_displayed);
	indent_printf("titleblock_printed: %u\n", (unsigned int)settings->titleblock_printed);
	indent_printf("ansi_grid_refs: %u\n", (unsigned int)settings->ansi_grid_refs);

	--indent;
	indent_printf("end pagesettings\n");
}

static void orcad_dump_schematic(struct orcad_schematic_node* const node,
	int indent)
{
	orcad_uint16_t i;

	indent_printf("begin schematic\n");
	++indent;

	indent_s(sch_name);
	indent_x(unknown_0);
	indent_u(num_pagenames);

	for(i=0;i<node->num_pagenames;++i)
	{
		indent_printf("pagenames[%u]: \"%s\"\n", (unsigned int)i,
			node->pagenames[i]);
	}

	indent_u(num_unk4s);
	indent_u(num_unk5s);
	indent_x(unknown_1);

	--indent;
	indent_printf("end schematic\n");
}

static void orcad_dump_page(struct orcad_page_node* const node, int indent)
{
	indent_printf("begin page\n");
	++indent;

	indent_s(page_name);
	indent_s(page_size);

	orcad_dump_pagesettings__(&node->settings, indent);

	dump_node_array(titleblock);
	dump_node_array(netprop);
	dump_node_array(busprop);

	indent_u(num_netaliases);
	orcad_dump_node_array((struct orcad_node**)node->netaliases,
		node->num_netaliases, indent);

	dump_node_array(wire);
	dump_node_array(partinst);
	dump_node_array(port);
	dump_node_array(global);
	dump_node_array(offpageconn);
	indent_u(num_ercsymbolinsts);
	indent_u(num_busentries);
	dump_node_array(graphicinst);
	indent_u(num_unk10);
	indent_u(num_unk11);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end page\n");
}

static void orcad_dump__graphic_inline(
	struct orcad_graphic_inline* const node, int indent)
{
	indent_printf("begin graphic\n");
	++indent;

	indent_u(instname_idx);
	indent_u(libpath_idx);
	indent_s(name);
	indent_u(db_id);
	indent_i(x);
	indent_i(y);
	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);
	indent_u(color);
	indent_u(rotation);
	indent_u(mirrored);
	indent_x(unknown_2);
	indent_x(unknown_3);

	dump_node_array(displayprop);

	indent_printf("type: %s\n", orcad_type2str(node->type));

	if(NULL!=node->obj)
	{
		orcad_dump_node((struct orcad_node*)node->obj, indent);
	}

	--indent;
	indent_printf("end graphic\n");
}

static void orcad_dump_global(struct orcad_global_node* const node, int indent)
{
	indent_printf("begin global\n");
	++indent;

	orcad_dump__graphic_inline(&node->graphic, indent);

	indent_u(wire_id);
	indent_x(unknown_0);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end global\n");
}

static void orcad_dump_offpageconn(struct orcad_offpageconn_node* const node,
	int indent)
{
	indent_printf("begin offpageconn\n");
	++indent;

	orcad_dump__graphic_inline(&node->graphic, indent);

	indent_u(wire_id);
	indent_x(unknown_0);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end offpageconn\n");
}

static void orcad_dump_port(struct orcad_port_node* const node, int indent)
{
	indent_printf("begin port\n");
	++indent;

	orcad_dump__graphic_inline(&node->graphic, indent);

	indent_u(wire_id);
	indent_x(unknown_0);
	indent_x(unknown_1);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end port\n");
}

static void orcad_dump_ercsymbolinst(
	struct orcad_ercsymbolinst_node* const node, int indent)
{
	indent_printf("begin ercsymbolinst\n");
	++indent;

	orcad_dump__graphic_inline(&node->graphic, indent);

	indent_s(msg1);
	indent_s(msg2);
	indent_s(msg3);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end ercsymbolinst\n");
}

static void orcad_dump_partinst(struct orcad_partinst_node* const node,
	int indent)
{
	indent_printf("begin partinst\n");
	++indent;

	indent_u(instname_idx);
	indent_u(libpath_idx);
	indent_s(name);
	indent_u(db_id);
	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);
	indent_i(x);
	indent_i(y);
	indent_u(color);
	indent_u(rotation);
	indent_u(mirrored);
	indent_x(unknown_4);

	dump_node_array(displayprop);

	indent_x(unknown_5);
	indent_s(refdes);
	indent_u(value_idx);
	indent_x(unknown_7);
	indent_x(unknown_8);
	indent_x(unknown_9);
	indent_x(flags);
	indent_u(primitive);
	indent_u(power_pins_visible);
	dump_node_array(pinconnection);
	indent_s(symname);
	indent_u(pim_idx);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end partinst\n");
}

static void orcad_dump_graphicinst(struct orcad_graphicinst_node* const node,
	int indent)
{
	indent_printf("begin graphicinst\n");
	++indent;

	orcad_dump__graphic_inline(&node->graphic, indent);

	--indent;
	indent_printf("end graphicinst\n");
}

static void orcad_dump_inlinepageobject(
	struct orcad_inlinepageobject_node* const node, int indent)
{
	orcad_uint16_t i;

	indent_printf("begin inlinepageobject\n");
	++indent;

	indent_s(name);
	indent_s(unk_str);
	indent_u(color);
	indent_u(num_primitives);

	for(i=0;i<node->num_primitives;++i)
	{
		orcad_dump_prim(node->primitives[i], indent);
	}

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end inlinepageobject\n");
}

static void orcad_dump_symbol_common(
	const struct orcad_symbol_common* const common, int indent)
{
	indent_printf("name: \"%s\"\n", common->name);
	indent_printf("source: \"%s\"\n", common->source);
}

static void orcad_dump_titleblocksymbol(
	struct orcad_titleblocksymbol_node* const node, int indent)
{
	orcad_uint16_t i;

	indent_printf("begin titleblocksymbol\n");
	++indent;

	orcad_dump_symbol_common(&node->sym_common, indent);

	indent_x(unknown_0);
	indent_x(unknown_1);

	indent_u(num_primitives);

	for(i=0;i<node->num_primitives;++i)
	{
		orcad_dump_prim(node->primitives[i], indent);
	}

	indent_x(unknown_2);
	indent_x(unknown_3);

	dump_node_array(symbolpin);
	dump_node_array(displayprop);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end titleblocksymbol\n");
}

static void orcad_dump_titleblock(struct orcad_titleblock_node* const node,
	int indent)
{
	indent_printf("begin titleblock\n");
	++indent;

	indent_x(unknown_0);
	indent_x(unknown_1);

	indent_s(name);

	indent_x(unknown_2);
	indent_x(unknown_3);
	indent_x(unknown_4);
	indent_x(unknown_5);
	indent_x(unknown_6);
	indent_x(unknown_7);

	dump_node_array(displayprop);

	indent_x(unknown_8);
	indent_x(unknown_9);
	indent_x(unknown_10);
	indent_x(unknown_11);

	--indent;
	indent_printf("end titleblock\n");
}

static void orcad_dump_symbolgraphic(
	struct orcad_symbolgraphic_node* const node, int indent)
{
	orcad_uint16_t i;

	indent_printf("begin symbolgraphic\n");
	++indent;

	orcad_dump_symbol_common(&node->sym_common, indent);

	indent_x(unknown_0);
	indent_x(unknown_1);

	indent_u(num_primitives);

	for(i=0;i<node->num_primitives;++i)
	{
		orcad_dump_prim(node->primitives[i], indent);
	}

	indent_u(symbox_x);
	indent_u(symbox_y);
	dump_node_array(symbolpin);
	dump_node_array(displayprop);
	indent_s(unk_str0);
	indent_s(unk_str1);
	indent_s(sym_prefix);
	indent_s(unk_str2);
	indent_x(flags);
	indent_u(pin_names_visible);
	indent_u(pin_names_rotate);
	indent_u(pin_numbers_visible);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end symbolgraphic\n");
}

static void orcad_dump_properties(
	struct orcad_properties_node* const node, int indent)
{
	orcad_uint16_t i;

	indent_printf("begin properties\n");
	++indent;

	orcad_dump_symbol_common(&node->sym_common, indent);

	indent_u(num_partnames);

	for(i=0;i<node->num_partnames;++i)
	{
		indent_printf("partnames[%u]: \"%s\"\n", (unsigned int)i,
			node->partnames[i]);
	}

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end properties\n");
}

static void orcad_dump_symbolpinmapping(
	struct orcad_symbolpinmapping_node* const node, int indent)
{
	indent_printf("begin symbolpinmapping\n");
	++indent;

	orcad_dump_symbol_common(&node->sym_common, indent);

	indent_s(sym_prefix);
	indent_s(unk_str0);
	indent_s(unk_str1);
	dump_node_array(pinidxmapping);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end symbolpinmapping\n");
}

static void orcad_dump__symbol(struct orcad_globalsymbol_node* const node,
	int indent, const char* const name)
{
	orcad_uint16_t i;

	indent_printf("begin %s\n", name);
	++indent;

	orcad_dump_symbol_common(&node->sym_common, indent);

	indent_x(unknown_0);
	indent_x(unknown_1);

	indent_u(num_primitives);

	for(i=0;i<node->num_primitives;++i)
	{
		orcad_dump_prim(node->primitives[i], indent);
	}

	indent_u(symbox_x);
	indent_u(symbox_y);
	dump_node_array(symbolpin);
	dump_node_array(displayprop);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end %s\n", name);
}

static void orcad_dump_ercsymbol(struct orcad_ercsymbol_node* const node,
	int indent)
{
	orcad_uint16_t i;

	indent_printf("begin ercsymbol\n");
	++indent;

	orcad_dump_symbol_common(&node->sym_common, indent);

	indent_x(unknown_0);
	indent_x(unknown_1);

	indent_u(num_primitives);

	for(i=0;i<node->num_primitives;++i)
	{
		orcad_dump_prim(node->primitives[i], indent);
	}

	indent_i(x1);
	indent_i(y1);
	indent_i(x2);
	indent_i(y2);
	indent_i(x);
	indent_i(y);

	orcad_dump_node_common(&node->node, indent);

	--indent;
	indent_printf("end ercsymbol\n");
}

static void orcad_dump_symboldisplayprop(
	struct orcad_symboldisplayprop_node* const node, int indent)
{
	indent_printf("begin symboldisplayprop\n");
	++indent;

	indent_u(name_idx);
	indent_i(x);
	indent_i(y);
	indent_u(font_id);
	indent_u(rotation);
	indent_u(color);
	indent_x(unknown_0);
	indent_u(format);
	indent_x(unknown_2);

	--indent;
	indent_printf("end symboldisplayprop\n");
}

static void orcad_dump_xcache(struct orcad_xcache_node* const node, int indent)
{
	indent_printf("begin x-cache\n");
	++indent;

	orcad_dump_node((struct orcad_node*)node->titleblocks, indent);
	orcad_dump_node((struct orcad_node*)node->symbolgraphics, indent);
	orcad_dump_node((struct orcad_node*)node->symbolproperties, indent);
	orcad_dump_node((struct orcad_node*)node->symbolpinmappings, indent);

	--indent;
	indent_printf("end x-cache\n");
}

static void orcad_dump_xsymbolgroup(
	struct orcad_xsymbolgroup_node* const node, int indent)
{
	indent_printf("begin x-symbolgroup\n");
	++indent;

	dump_node_array(symbol);

	--indent;
	indent_printf("end x-symbolgroup\n");
}

static void orcad_dump_xcachesymbol(
	struct orcad_xcachesymbol_node* const node, int indent)
{
	indent_printf("begin x-cachesymbol\n");
	++indent;

	indent_s(symname);
	dump_node_array(variant);

	--indent;
	indent_printf("end x-cachesymbol\n");
}

static void orcad_dump_xcachesymvariant(
	struct orcad_xcachesymvariant_node* const node, int indent)
{
	time_t tim;

	indent_printf("begin x-cachesymvariant\n");
	++indent;

	indent_s(lib_path);

	tim = node->ctime;
	indent_printf("ctime: %s", ctime(&tim));

	tim = node->mtime;
	indent_printf("mtime: %s", ctime(&tim));

	indent_printf("type: %s\n", orcad_type2str(node->type));

	if(NULL!=node->obj)
	{
		orcad_dump_node(node->obj, indent);
	}

	--indent;
	indent_printf("end x-cachesymvariant\n");
}

static void orcad_dump_xlibrary(struct orcad_xlibrary_node* const node,
	int indent)
{
	time_t tim;
	orcad_uint32_t i;

	indent_printf("begin x-library\n");
	++indent;

	indent_s(introduction);
	indent_u(ver_major);
	indent_u(ver_minor);

	tim = node->ctime;
	indent_printf("ctime: %s", ctime(&tim));

	tim = node->mtime;
	indent_printf("mtime: %s", ctime(&tim));

	indent_u(num_fonts);
	/* do we need to display these fonts? */

	indent_u(num_unks);

	for(i=0;i<node->num_unks;++i)
	{
		indent_printf("unks[%u]: %u\n", (unsigned int)i,
			(unsigned int)node->unks[i]);
	}

	indent_x(unknown_0);
	indent_x(unknown_1);

	for(i=0;i<(sizeof(node->partfields)/sizeof(node->partfields[0]));++i)
	{
		indent_printf("partfields[%lu]: \"%s\"\n", (unsigned long)i,
			node->partfields[i]);
	}

	orcad_dump_pagesettings__(&node->settings, indent);

	indent_u(num_names);

	if(NULL!=node->names)
	{
		for(i=0;i<node->num_names;++i)
		{
			indent_printf("names[%lu]: \"%s\"\n", (unsigned long)i,
				node->names[i]);
		}
	}

	indent_u(num_aliases);

	if(NULL!=node->aliases)
	{
		for(i=0;i<node->num_aliases;++i)
		{
			indent_printf("begin aliases[%lu]\n", (unsigned long)i);
			++indent;
			indent_printf("alias: \"%s\"\n", node->aliases[i].alias);
			indent_printf("package: \"%s\"\n", node->aliases[i].package);
			--indent;
			indent_printf("end aliases[%u]\n", (unsigned int)i);
		}
	}

	indent_x(flags);
	indent_x(unknown_3);

	indent_printf("sch_name: \"%s\"\n", node->sch_name);

	--indent;
	indent_printf("end x-library\n");
}

static void orcad_dump_node(struct orcad_node* const node, int indent)
{
	switch(node->type)
	{
	case ORCAD_TYPE_INLINEPAGEOBJECT:
		orcad_dump_inlinepageobject((struct orcad_inlinepageobject_node*)node,
			indent);
		break;

	case ORCAD_TYPE_PROPERTIES:
		orcad_dump_properties((struct orcad_properties_node*)node, indent);
		break;

	case ORCAD_TYPE_SCHEMATIC:
		orcad_dump_schematic((struct orcad_schematic_node*)node, indent);
		break;

	case ORCAD_TYPE_PAGE:
		orcad_dump_page((struct orcad_page_node*)node, indent);
		break;

	case ORCAD_TYPE_PARTINST:
		orcad_dump_partinst((struct orcad_partinst_node*)node, indent);
		break;

	case ORCAD_TYPE_PINCONNECTION:
		orcad_dump_pinconnection((struct orcad_pinconnection_node*)node,
			indent);
		break;

	case ORCAD_TYPE_WIRE:
		orcad_dump_wire((struct orcad_wire_node*)node, indent);
		break;

	case ORCAD_TYPE_PORT:
		orcad_dump_port((struct orcad_port_node*)node, indent);
		break;

	case ORCAD_TYPE_ERCSYMBOLINST:
		orcad_dump_ercsymbolinst((struct orcad_ercsymbolinst_node*)node,
			indent);
		break;

	case ORCAD_TYPE_SYMBOLGRAPHIC:
		orcad_dump_symbolgraphic((struct orcad_symbolgraphic_node*)node,
			indent);
		break;

	case ORCAD_TYPE_SYMBOLPIN:
		orcad_dump_symbolpin((struct orcad_symbolpin_node*)node, indent);
		break;

	case ORCAD_TYPE_SYMBOLPINMAPPING:
		orcad_dump_symbolpinmapping((struct orcad_symbolpinmapping_node*)node,
			indent);
		break;

	case ORCAD_TYPE_PINIDXMAPPING:
		orcad_dump_pinidxmapping((struct orcad_pinidxmapping_node*)node,
			indent);
		break;

	case ORCAD_TYPE_GLOBALSYMBOL:
		orcad_dump__symbol((struct orcad_globalsymbol_node*)node, indent,
			"globalsymbol");
		break;

	case ORCAD_TYPE_PORTSYMBOL:
		orcad_dump__symbol((struct orcad_globalsymbol_node*)node, indent,
			"portsymbol");
		break;

	case ORCAD_TYPE_OFFPAGECONNSYMBOL:
		orcad_dump__symbol((struct orcad_globalsymbol_node*)node, indent,
			"offpageconnsymbol");
		break;

	case ORCAD_TYPE_GLOBAL:
		orcad_dump_global((struct orcad_global_node*)node, indent);
		break;

	case ORCAD_TYPE_OFFPAGECONN:
		orcad_dump_offpageconn((struct orcad_offpageconn_node*)node, indent);
		break;

	case ORCAD_TYPE_SYMBOLDISPLAYPROP:
		orcad_dump_symboldisplayprop(
			(struct orcad_symboldisplayprop_node*)node, indent);
		break;

	case ORCAD_TYPE_NETPROP:
		orcad_dump_netprop((struct orcad_netprop_node*)node, indent);
		break;

	case ORCAD_TYPE_BUSPROP:
		orcad_dump_busprop((struct orcad_busprop_node*)node, indent);
		break;

	case ORCAD_TYPE_GRAPHICBOXINST:
	case ORCAD_TYPE_GRAPHICLINEINST:
	case ORCAD_TYPE_GRAPHICARCINST:
	case ORCAD_TYPE_GRAPHICELLIPSEINST:
	case ORCAD_TYPE_GRAPHICPOLYGONINST:
	case ORCAD_TYPE_GRAPHICTEXTINST:
	case ORCAD_TYPE_GRAPHICBITMAPINST:
	case ORCAD_TYPE_GRAPHICBEZIERINST:
		orcad_dump_graphicinst((struct orcad_graphicinst_node*)node, indent);
		break;

	case ORCAD_TYPE_TITLEBLOCKSYMBOL:
		orcad_dump_titleblocksymbol((struct orcad_titleblocksymbol_node*)node,
			indent);
		break;

	case ORCAD_TYPE_TITLEBLOCK:
		orcad_dump_titleblock((struct orcad_titleblock_node*)node, indent);
		break;

	case ORCAD_TYPE_ERCSYMBOL:
		orcad_dump_ercsymbol((struct orcad_ercsymbol_node*)node, indent);
		break;

	case ORCAD_TYPE_ALIAS:
		orcad_dump_alias((struct orcad_alias_node*)node, indent);
		break;

	case ORCAD_TYPE_X_NETALIAS:
		orcad_dump_xnetalias((struct orcad_xnetalias_node*)node, indent);
		break;

	case ORCAD_TYPE_X_CACHE:
		orcad_dump_xcache((struct orcad_xcache_node*)node, indent);
		break;

	case ORCAD_TYPE_X_SYMBOLGROUP:
		orcad_dump_xsymbolgroup((struct orcad_xsymbolgroup_node*)node, indent);
		break;

	case ORCAD_TYPE_X_CACHESYMBOL:
		orcad_dump_xcachesymbol((struct orcad_xcachesymbol_node*)node, indent);
		break;

	case ORCAD_TYPE_X_CACHESYMVARIANT:
		orcad_dump_xcachesymvariant((struct orcad_xcachesymvariant_node*)node,
			indent);
		break;

	case ORCAD_TYPE_X_LIBRARY:
		orcad_dump_xlibrary((struct orcad_xlibrary_node*)node, indent);
		break;

	default:
		fprintf(stderr, "Error: Type 0x%x (%s) is not handled!\n",
			(unsigned int)node->type, orcad_type2str(node->type));
		break;
	}
}

void orcad_dump(struct orcad_node* const root)
{
	orcad_dump_node(root, 0);
}
