#include "stdio.h"
#include "asa.h"
#include <math.h>
#ifdef WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif

#define MIN_VAR_V_DEFAULT 0.6
#define MIN_VAR_C_DEFAULT 0.0002
#define N_POINTS 512  // number_points must be 256 or 512

/**
 * Function writes information about last operation with server.
 * @param Server: server with measuring device;
 * @param Status: status of last operation;
 * @FuncName: name of last operation.
 */
void CheckStatus(server_t* Server, status_t Status, char* FuncName)
{
	int WaitIter = 0;
	while (Status == ASA_IN_PROGRESS)
	{
		if (WaitIter == 0)
		{
			printf("Operation is in progress");
		}
		else if (WaitIter % 10 == 0)
		{
			printf(".");
		}
		WaitIter++;
		Status = GetLastOperationResult(Server);
		if (Status == ASA_OK)
		{
			printf("\n%s is done!\n", FuncName);
			break;
		}
		else if (Status != ASA_IN_PROGRESS && Status != ASA_OK)
		{
			printf("\n");
			break;
		}
	}
	if (Status == ASA_CONNECTION_ERROR)
	{
		printf("ConnectionError during %s call. ConnectionError code: %d\n", FuncName, Status);
		exit(-1);
	}
	else if (Status < ASA_OK)
	{
		printf("Error during %s call. Error code: %d\n", FuncName, Status);
		exit(-1);
	}
}

/**
 * Function sleeps given msec.
 * @param sleep_time: time to sleep in msec.
 */
void SleepMSec(int sleep_time)
{
#ifdef _WIN32
	Sleep(sleep_time);
#else
	usleep(sleep_time * 1000);
#endif
}

