#include "IrFoxAnalyzerResults.h"
#include <AnalyzerHelpers.h>
#include <AnalyzerResults.h>
#include "IrFoxAnalyzer.h"
#include "IrFoxAnalyzerSettings.h"
#include "IrFoxDecoder.h"
#include <cstdio>
#include <fstream>

IrFoxAnalyzerResults::IrFoxAnalyzerResults(IrFoxAnalyzer* analyzer, IrFoxAnalyzerSettings* settings)
	: AnalyzerResults(),
	  mSettings(settings),
	  mAnalyzer(analyzer)
{
}

IrFoxAnalyzerResults::~IrFoxAnalyzerResults()
{
}

void IrFoxAnalyzerResults::GenerateBubbleText(U64 frame_index, Channel& channel, DisplayBase display_base)
{
	(void)display_base;
	(void)channel;
	ClearResultStrings();
	Frame frame = GetFrame(frame_index);

	char line[256];

	switch (frame.mType)
	{
	case IRF_FT_DATA_BIT:
	case IRF_FT_SYNC_BIT:
	case IRF_FT_PREAMBLE:
	case IRF_FT_OVERFLOW:
	case IRF_FT_ABORT:
	{
		const char* bt = mAnalyzer->BubbleTextForFrame(frame_index);
		if (bt && bt[0])
			AddResultString(bt);
		else if (frame.mType == IRF_FT_DATA_BIT)
			AddResultString(frame.mData1 ? "1" : "0");
		else if (frame.mType == IRF_FT_SYNC_BIT)
		{
			snprintf(line, sizeof line, "sync: %s", frame.mData1 ? "1" : "0");
			AddResultString(line);
		}
		else if (frame.mType == IRF_FT_OVERFLOW)
			AddResultString("OVF");
		else if (frame.mType == IRF_FT_ABORT)
			AddResultString("SYNC!");
		else
			AddResultString("PRE");
		break;
	}

	case IRF_FT_PACKET_OK:
	case IRF_FT_PACKET_CRC_FAIL:
	{
		snprintf(line, sizeof line, "%s %lluB", frame.mType == IRF_FT_PACKET_OK ? "OK" : "CRC",
				 (unsigned long long)frame.mData1);
		AddResultString(line);
		const char* hx = mAnalyzer->PacketHexForFrame(frame_index);
		if (hx && hx[0])
			AddResultString(hx);
		break;
	}

	default:
		snprintf(line, sizeof line, "? type=%u", static_cast<unsigned>(frame.mType));
		AddResultString(line);
		break;
	}
}

void IrFoxAnalyzerResults::GenerateExportFile(const char* file, DisplayBase display_base, U32 export_type_user_id)
{
	(void)export_type_user_id;
	(void)display_base;
	std::ofstream file_stream(file, std::ios::out);

	const U64 trigger_sample = mAnalyzer->GetTriggerSample();
	const U32 sample_rate = mAnalyzer->GetSampleRate();

	file_stream << "Time[s],Type,Data1,bit_idx,err_low,err_high,err_other,Flags,Hex" << std::endl;

	const U64 num_frames = GetNumFrames();
	for (U32 i = 0; i < num_frames; i++)
	{
		Frame frame = GetFrame(i);

		char time_str[128];
		AnalyzerHelpers::GetTimeString(frame.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, 128);

		const char* typ = "?";
		switch (frame.mType)
		{
		case IRF_FT_DATA_BIT:
			typ = "D";
			break;
		case IRF_FT_SYNC_BIT:
			typ = "S";
			break;
		case IRF_FT_PACKET_OK:
			typ = "OK";
			break;
		case IRF_FT_PACKET_CRC_FAIL:
			typ = "CRC";
			break;
		case IRF_FT_OVERFLOW:
			typ = "OVF";
			break;
		case IRF_FT_ABORT:
			typ = "ABORT";
			break;
		case IRF_FT_PREAMBLE:
			typ = "PRE";
			break;
		default:
			break;
		}

		const char* hx = mAnalyzer->PacketHexForFrame(i);
		if (!hx)
			hx = "";

		U64 bit_idx = 0;
		U32 err_l = 0, err_h = 0, err_o = 0;
		if (frame.mType == IRF_FT_DATA_BIT || frame.mType == IRF_FT_SYNC_BIT ||
			frame.mType == IRF_FT_OVERFLOW || frame.mType == IRF_FT_ABORT)
		{
			bit_idx = frame.mData2 & 0xFFFFull;
			err_l = static_cast<U32>((frame.mData2 >> 16) & 0xFFull);
			err_h = static_cast<U32>((frame.mData2 >> 24) & 0xFFull);
			err_o = static_cast<U32>((frame.mData2 >> 32) & 0xFFull);
		}

		file_stream << time_str << "," << typ << "," << frame.mData1 << "," << bit_idx << "," << err_l << "," << err_h
					<< "," << err_o << "," << static_cast<unsigned>(frame.mFlags) << "," << hx << std::endl;

		if (UpdateExportProgressAndCheckForCancel(i, num_frames) == true)
		{
			file_stream.close();
			return;
		}
	}

	file_stream.close();
}

void IrFoxAnalyzerResults::GenerateFrameTabularText(U64 frame_index, DisplayBase display_base)
{
#ifdef SUPPORTS_PROTOCOL_SEARCH
	(void)display_base;
	Frame frame = GetFrame(frame_index);
	ClearTabularText();
	char buf[64];
	snprintf(buf, sizeof buf, "t%u", static_cast<unsigned>(frame.mType));
	AddTabularText(buf);
	snprintf(buf, sizeof buf, "%llu", (unsigned long long)frame.mData1);
	AddTabularText(buf);
#endif
}

void IrFoxAnalyzerResults::GeneratePacketTabularText(U64 packet_id, DisplayBase display_base)
{
	(void)packet_id;
	(void)display_base;
}

void IrFoxAnalyzerResults::GenerateTransactionTabularText(U64 transaction_id, DisplayBase display_base)
{
	(void)transaction_id;
	(void)display_base;
}
