#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 <ctype.h>

static int orcad_cmp_pagename_reverse(const void* a, const void* b)
{
	const char* lhs = *(const char**)a;
	const char* rhs = *(const char**)b;

	while(*lhs && *rhs && (*lhs == *rhs || tolower(*lhs) == tolower(*rhs)))
	{
		++lhs;
		++rhs;
	}

	/* we want reverse order, swap final comparison! */
	return tolower(*rhs) - tolower(*lhs);
}

static long orcad_read_schematic__(struct io_orcad_rctx_s* const rctx,
	long offs, struct orcad_node** const out_node)
{
	orcad_uint16_t i;

	struct orcad_node* const parent = NULL;

	orcad_create_node(struct orcad_schematic_node, ORCAD_TYPE_SCHEMATIC);

	if(0>(offs=orcad_read_string2(rctx, offs, &node->sch_name)))
	{
		fprintf(stderr, "Error: Could not read sch_name\n");
		return -1;
	}

	read_u32(unknown_0);

	read_u16(num_pagenames);

	if(NULL==(node->pagenames=(char**)calloc(node->num_pagenames,
		sizeof(char*))))
	{
		fprintf(stderr, "Error: Could not allocate 'pagenames'\n");
		return -1;
	}

	for(i=0;i<node->num_pagenames;++i)
	{
		if(0>(offs=orcad_read_string2(rctx, offs, &node->pagenames[i])))
		{
			fprintf(stderr, "Error: Could not read pagenames[%u]\n",
				(unsigned int)i);
			return -1;
		}
	}

	/* we sort pagenames in reverse order, because the page loader would */
	/* need only a single variable to do so ("how many pages left") */
	qsort(node->pagenames, node->num_pagenames, sizeof(char*),
		orcad_cmp_pagename_reverse);

	read_u16(num_unk4s);

	if(NULL==(node->unk4s=(orcad_uint32_t*)calloc(node->num_unk4s,
		sizeof(orcad_uint32_t))))
	{
		fprintf(stderr, "Error: Could not allocate 'unk4s'\n");
		return -1;
	}

	for(i=0;i<node->num_unk4s;++i)
	{
		if(0>(offs=orcad_read_field_u32(rctx, offs, &node->unk4s[i])))
		{
			fprintf(stderr, "Error: Could not read unk4s[%u]\n",
				(unsigned int)i);
			return -1;
		}
	}

	read_u16(num_unk5s);

	if(NULL==(node->unk5s=(unsigned char*)calloc(node->num_unk5s, 5)))
	{
		fprintf(stderr, "Error: Could not allocate 'unk5s'\n");
		return -1;
	}

	for(i=0;i<node->num_unk5s;++i)
	{
		if(5!=fio_fread(rctx, (char*)(node->unk5s+i*5), 5))
		{
			fprintf(stderr, "Error: Could not read unk5s[%u]\n",
				(unsigned int)i);
			return -1;
		}

		offs += 5;
	}

	read_u32(unknown_1);

	return offs;
}

struct orcad_node* orcad_read_schematic(struct io_orcad_rctx_s* const rctx)
{
	struct orcad_node* res = NULL;

	long offs = orcad_read_schematic__(rctx, 0, &res);

	if(0>offs)
	{
		if(NULL!=res)
		{
			orcad_free(res);
		}

		return NULL;
	}

	{
		char c;

		if(0<fio_fread(rctx, &c, 1))
		{
			fprintf(stderr, "Error: Schematic was not interpreted correctly!\n");
			fprintf(stderr, "Ending offs: %li (0x%lx)\n", offs, offs);

			if(NULL!=res)
			{
				orcad_free(res);
			}

			return NULL;
		}
	}

	return res;
}
