#ifndef ORCAD_READ_PARSE_H
#define ORCAD_READ_PARSE_H

/* TODO: replace ASAP! */
#include <stdint.h>
typedef uint8_t  my_uint8_t;
typedef int16_t  my_int16_t;
typedef uint16_t my_uint16_t;
typedef int32_t  my_int32_t;
typedef uint32_t my_uint32_t;

struct io_orcad_rctx_s;
struct orcad_inlinepageobject_node;
struct orcad_prim;

enum orcad_type
{
	ORCAD_TYPE_INLINEPAGEOBJECT   = 0x02,
	ORCAD_TYPE_PROPERTIES         = 0x06,
	ORCAD_TYPE_PAGE               = 0x0a,
	ORCAD_TYPE_PARTINST           = 0x0d,
	ORCAD_TYPE_0x10               = 0x10,
	ORCAD_TYPE_WIRE               = 0x14,
	ORCAD_TYPE_PORT               = 0x17,
	ORCAD_TYPE_SYMBOLGRAPHIC      = 0x18,
	ORCAD_TYPE_SYMBOLPIN          = 0x1a,
	ORCAD_TYPE_SYMBOLPINMAPPING   = 0x1f,
	ORCAD_TYPE_PINIDXMAPPING      = 0x20,
	ORCAD_TYPE_GLOBALSYMBOL       = 0x21,
	ORCAD_TYPE_PORTSYMBOL         = 0x22,
	ORCAD_TYPE_OFFPAGECONNSYMBOL  = 0x23,
	ORCAD_TYPE_GLOBAL             = 0x25,
	ORCAD_TYPE_OFFPAGECONN        = 0x26,
	ORCAD_TYPE_SYMBOLDISPLAYPROP  = 0x27,
	ORCAD_TYPE_NETPROP            = 0x34,
	ORCAD_TYPE_GRAPHICBOXINST     = 0x37,
	ORCAD_TYPE_GRAPHICLINEINST    = 0x38,
	ORCAD_TYPE_GRAPHICARCINST     = 0x39,
	ORCAD_TYPE_GRAPHICELLIPSEINST = 0x3a,
	ORCAD_TYPE_GRAPHICPOLYGONINST = 0x3b,
	ORCAD_TYPE_GRAPHICTEXTINST    = 0x3d,
	ORCAD_TYPE_TITLEBLOCKSYMBOL   = 0x40,
	ORCAD_TYPE_TITLEBLOCK         = 0x41,
	ORCAD_TYPE_GRAPHICBEZIERINST  = 0x58,

	/* additional types that are not part of the binary format */

	ORCAD_TYPE_X_CACHE            = 0x1000
};

enum orcad_primtype
{
	ORCAD_PRIMITIVE_RECT        = 0x28,
	ORCAD_PRIMITIVE_LINE        = 0x29,
	ORCAD_PRIMITIVE_ARC         = 0x2a,
	ORCAD_PRIMITIVE_ELLIPSE     = 0x2b,
	ORCAD_PRIMITIVE_POLYGON     = 0x2c,
	ORCAD_PRIMITIVE_POLYLINE    = 0x2d,
	ORCAD_PRIMITIVE_TEXT        = 0x2e,
	ORCAD_PRIMITIVE_BEZIER      = 0x57
};

struct orcad_netalias
{
	char alias[256];
	my_uint32_t net_id;
};

struct orcad_graphic_inline
{
	my_uint32_t unknown_0;
	my_uint32_t unknown_1;
	char name[256];
	my_uint32_t db_id;
	my_uint16_t y;
	my_uint16_t x;
	my_uint16_t y2;
	my_uint16_t x2;
	my_uint16_t x1;
	my_uint16_t y1;
	my_uint8_t  color;
	my_uint8_t  rotation;
	my_uint8_t  unknown_2;
	my_uint8_t  unknown_3;

	my_uint16_t num_displayprops;

	enum orcad_type type;

	struct orcad_inlinepageobject_node* obj;
};

struct orcad_node
{
	enum orcad_type    type;
	struct orcad_node* parent;

	/* offset where the object payload starts */
	long offs;

	/* size of the object according to orcad_header */
	long size;
};

struct orcad_netprop_node
{
	struct orcad_node node;

	my_uint32_t net_id;
	my_uint8_t  unknown[7];
	my_uint32_t color;
	my_uint32_t line_width;
	my_uint32_t line_style;
};

struct orcad_wire_node
{
	struct orcad_node node;

	my_uint32_t wire_id;
	my_uint32_t net_id;
	my_uint32_t color;
	my_uint32_t start_x;
	my_uint32_t start_y;
	my_uint32_t end_x;
	my_uint32_t end_y;
	my_uint8_t  unknown_0; /* related to junctions */