int main(int const argc, const char** const argv)
{
	// Setup server settings
	server_t Server;
	char DeviceURL[64];
	printf("Enter ASA device IP address (format: 192.168.1.1): ");
#if defined(WIN32)
	scanf_s("%s", DeviceURL, 64);
#else
	scanf("%s", DeviceURL, 64);
#endif
	Server.Host = DeviceURL;
	Server.Port = "8888";

	// For checking errors
	status_t Status;
	version_t Version = GetLibraryVersion();
	printf("Using libasa %d.%d.%d\n", Version.Major, Version.Minor, Version.Bugfix);
	version_t API_Version = GetAPIVersion();
	printf("Using API %d.%d.%d\n", API_Version.Major, API_Version.Minor, API_Version.Bugfix);

	printf("-- Update device settings --\n");
	asa_settings_t SettingsOut;
	SettingsOut.SamplingRateHz = 100.0;  // may be any value from 0 to 10^11
	SettingsOut.NumberPoints = N_POINTS;
	SettingsOut.NumberChargePoints = N_POINTS;  // may be any value from 0 to 10^7
	SettingsOut.ProbeSignalFrequencyHz = 1;
	SettingsOut.VoltageAmplV = 1; // Use (max current, max voltage) combinations
	SettingsOut.MaxCurrentMA = 10; // from specification here !!! Other combinations will cause errors.
	SettingsOut.MeasureFlags = 0;  // may be any value from 0 to 5
	SettingsOut.DebugModelType = COMPONENT_MODEL_TYPE_CAPACITOR;
	SettingsOut.DebugModelNominal = 0.00000001;
	SettingsOut.TriggerMode = MODE_MANUAL;
	Status = SetSettings(&Server, &SettingsOut);
	CheckStatus(&Server, Status, "SetSettings");

	printf("-- Read settings from device --\n");
	asa_settings_t SettingsIn;
	Status = GetSettings(&Server, &SettingsIn);
	CheckStatus(&Server, Status, "GetSettings");

	printf("-- Do fast calibration with open probes --\n");
	Status = Calibrate(&Server, FAST_OPEN_CALIBRATE);
	CheckStatus(&Server, Status, "Calibrate");
	if (Status < 0)
	{
		printf("Calibration was not started");
		return 1;
	}
	while (GetLastOperationResult(&Server) == ASA_OK)
	{
		// Calibration is pending
		SleepMSec(500);
	}
	while (GetLastOperationResult(&Server) == ASA_IN_PROGRESS)
	{
		// Calibration is running
		SleepMSec(500);
	}
	if (GetLastOperationResult(&Server) == ASA_OK)
	{
		printf("Calibration completed successfully\n");
	}
	else
	{
		printf("Calibration completed unsuccessfully\n");
	}

	printf("-- Do measure IV curve --\n");
	Status = TriggerMeasurement(&Server);
	while (GetLastOperationResult(&Server) != ASA_OK)
	{
		SleepMSec(500);
	}
	CheckStatus(&Server, Status, "TriggerMeasurement");

	printf("-- Get measured IV curve --\n");
	iv_curve_t IVC;
	Status = GetIVCurve(&Server, &IVC, SettingsOut.NumberPoints);
	CheckStatus(&Server, Status, "GetIVCurve");

	printf("-- Get status of buttons --\n");
	asa_buttons_t Buttons;
	Status = GetStatusButtons(&Server, &Buttons);
	CheckStatus(&Server, Status, "GetStatusButtons");

	printf("-- Get temperature of probes --\n");
	asa_temperature_t Temperature;
	Status = GetTempProbes(&Server, &Temperature);
	CheckStatus(&Server, Status, "GetTempProbes");

	printf("Got settings (Out, In):\n");
	printf("Probe signal frequency: (%0.lf, %0.lf) Hz\n", SettingsOut.ProbeSignalFrequencyHz, SettingsIn.ProbeSignalFrequencyHz);
	printf("Voltage amplitude: (%.2lf, %.2lf) V\n", SettingsOut.VoltageAmplV, SettingsIn.VoltageAmplV);
	printf("Number of points: (%.d, %.d)\n", SettingsOut.NumberPoints, SettingsIn.NumberPoints);
	printf("Maximum current: (%.0lf, %.0lf) mA\n", SettingsOut.MaxCurrentMA, SettingsIn.MaxCurrentMA);
	printf("Virtual component model: (%d, %d)\n", SettingsOut.DebugModelType, SettingsIn.DebugModelType);
	printf("Virtual component model nominal: (%.2lf, %.2lf)\n", SettingsOut.DebugModelNominal, SettingsIn.DebugModelNominal);
	printf("Virtual component model: (%d, %d)\n", SettingsOut.TriggerMode, SettingsIn.TriggerMode);
	printf("ButtonPressed: (%d, %d)\n", Buttons.GrayProbeButton, Buttons.BlueProbeButton);
	printf("Temperature: (%d, %d, %d, %d)\n", Temperature.GrayOverheat, Temperature.GrayTemperature, Temperature.BlueOverheat, Temperature.BlueTemperature);
	printf("-- Get number of points for one period of curve --\n");
	const uint32_t NumPointsToPrint = GetNumberPointsForSinglePeriod(&SettingsIn);
	printf("Number of points for one period of curve: %d\n", NumPointsToPrint);
	printf("Voltages (V) and currents (A) of received curve:\n", NumPointsToPrint);
	for (uint32_t i = 0; i < NumPointsToPrint; i++)
	{
		printf("[%lf, %lf];\n ", IVC.Voltages[i], IVC.Currents[i]);
	}
	printf("\n");

	printf("-- Set default values as threshold of noise for compare curves --\n");
	SetMinVC(MIN_VAR_V_DEFAULT, MIN_VAR_C_DEFAULT);

	printf("-- Compare of two identical curves must be 0 --\n");
	double Score = CompareIVC(IVC.Voltages, IVC.Currents, SettingsOut.NumberPoints, IVC.Voltages, IVC.Currents, SettingsOut.NumberPoints);
	printf("Score =  %lf\n", Score);

    system("pause");
	return 0;
}