	my_uint16_t num_alias;

	my_uint16_t num_displayprops;

	my_uint32_t line_width;
	my_uint32_t line_style;
};

struct orcad_inlinepageobject_node
{
	struct orcad_node node;

	char name[256];
	char unk_str[256];
	my_uint32_t color;

	my_uint16_t num_primitives;
	struct orcad_prim** primitives;
};

struct orcad_port_node
{
	struct orcad_node node;
	struct orcad_graphic_inline graphic;

	my_uint32_t wire_id;
	my_uint8_t  unknown_0;
	my_uint32_t unknown_1;
};

struct orcad_global_node
{
	struct orcad_node node;
	struct orcad_graphic_inline graphic;

	my_uint32_t wire_id;
	my_uint8_t  unknown_0;
};

struct orcad_offpageconn_node
{
	struct orcad_node node;
	struct orcad_graphic_inline graphic;

	my_uint32_t wire_id;
	my_uint8_t  unknown_0;
};

struct orcad_graphicinst_node
{
	struct orcad_node node;
	struct orcad_graphic_inline graphic;
};

struct orcad_T0x10_node
{
	struct orcad_node node;

	my_int16_t  nc; /* pin is no connect */
	my_int16_t  idx;
	my_uint16_t x;
	my_uint16_t y;
	my_uint32_t wire_id;
	my_uint32_t unknown_0;

	my_uint16_t num_displayprops;
};

struct orcad_partinst_node
{
	struct orcad_node node;

	my_uint32_t unknown_0;
	my_uint32_t unknown_1;
	char name[256];
	my_uint32_t db_id;
	my_uint32_t unknown_2;
	my_uint32_t unknown_3;
	my_uint16_t x;
	my_uint16_t y;
	my_uint32_t unknown_4;

	my_uint16_t num_displayprops;

	my_uint8_t unknown_5;
	char refdes[256];
	my_uint32_t unknown_6;
	my_uint32_t unknown_7;
	my_uint32_t unknown_8;
	my_uint16_t unknown_9;

	my_uint16_t num_T0x10s;
	struct orcad_T0x10_node* T0x10s;

	char symname[256];
	my_uint16_t unknown_11;
};

struct orcad_pagesettings
{
	my_uint32_t ctime;
	my_uint32_t mtime;
	my_uint32_t unknown_0;
	my_uint32_t unknown_1;
	my_uint32_t unknown_2;
	my_uint32_t unknown_3;
	my_uint32_t width;  /* sheet width in mils */
	my_uint32_t height; /* sheet height in mils */
	my_uint32_t pin_to_pin;
	my_uint16_t unknown_4;
	my_uint16_t horiz_count; /* this is the resolution of the guides at */
	my_uint16_t vert_count;  /* ... the edge of the page */
	my_uint16_t unknown_5; /* some flags? */
	my_uint32_t horiz_width; /* maybe grid resolution? */
	my_uint32_t vert_width;  /* maybe grid resolution? */
	my_uint32_t unknown_6;
	my_uint32_t unknown_7;
	my_uint32_t unknown_8;
	my_uint32_t unknown_9;
	my_uint32_t unknown_10;
	my_uint32_t unknown_11;
	my_uint32_t unknown_12;
	my_uint32_t unknown_13;
	my_uint32_t unknown_14;
	my_uint32_t unknown_15;
	my_uint32_t unknown_16;
	my_uint32_t unknown_17;
	my_uint32_t horiz_char;
	my_uint32_t unknown_18;
	my_uint32_t horiz_ascending;
	my_uint32_t vert_char;
	my_uint32_t unknown_19;
	my_uint32_t vert_ascending;
	my_uint32_t is_metric;
	my_uint32_t border_displayed;
	my_uint32_t border_printed;
	my_uint32_t gridref_displayed;
	my_uint32_t gridref_printed;
	my_uint32_t titleblock_displayed;
	my_uint32_t titleblock_printed;
	my_uint32_t ansi_grid_refs;
};

struct orcad_page_node
{
	struct orcad_node node;

	char page_name[256];
	char page_size[64];

	struct orcad_pagesettings settings;

	my_uint16_t num_titleblocks;

	my_uint16_t num_netprops;
	struct orcad_netprop_node** netprops;

	/* unknown T0x35 objects */
	my_uint16_t num_T0x35s;

	my_uint16_t num_netaliases;
	struct orcad_netalias** netaliases;

	my_uint16_t num_wires;
	struct orcad_wire_node** wires;

	my_uint16_t num_partinsts;
	struct orcad_partinst_node** partinsts;

	my_uint16_t num_ports;
	struct orcad_port_node** ports;

	my_uint16_t num_globals;
	struct orcad_global_node** globals;

	my_uint16_t num_offpageconns;
	struct orcad_offpageconn_node** offpageconns;

	my_uint16_t num_ercsymbolinsts;

	my_uint16_t num_busentries;

	my_uint16_t num_graphicinsts;
	struct orcad_graphicinst_node** graphicinsts;

	my_uint16_t num_unk10;

	my_uint16_t num_unk11;
};

struct orcad_symbolpin_node
{
	struct orcad_node node;

	char pin_name[256];
	my_int32_t start_x;
	my_int32_t start_y;
	my_int32_t hotpt_x;
	my_int32_t hotpt_y;
	my_uint16_t pin_shape;
	my_uint16_t unknown_0;
	my_uint16_t port_type;
	my_uint16_t unknown_1;
	my_uint16_t unknown_2;

	my_uint16_t num_displayprops;
};

struct orcad_pin
{
	char pin_name[256];
	my_uint8_t pin_ignore;
	my_uint8_t pin_group;
};

struct orcad_pinidxmapping_node
{
	struct orcad_node node;

	char unit_ref[256];
	char symname[256];

	my_uint16_t num_pins;
	struct orcad_pin** pins; /* note: some of 'pins[i]' might be NULL! */
};

struct orcad_point
{
	my_uint16_t x;
	my_uint16_t y;
};

struct orcad_bsegment
{
	struct orcad_point p1;
	struct orcad_point p2;
	struct orcad_point p3;
	struct orcad_point p4;
};

struct orcad_prim
{
	enum orcad_primtype type;
	long offs;
};

struct orcad_text_prim
{
	struct orcad_prim prim;

	my_int32_t  x;
	my_int32_t  y;
	my_int32_t  x1;
	my_int32_t  y1;
	my_int32_t  x2;
	my_int32_t  y2;
	my_uint16_t font_id;
	my_uint16_t unknown_0;
	char text[256];
};

struct orcad_line_prim
{
	struct orcad_prim prim;

	my_int32_t x1;
	my_int32_t y1;
	my_int32_t x2;
	my_int32_t y2;

	int have_line_style; /* line_style and line_width */
	my_uint32_t line_style;
	my_uint32_t line_width;
};

struct orcad_rect_prim
{
	struct orcad_prim prim;

	my_int32_t x1;
	my_int32_t y1;
	my_int32_t x2;
	my_int32_t y2;

	int have_line_style; /* line_style and line_width */
	my_uint32_t line_style;
	my_uint32_t line_width;

	int have_fill_style; /* fill_style and hatch_style */
	my_uint32_t fill_style;
	my_uint32_t hatch_style;
};

struct orcad_arc_prim
{
	struct orcad_prim prim;

	/*
		[x1, y1], [x2, y2] is the bbox
		[start_x, start_y] is the starting point of the arc
		[end_x, end_y] is the ending point of the arc

		the arc is drawn from start point to end point in CCW direction
	*/

	my_int32_t x1;
	my_int32_t y1;
	my_int32_t x2;
	my_int32_t y2;
	my_int32_t start_x;
	my_int32_t start_y;
	my_int32_t end_x;
	my_int32_t end_y;

	int have_line_style; /* line_style and line_width */
	my_uint32_t line_style;
	my_uint32_t line_width;
};

struct orcad_ellipse_prim
{
	struct orcad_prim prim;

	my_int32_t x1;
	my_int32_t y1;
	my_int32_t x2;
	my_int32_t y2;

	int have_line_style; /* line_style and line_width */
	my_uint32_t line_style;
	my_uint32_t line_width;

	int have_fill_style; /* fill_style and hatch_style */
	my_uint32_t fill_style;
	my_uint32_t hatch_style;
};

struct orcad_polygon_prim
{
	struct orcad_prim prim;

	int have_line_style; /* line_style and line_width */
	my_uint32_t line_style;
	my_uint32_t line_width;

	int have_fill_style; /* fill_style and hatch_style */
	my_uint32_t fill_style;
	my_uint32_t hatch_style;

	my_uint32_t num_points;
	struct orcad_point* points;
};

struct orcad_bezier_prim
{
	struct orcad_prim prim;

	int have_line_style; /* line_style and line_width */
	my_uint32_t line_style;
	my_uint32_t line_width;

	my_uint32_t num_segments;
	struct orcad_bsegment* segments;
};

struct orcad_node* orcad_read(struct io_orcad_rctx_s* const rctx);
/*struct orcad_node* orcad_read_cache(struct io_orcad_rctx_s* const rctx);*/

void orcad_dump(struct orcad_node* const root);
void orcad_free(struct orcad_node* const root);

#endif /* ORCAD_READ_PARSE_H */
