#include <windows.h>
#include "hcm4mfs.h"

using namespace std;


#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>
#include <algorithm>
#include <fstream>
#include <cctype>
#include <vector>
#include <sys/stat.h>
#include <array>   
#include <sstream>

#include "Dll/HcmTerrain.h"
#include "Dll/Structures.h"
#include "Dll/Additional.h"
#include "Dll/Get_FS_from_figures.h"
#include "Dll/Antenna.h"
#include "Dll/Antenna_correction.h"
#include "Dll/DebugFile.h"
#include "Dll/PointToPointForLine.h"
#include "Dll/ErrorCodes.h"


extern "C" void LIBRARY_API GetInfoString(char* outputString){
    std::string info = "HCM4MFS DLL 1.20";
    if (info.length() > 19) {
        info = info.substr(0, 19);
    }
    strncpy(outputString, info.c_str(), 20);
    outputString[19] = '\0';
}

extern "C" void LIBRARY_API GetStructureSizes(int* sizeIn, int* sizeOut)
{
    if (sizeIn)  *sizeIn  = static_cast<int>(sizeof(PointToPoint_Input_Parameters));
    if (sizeOut) *sizeOut = static_cast<int>(sizeof(PointToPoint_Output_Parameters));
}

extern "C" void LIBRARY_API GetErrorMessage(int errorCode, char* outputString, int bufferSize)
{
    std::string errorMsg = getErrorMessageI(errorCode);
    
    if (errorMsg.length() >= static_cast<size_t>(bufferSize)) {
        errorMsg = errorMsg.substr(0, bufferSize - 1);
    }
    
    strncpy(outputString, errorMsg.c_str(), bufferSize);
    outputString[bufferSize - 1] = '\0'; 
}

extern "C" void LIBRARY_API GetInfoMessage(int infoCode, char* outputString, int bufferSize)
{
    std::string infoMsg = getInfoMessageI(infoCode);
    
    if (infoMsg.length() >= static_cast<size_t>(bufferSize)) {
        infoMsg = infoMsg.substr(0, bufferSize - 1);
    }
    
    strncpy(outputString, infoMsg.c_str(), bufferSize);
    outputString[bufferSize - 1] = '\0'; 
}

extern "C" void LIBRARY_API PointToPoint(PointToPoint_Input_Parameters &input, PointToPoint_Output_Parameters &output){
	output.HCM_error = 0;
	std::strcpy(output.Version, "Version 1.19 One2One");
	
	for (int i = 0; i < 20; ++i) {output.Info[i] = false;};

	WriteDebugInformationInput(input);

	if (input.C_Mode<-11 || input.C_Mode>12){
		output.HCM_error = 1025;// "C_mode is out of range"
		return;
	}

	if (input.Sea_temperature[0] != 'W' && 
	    input.Sea_temperature[0] != 'I' && 
	    input.Sea_temperature[0] != 'C') {
	    input.Sea_temperature[0] = 'W';
	}

	(input.Chan_occup == 0 || input.Chan_occup == 1) ? input.Chan_occup : input.Chan_occup=0;
	if (input.PointDistance < 0.03 || input.PointDistance > 1){input.PointDistance = 0.1;};

	if (input.Border_path[0] == '\0') {
		output.HCM_error = 38;
		return;
	};
	if (input.Topo_path[0] == '\0') {
		output.HCM_error = 36;
		return;
	};
	HcmTerrain terra;
	terra.PathToTopo = std::string(input.Topo_path);        
	terra.PathToMorpho = std::string(input.Morpho_path);    
	terra.stepProfile = input.PointDistance;
	
	if (Trimmer(input.Tx_Ant_typ_H).empty()) {
	    std::strcpy(input.Tx_Ant_typ_H, "000ND00");
	}
	if (Trimmer(input.Tx_Ant_typ_V).empty()) {
	    std::strcpy(input.Tx_Ant_typ_V, "000ND00");
	}
	if (input.Tx_Type_of_Ant == 0 || input.Tx_Type_of_Ant == 1){//(E/I)
		input.Tx_Type_of_Ant == 0 ? output.Tx_ant_type_corr = 0.0 : output.Tx_ant_type_corr = 2.1;
	} else {
		output.HCM_error = 1033;//, "Error in type of Tx antenna (E/I)"},
		return;
	};
	if (input.Tx_Longitude < -180 || input.Tx_Longitude>180){
		output.HCM_error = 1001;//"Error in geographical coordinates (Tx longitude, degrees)"
		return;
	}
	if (input.Tx_Latitude < -89.9 || input.Tx_Latitude>89.9){
		output.HCM_error = 1005;//"Error in geographical coordinates (Tx latitude, degrees)"
		return;
	}
	if (input.Tx_Power < -100 || input.Tx_Power>100){
		output.HCM_error = 1034;//"Error in power"
		return;
	}
	if (input.Tx_H_Ant < 0 || input.Tx_H_Ant>150){
		output.HCM_error = 1009;//"Error in Tx antenna height"
		return;
	}
	if (input.Tx_Serv_area < 0 || input.Tx_Serv_area>150){
		output.HCM_error = 1012;// "Error in radius of service area of Tx"
		return;
	}

	if (Trimmer(input.Rx_Ant_typ_H).empty()) {
	    std::strcpy(input.Rx_Ant_typ_H, "000ND00");
	}
	if (Trimmer(input.Rx_Ant_typ_V).empty()) {
	    std::strcpy(input.Rx_Ant_typ_V, "000ND00");
	}
	
	if (input.Rx_Type_of_Ant == 0 || input.Rx_Type_of_Ant == 1){input.Rx_Type_of_Ant=0;};
	if (input.Rx_Longitude < -180 || input.Rx_Longitude>180){
		output.HCM_error = 1014;//"Error in geographical coordinates (Rx longitude, degrees)"
		return;
	}
	if (input.Rx_Latitude < -89.9 || input.Rx_Latitude>89.9){
		output.HCM_error = 1018;//"Error in geographical coordinates (Rx latitude, degrees)"
		return;
	}
	if (input.Rx_H_Ant < 0 || input.Rx_H_Ant>150){
		output.HCM_error = 1022;//"Error in Rx antenna height"
		return;
	}
	if (input.Rx_Serv_area < 0 || input.Rx_Serv_area>150){
		output.HCM_error = 1029;//"Error in radius of Rx service area"
		return;
	}
	if (input.Rx_Ant_gain < -50 || input.Rx_Ant_gain>50){
		output.HCM_error = 1045;//Error in gain of Rx antenna
		return;
	}
	if (input.Rx_Azi < 0 || input.Rx_Azi>360){
		output.HCM_error = 1043;//Error in Rx azimuth
		return;
	}
	if (input.Rx_Elev < -90 || input.Rx_Elev>90){
		output.HCM_error = 1042;//Error in Rx elevation
		return;
	}


	output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
	std::string txDesig(input.Tx_Desig_of_emis);
	std::string rxDesig(input.Rx_Desig_of_emis);
		
	switch(input.C_Mode) {
	case 12://12    point to point calculation (t%=1%)
		output.Time_percentage = 1;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case 11://11    point to point calculation (t%=50%
		output.Time_percentage = 50;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case 10://10    point to point calculation (t%=10%)
		output.Time_percentage = 10;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case 0://0  point to point calculation (t%=Channel occ.)
		if(input.Tx_Freq >= 29.7 && input.Tx_Freq <= 47.0) {
			output.Perm_FS = 0.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 3.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 68.0 && input.Tx_Freq <= 74.8) {
			output.Perm_FS = 6.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 9.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 75.2 && input.Tx_Freq <= 87.5) {
			output.Perm_FS = 6.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 9.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 146.0 && input.Tx_Freq <= 149.9) {
			output.Perm_FS = 12.0;
			output.Table_CBR_D = 80.0;
			output.ERP_ref_Tx = 12.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 150.05 && input.Tx_Freq <= 174.0) {
			output.Perm_FS = 12.0;
			output.Table_CBR_D = 80.0;
			output.ERP_ref_Tx = 12.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 380.0 && input.Tx_Freq <= 385.0) {
			output.Perm_FS = 18.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 14.0;
			output.Info[4] = false;
			output.Info[18] = true;
		}
		else if(input.Tx_Freq >= 390.0 && input.Tx_Freq <= 395.0) {
			output.Perm_FS = 18.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 14.0;
			output.Info[4] = false;
			output.Info[18] = true;
		}
		else if(input.Tx_Freq >= 406.1 && input.Tx_Freq <= 430.0) {
			output.Perm_FS = 20.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 16.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 440.0 && input.Tx_Freq <= 470.0) {
			output.Perm_FS = 20.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 16.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 862.0 && input.Tx_Freq <= 960.0) {
			output.Perm_FS = 26.0;
			output.Table_CBR_D = 30.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 1710.0 && input.Tx_Freq <= 1785.0) {
			output.Perm_FS = 35.0;
			output.Table_CBR_D = 15.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 1805.0 && input.Tx_Freq <= 1880.0) {
			output.Perm_FS = 35.0;
			output.Table_CBR_D = 15.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else {
			output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
			output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
			output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
			output.Info[4] = true;
		}
		if ((output.Info[18] && txDesig.substr(0, 7) == "25K0G7W" && 
		     rxDesig.substr(0, 7) == "25K0G7W") ||
		    input.Chan_occup == 0) {
		    output.Time_percentage = 10;
		}
		else {
			output.Time_percentage = 1;
		}
		break;
	default:
		output.HCM_error = 1025; //"C_mode is out of range"
		return;
	}



	//AnnexInFreqRange; 
	// TRUE if input.useAnnex1=true  AND freqTx in Annex1FreqRange.   THEN Perm_FS =Perm_FS_from_table
	// modes p2p and Cbr
	output.Perm_FS_from_table = output.Perm_FS;
	output.AnnexInFreqRange = false;
	if (input.useAnnex1 && output.Perm_FS_from_table>HCM4A_ERROR_VALUE_DOUBLE){
			output.AnnexInFreqRange = true;
	}else{
		if(input.Perm_FS_input >HCM4A_ERROR_VALUE_DOUBLE) {
			output.Info[5] = true;
			output.Perm_FS = input.Perm_FS_input;
		}
		else {
			if(output.Info[4]) {
				output.HCM_error = 1026; //"Error in input value of permissible field strength"},
				return;
			}
		}
	}

	output.Prot_margin = 0;

	output.Tx_Longitude_Calc = input.Tx_Longitude;
	output.Tx_Latitude_Calc = input.Tx_Latitude;
	output.Rx_Longitude_Calc = input.Rx_Longitude;
	output.Rx_Latitude_Calc = input.Rx_Latitude;
	PositionOfMobileA(input, output);
	if (output.HCM_error>0) return;

	// for backward compatibility
	std::string tmpS = CoorToString(output.Tx_Longitude_Calc, output.Tx_Latitude_Calc);
	StrtoCoor(tmpS, output.Tx_Longitude_Calc, output.Tx_Latitude_Calc);
	tmpS = CoorToString(output.Rx_Longitude_Calc, output.Rx_Latitude_Calc);
	StrtoCoor(tmpS, output.Rx_Longitude_Calc, output.Rx_Latitude_Calc);
	// for backward compatibility


	output.Distance = CalcDistanceM(output.Tx_Longitude_Calc, output.Tx_Latitude_Calc,
									output.Rx_Longitude_Calc, output.Rx_Latitude_Calc);
	output.Dir_Rx_Tx = CalcDirectionM(output.Rx_Longitude_Calc, output.Rx_Latitude_Calc,
									output.Tx_Longitude_Calc, output.Tx_Latitude_Calc);
	output.Dir_Tx_Rx = CalcDirectionM(output.Tx_Longitude_Calc, output.Tx_Latitude_Calc,
									output.Rx_Longitude_Calc, output.Rx_Latitude_Calc);

						
	if (output.Distance >= input.MaxCalcDistanceKm ){
		output.HCM_error = 1028;// "The distance is greater than 1000 km. Calculations not possible"},
		return;	
	}


	output.Rx_H_Site_Ant = input.Rx_H_Site_Ant;
	if (input.Rx_H_Site_Ant == HCM4A_NO_INPUT_INT || input.Rx_Serv_area > 0.0){
		output.Info[8] = true; //The height is taken from terrain database
		output.Rx_H_Site_Ant = std::trunc(terra.GetHeigth(output.Rx_Longitude_Calc, output.Rx_Latitude_Calc));

		if ( terra.isErrorHeigth(output.Rx_H_Site_Ant) ){
			output.HCM_error = 42;//"Error opening terrain- or morphological data file (data not available)
			return;
		}
	} else {
		output.Rx_H_Site_Ant = std::trunc(terra.GetHeigth(output.Rx_Longitude_Calc, output.Rx_Latitude_Calc));
		if ( terra.isErrorHeigth(output.Rx_H_Site_Ant) ){
			output.HCM_error = 44;//"Error opening terrain- or morphological data file (data not available)
			return;
		}
		if (std::abs(output.Rx_H_Site_Ant - input.Rx_H_Site_Ant) <= input.Rx_H_Site_Ant / 10) {
			output.Info[9] = true; //Height of Rx site differs from height of terrain data
		} else {
			output.Info[10] = true; //  Rx site height differs more than 10%, calculated values may be (extremely) wrong!
		}
		output.Rx_H_Site_Ant = input.Rx_H_Site_Ant;
	}

	output.Tx_H_Site_Ant = input.Tx_H_Site_Ant;
	if (input.Tx_H_Site_Ant == HCM4A_NO_INPUT_INT || input.Tx_Serv_area > 0.0){
		output.Info[1] = true; //The height is taken from terrain database

		output.Tx_H_Site_Ant = std::trunc(terra.GetHeigth(output.Tx_Longitude_Calc, output.Tx_Latitude_Calc));
		if ( terra.isErrorHeigth(output.Tx_H_Site_Ant) ){
			output.HCM_error = 41;//"Error opening terrain- or morphological data file (data not available)
			return;
		}
	} else {
		output.Tx_H_Site_Ant = std::trunc(terra.GetHeigth(output.Tx_Longitude_Calc, output.Tx_Latitude_Calc));
		if ( terra.isErrorHeigth(output.Tx_H_Site_Ant) ){
			output.HCM_error = 41;//"Error opening terrain- or morphological data file (data not available)
			return;
		}
		if (std::abs(output.Tx_H_Site_Ant - input.Tx_H_Site_Ant) <= input.Tx_H_Site_Ant / 10) {
			output.Info[2] = true; //Height of Tx site differs from height of terrain data
		} else {
			output.Info[3] = true; // Tx site height differs more than 10%, calculated values may be (extremely) wrong!
		}
		output.Tx_H_Site_Ant = input.Tx_H_Site_Ant;
	}


	output.V_angle_Tx_Rx = std::atan2((output.Rx_H_Site_Ant + input.Rx_H_Ant) - (output.Tx_H_Site_Ant + input.Tx_H_Ant), (1000* output.Distance));
	output.V_angle_Tx_Rx = output.V_angle_Tx_Rx * RadToDeg;

	// Calculation of power in direction of the receiver 'Power_to_Rx'
	if (std::strcmp(input.Tx_Ant_typ_H, "000ND00") == 0 &&
	    std::strcmp(input.Tx_Ant_typ_V, "000ND00") == 0) {
		output.Tx_ant_corr = 0.0;
		output.H_diff_angle_Tx_Rx = 0.0;
		output.V_diff_angle_Tx_Rx = 0.0;
	} else {
		if (input.Tx_Elev <-90 || input.Tx_Elev >90){
			output.HCM_error = 1031; //Error in Tx elevation
			return;
		}
		if (input.Tx_Azi <0 || input.Tx_Azi >360){
			output.HCM_error = 1032; //Error in Tx azimuth
			return;
		}

		// NOT MODIFIED
		Antenna_correction(output.Dir_Tx_Rx, input.Tx_Azi, output.V_angle_Tx_Rx, input.Tx_Elev,
							input.Tx_Ant_typ_H, input.Tx_Ant_typ_V,
							//out
							output.H_diff_angle_Tx_Rx, output.V_diff_angle_Tx_Rx,
							output.Tx_ant_corr, output.HCM_error);
		if (output.HCM_error != 0) return;
	}

	input.Tx_Type_of_Ant == 0 ? output.Tx_ant_type_corr = 0.0 : output.Tx_ant_type_corr = 2.1;
	output.Power_to_Rx = input.Tx_Power - output.Tx_ant_corr - output.Tx_ant_type_corr;

	output.Free_space_FS = 77.0 - 20.0 * std::log10(output.Distance) + output.Power_to_Rx;

	// If distance is less than 1 km, use free space field strength
	if (output.Distance < 1.0) {
		output.Calculated_FS = output.Free_space_FS;
		output.Info[11] = true; //Free space field strength used because distance < 1 km
		return;
	}

	terra.GetProfile( output.Tx_Longitude_Calc, output.Tx_Latitude_Calc,
					output.Rx_Longitude_Calc, output.Rx_Latitude_Calc,
					true, output.Tx_H_Site_Ant, output.Rx_H_Site_Ant);

	output.ProfilePoints = terra.countSteps;

	// Calculation of the first Fresnel zone
	if (input.Tx_Serv_area + input.Rx_Serv_area == 0.0) {
		std::vector<double> hdz(10002), hdc(10002), hdf(10002);
		int j = terra.countSteps - 2;
		for (int i = 1; i <= j; ++i) {
			hdz[i] = terra.T_Prof[i + 1] + terra.stepProfile * i * (output.Distance - terra.stepProfile * i) / 17.0;
		}

		if (output.Distance > 2.0) {
			int ind1 = static_cast<int>(std::round(1.0 / terra.stepProfile));
			int ind2 = static_cast<int>(std::round((output.Distance - 1.0) / terra.stepProfile));
			for (int i = ind1; i <= ind2; ++i) {
				hdz[i] += 10.0;
			}
		}

		for (int i = 1; i <= j; ++i) {
			hdc[i] = input.Rx_H_Ant * terra.stepProfile * i / output.Distance - hdz[i];
			double x = terra.stepProfile * i * (output.Distance - terra.stepProfile * i);
			hdf[i] = (x <= 0.0) ? 0.0 : 547.7 * std::sqrt(x / (output.Distance * input.Tx_Freq));
		}

		bool free = true;
		for (int i = 1; i <= j; ++i) {
			if ((hdc[i] - hdf[i]) < 0.0) {
				free = false;
				break;
			}
		}

		if (free) {
			output.Calculated_FS = output.Free_space_FS;
			output.Info[12] = true; //Free space field strength is used, because 1st Fresnel zone is free
			WriteDebugInformationOutput(input, output, terra);
			return;
		}
	}


	// Calculate Terrain Clearance Angles and TCA correction factors
	double xTCA = 0.0; //temp value

	output.Tx_TCA_corr = 0;
	if (input.Tx_Serv_area == 0.0) {
		output.Tx_TCA = -90.0;
		int jtx = (output.Distance >= 16.0) ? std::round(16.0 / input.PointDistance) : output.ProfilePoints - 2;
		for (int i = 1; i <= jtx; ++i) {
			xTCA = (terra.T_Prof[1 + i] - (input.Tx_H_Ant)) / (input.PointDistance * i * 1000.0);
			xTCA = std::atan(xTCA) * RadToDeg; // Convert to degrees
			if (xTCA > output.Tx_TCA) output.Tx_TCA = xTCA;
		}

		output.Tx_TCA_corr = TCACorrectionCalculation(output.Tx_TCA, input.Tx_Freq, output.Distance);
	}

	output.Rx_TCA_corr = 0;
	if (input.Rx_Serv_area == 0.0) {
		output.Rx_TCA = -90.0;
		int jrx = (output.Distance >= 16.0) ? std::round(16.0 / input.PointDistance) : output.ProfilePoints - 2;
		for (int i = 1; i <= jrx; ++i) {
			xTCA = (terra.T_Prof[output.ProfilePoints - i] - (input.Rx_H_Ant)) / (input.PointDistance * i * 1000.0);
			xTCA = std::atan(xTCA) * RadToDeg; // Convert to degrees
			if (xTCA > output.Rx_TCA) output.Rx_TCA = xTCA;
		}
		output.Rx_TCA_corr = TCACorrectionCalculation(output.Rx_TCA, input.Rx_Freq, output.Distance);
	}

	// Effective antenna heights
	int d1,d2;
	if (output.Distance < 15.0) {
		d1 = std::round(output.ProfilePoints / 15.0);
		d2 = output.ProfilePoints - 1;
	}else{
		d1 = std::round(1.0 / input.PointDistance);
		d2 = std::round(15 / input.PointDistance);
	}

	// Transmitter:
	double hsum = 0.0; //temp value;

	if (input.Tx_Serv_area > 0.0) {
		// Height of a mobile 'hmTx'
		output.Heff_Tx = static_cast<double>(input.Tx_H_Ant);
	} else {
		hsum = 0.0;
		for (int I = d1; I <= d2; ++I) {
			hsum += terra.T_Prof[I];
		}
		output.Heff_Tx = input.Tx_H_Ant - static_cast<double>(hsum) / static_cast<double>(d2 - d1 + 1);

	}
	if (output.Heff_Tx < 3.0) output.Heff_Tx = 3.0;

	if (input.Rx_Serv_area > 0) {
		output.Heff_Rx = input.Rx_H_Ant;
	} else {
		hsum = 0.0;
		for (int i = d1; i <= d2; ++i) {
			hsum += terra.T_Prof[output.ProfilePoints - i];
		}
		output.Heff_Rx = input.Rx_H_Ant - static_cast<double>(hsum) / (d2 - d1 + 1);
	}
	if (output.Heff_Rx < 3.0) output.Heff_Rx = 3.0;

	output.Heff = (output.Heff_Tx * output.Heff_Rx) / 10.0;

	// Calculate distance over sea
	output.D_sea_calculated = 0.0;
	bool null = false;
	double ds1 = 0.0;
	int j1 = 0;
	if (output.Distance > 1.0) {
		for (int i = 1; i < output.ProfilePoints; ++i) {
			if (terra.M_Prof[i] == 1) { // Assuming 1 represents 'sea'
				if (null) {
					++j1;
				} else {
					j1 = 0;
					null = true;
				}
			} else {
				if (null) {
					ds1 = static_cast<double>(j1) * input.PointDistance;
					output.D_sea_calculated += ds1;
					ds1 = 0.0;
					j1 = 0;
					null = false;
				}
			}
		}
		if (null) {
			ds1 = static_cast<double>(j1) * input.PointDistance;
			output.D_sea_calculated += ds1;
			null = false;
		}
	}

	if (output.D_sea_calculated > output.Distance) {
		output.Info[13] = true;
		output.D_sea_calculated = output.Distance;
	}

	// Calculate Delta h and Dh correction factor
	if ((output.Distance <= 10.0) || (output.D_sea_calculated >= output.Distance)) {
		output.Dh = 50.0;
		output.Dh_corr = 0.0;
	} else {
		output.Dh = DhCalculationM(output.Distance, terra);
		DhCorrectionM(output.Dh, output.Distance, input.Tx_Freq, output.Dh_corr);
	}

	// Calculate the field strength from the figures
	FS_figures fsf;
	fsf.Tx_frequency = input.Tx_Freq;
	fsf.Distance = output.Distance;     // km
	fsf.Heff = output.Heff;          // m
	fsf.Time_percentage = output.Time_percentage; // %
	fsf.LatM = 0;//(latTx + latRx)/2; // Middle Latitide of path
	fsf.Sea_temperature = input.Sea_temperature[0]; // Sea_temperature
	fsf.TxLongitude = input.Tx_Longitude;
	fsf.TxLatitude = input.Tx_Latitude;

	fsf.Get_FS_from_figures_Old();

	output.HCM_error = fsf.HCM_error;
	if (output.HCM_error != 0) return;

	output.Land_FS_old  = fsf.Land_FS_1kW - 30.0 + output.Power_to_Rx;
	output.Land_FS_old += output.Tx_TCA_corr + output.Rx_TCA_corr - output.Dh_corr;

	fsf.Get_FS_from_figures();

	output.HCM_error = fsf.HCM_error;
	if (output.HCM_error != 0) return;

	// Corrections according to the power
	output.Land_FS = fsf.Land_FS_1kW - 30.0 + output.Power_to_Rx;
	output.Sea_FS = fsf.Sea_FS_1kW - 30.0 + output.Power_to_Rx;

	// Clearance angle corrections and delta h correction
	output.Land_FS += output.Tx_TCA_corr + output.Rx_TCA_corr - output.Dh_corr;

	if (output.D_sea_calculated == 0.0) {
		output.Calculated_FS = output.Land_FS;
	} else {
		// Mixed path calculation
		if (output.Time_percentage < 10) {
			std::vector<double> a = {0.0, 0.07, 0.13, 0.2, 0.29, 0.37, 0.46, 0.56, 0.67, 0.8, 1.0};
			double factorOfPathOverSea = output.D_sea_calculated / output.Distance;
			double x = factorOfPathOverSea * 10.0;
			double a1 = a[static_cast<int>(x) + 1];
			double a2, ax = 0;
			if (x < 10.0) {
				a2 = a[static_cast<int>(x) + 2];
			} else {
				a2 = a1;
			}
			x -= static_cast<int>(x);
			ax = a1 + x * (a2 - a1);
			output.Calculated_FS = output.Land_FS + ax * (output.Sea_FS - output.Land_FS);
		} else {
			output.Calculated_FS = output.Land_FS * (output.Distance - output.D_sea_calculated) /
									output.Distance + output.Sea_FS * output.D_sea_calculated / output.Distance;
		}

	}

	if (output.HCM_error > 0) return;
	
	Permissible_FS_calculationM( input, output, true);
	if (!output.AnnexInFreqRange) {
		output.Perm_FS += input.Perm_FS_input;
	} else{
		output.Perm_FS += output.Perm_FS_from_table;
	}
	output.Prot_margin = output.Perm_FS - output.Calculated_FS;

	WriteDebugInformationOutput(input, output, terra);

}


extern "C" void LIBRARY_API LineCalc(PointToPoint_Input_Parameters &input, PointToPoint_Output_Parameters &output){
	output.HCM_error = 0;
	std::strcpy(output.Version, "Version 1.19 LineCalc");
	
	for (int i = 0; i < 20; ++i) {output.Info[i] = false;};
	
	WriteDebugInformationInput(input);


	if (input.C_Mode<-11 || input.C_Mode>12){
		output.HCM_error = 1025;// "C_mode is out of range"
		return;
	}

	if (input.Sea_temperature[0] != 'W' && 
	    input.Sea_temperature[0] != 'I' && 
	    input.Sea_temperature[0] != 'C') {
	    input.Sea_temperature[0] = 'W';
	}

	(input.Chan_occup == 0 || input.Chan_occup == 1) ? input.Chan_occup : input.Chan_occup=0;
	if (input.PointDistance < 0.03 || input.PointDistance > 1){input.PointDistance = 0.1;};

	HcmTerrain terra;
	terra.PathToTopo = input.Topo_path;
	terra.PathToMorpho = input.Morpho_path;
	terra.stepProfile = input.PointDistance;

	if (Trimmer(input.Tx_Ant_typ_H).empty()) {
	    std::strcpy(input.Tx_Ant_typ_H, "000ND00");
	}
	if (Trimmer(input.Tx_Ant_typ_V).empty()) {
	    std::strcpy(input.Tx_Ant_typ_V, "000ND00");
	}
	if (input.Tx_Type_of_Ant == 0 || input.Tx_Type_of_Ant == 1){//(E/I)
		input.Tx_Type_of_Ant == 0 ? output.Tx_ant_type_corr = 0.0 :	output.Tx_ant_type_corr = 2.1;
	} else {
		output.HCM_error = 1033;//, "Error in type of Tx antenna (E/I)"},
		return;
	};
	if (input.Tx_Longitude < -180 || input.Tx_Longitude>180){
		output.HCM_error = 1001;//"Error in geographical coordinates (Tx longitude, degrees)"
		return;
	}
	if (input.Tx_Latitude < -89.9 || input.Tx_Latitude>89.9){
		output.HCM_error = 1005;//"Error in geographical coordinates (Tx latitude, degrees)"
		return;
	}
	if (input.Tx_Power < -100 || input.Tx_Power>100){
		output.HCM_error = 1034;//"Error in power"
		return;
	}
	output.Power_to_Rx = input.Tx_Power - output.Tx_ant_type_corr;

	if (input.Tx_H_Ant < 0 || input.Tx_H_Ant>150){
		output.HCM_error = 1009;//"Error in Tx antenna height"
		return;
	}
	if (input.Tx_Serv_area < 0 || input.Tx_Serv_area>150){
		output.HCM_error = 1012;// "Error in radius of service area of Tx"
		return;
	}

	input.Rx_Serv_area = 0;
	input.Rx_Freq = 0;
	std::strcpy(input.Rx_Desig_of_emis, "       ");
	std::string txDesig(input.Tx_Desig_of_emis);
	std::string rxDesig(input.Rx_Desig_of_emis);
	
	output.AnnexInFreqRange = false;
	switch(input.C_Mode) {
	case -1://-1	point to line calculation (t%=Channel occ., 10m)
		if(input.Tx_Freq >= 29.7 && input.Tx_Freq <= 47.0) {
			output.Perm_FS = 0.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 3.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 68.0 && input.Tx_Freq <= 74.8) {
			output.Perm_FS = 6.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 9.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 75.2 && input.Tx_Freq <= 87.5) {
			output.Perm_FS = 6.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 9.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 146.0 && input.Tx_Freq <= 149.9) {
			output.Perm_FS = 12.0;
			output.Table_CBR_D = 80.0;
			output.ERP_ref_Tx = 12.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 150.05 && input.Tx_Freq <= 174.0) {
			output.Perm_FS = 12.0;
			output.Table_CBR_D = 80.0;
			output.ERP_ref_Tx = 12.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 380.0 && input.Tx_Freq <= 385.0) {
			output.Perm_FS = 18.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 14.0;
			output.Info[4] = false;
			output.Info[18] = true;
		}
		else if(input.Tx_Freq >= 390.0 && input.Tx_Freq <= 395.0) {
			output.Perm_FS = 18.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 14.0;
			output.Info[4] = false;
			output.Info[18] = true;
		}
		else if(input.Tx_Freq >= 406.1 && input.Tx_Freq <= 430.0) {
			output.Perm_FS = 20.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 16.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 440.0 && input.Tx_Freq <= 470.0) {
			output.Perm_FS = 20.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 16.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 862.0 && input.Tx_Freq <= 960.0) {
			output.Perm_FS = 26.0;
			output.Table_CBR_D = 30.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 1710.0 && input.Tx_Freq <= 1785.0) {
			output.Perm_FS = 35.0;
			output.Table_CBR_D = 15.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 1805.0 && input.Tx_Freq <= 1880.0) {
			output.Perm_FS = 35.0;
			output.Table_CBR_D = 15.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else {
			output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
			output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
			output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
			output.Info[4] = true;
		}
		if ((output.Info[18] && txDesig.substr(0, 7) == "25K0G7W" && 
		     rxDesig.substr(0, 7) == "25K0G7W") ||
		    input.Chan_occup == 0) {
		    output.Time_percentage = 10;
		}
		else {
			output.Time_percentage = 1;
		}
		break;
	case -9://-9	point to line calculation (t%=10%, 3m)
		output.Time_percentage = 10;
		input.Rx_H_Ant = 3;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case -10://-10	point to line calculation (t%=10%, 10m)
		output.Time_percentage = 10;
		input.Rx_H_Ant = 10;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case -11://-11	point to line calculation (t%=50%, 3m)
		output.Time_percentage = 50;
		input.Rx_H_Ant = 3;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	default:
		output.HCM_error = 1025; //"C_mode is out of range"
		return;
	}


	output.Perm_FS_from_table = output.Perm_FS;

	if (input.C_Mode > 0){
		if (input.Max_CBR_D_input < 0 || input.Max_CBR_D_input > 0){
			output.HCM_error = 1027;// "Error in input value of maximum cross border range
			return;
		}
		output.Info[6] = true;//Input value of maximum cross border range is used
		if(output.Info[4] && input.C_Mode < 0 && input.D_to_border < 0) {
			output.HCM_error = 1050;
			return;
		}
	}

	if(input.Perm_FS_input >HCM4A_ERROR_VALUE_DOUBLE) {
		output.Info[5] = true;
		output.Perm_FS = input.Perm_FS_input;
	}
	else {
		if(output.Info[4]) {
			output.HCM_error = 1026; //"Error in input value of permissible field strength"},
			return;
		}
	}
	output.Prot_margin = 0;


	if (input.D_to_border > 999 || input.D_to_border == HCM4A_ERROR_VALUE_INT) {
		output.HCM_error = 1047;	// Distance to borderline is too long
		return;
	}

	PointToPoint_Input_Parameters inputLine;
	inputLine = input;
	inputLine.Rx_Freq = inputLine.Tx_Freq;


	// Select line data
	std::vector<double> nRecord(22), nFile(30800);
	std::vector<Coordinate> coCp(1400);
	int nCp = 0;
	int nAll = 0;
	int recX = 0;
	int recNX = -1;
	int count_in_Nlist = 0;
	std::vector<int> ListIndexes(3);
	std::vector<double> ListMaxFS(3);
	double longRxTmp, latRxTmp;
	int d2b = input.D_to_border;

	std::string filenameTestCutTx = std::string(input.Border_path, 256) + 
                                std::string(input.Land_from, 3) + 
                                ".all";

	std::string BorderFile = std::string(input.Land_from, 3) + 
	                         std::string(input.Land_to, 3) + 
	                         ".";

	std::string tmpS = std::to_string(input.D_to_border);
	if (tmpS.length() == 1){ BorderFile += "00" + tmpS;};
	if (tmpS.length() == 2){ BorderFile += "0" + tmpS;};
	if (tmpS.length() == 3){ BorderFile += tmpS;};



	// all BORDERLINE centerpoints of the affected country:
	std::ifstream file(input.Border_path + BorderFile.substr(0, 7) + "000", std::ios::binary);
	if (!file) {
		output.HCM_error = 1048;// Selected line data not available
		return;
	}
	// Store all center points table 'Co_cp(i,j)'
	while (nCp < 1400 && file.read(reinterpret_cast<char*>(nRecord.data()), 176)) {
		coCp[nCp].longitude = nRecord[20] * RadToDeg;
		coCp[nCp].latitude = nRecord[21] * RadToDeg;
		nCp++;
	}
	file.close();
	nCp--;



	// Open line file and cache full line D_to_border
	file.open(input.Border_path + BorderFile, std::ios::binary);
	if (!file) {
		output.HCM_error = 1048;  // Selected line data not available
		return;
	}

	while (nAll < 1400 && file.read(reinterpret_cast<char*>(&nFile[nAll * 22]), 176)) {
		nAll++;
	}
	file.close();

	for (int i=0; i<=nAll*22; ++i){
		nFile[i] = nFile[i] * RadToDeg;
	}
	nAll--;



	for (int i = 0; i < 3; ++i) {
		ListIndexes[i] = 0;
		ListMaxFS[i] = 0.0;
	}


	// TEST EACH POINT
	double fsX = -999.9;

	for (int j = 0; j <= nAll; ++j) {
		for (int k = 0; k < 20; k += 2) {
			longRxTmp = nFile[22 * j + k];
			latRxTmp = nFile[22 * j + k + 1];

			double lo = input.Tx_Longitude;
			double la = input.Tx_Latitude;

			// Get Tx Lon Lan which
			CBR_CoordinatesM(longRxTmp, latRxTmp, lo, la, d2b, input.Tx_Serv_area, filenameTestCutTx);

			if ((input.D_to_border != 0) && Test_cutM(longRxTmp, latRxTmp, lo, la, coCp, nCp)){
				continue;
			}
				

			inputLine.Tx_Longitude = lo;
			inputLine.Tx_Latitude = la;
			inputLine.Rx_Longitude = longRxTmp;
			inputLine.Rx_Latitude = latRxTmp;

			PointToPointForLine(inputLine, output, terra);
			if (output.HCM_error >0) {
				continue; 
			}

			if (output.Calculated_FS >= fsX) {
				fsX = output.Calculated_FS;
				recX = k;
				recNX = j;
			}
		}
	}

	if (recNX >= 0) {
		longRxTmp = nFile[22 * recNX + recX];
		latRxTmp = nFile[22 * recNX + recX + 1];
		double lo = input.Tx_Longitude;
		double la = input.Tx_Latitude;
		CBR_CoordinatesM(longRxTmp, latRxTmp, lo, la, d2b, input.Tx_Serv_area, filenameTestCutTx);

		inputLine.Tx_Longitude = lo;
		inputLine.Tx_Latitude = la;
		inputLine.Rx_Longitude = longRxTmp;
		inputLine.Rx_Latitude = latRxTmp;

		PointToPointForLine(inputLine, output, terra);
		
		WriteDebugInformationOutput(input, output, terra);
			
	} else {
		output.HCM_error = 1047; //Distance to borderline is too long
	}
}


extern "C" void LIBRARY_API CbrCalc(PointToPoint_Input_Parameters &input, PointToPoint_Output_Parameters &output){
	output.HCM_error = 0;
	std::strcpy(output.Version, "Version 1.19 CbrCalc");
	for (int i = 0; i < 20; ++i) {output.Info[i] = false;};

	WriteDebugInformationInput(input);

	if (input.C_Mode<-11 || input.C_Mode>12){
		output.HCM_error = 1025;// "C_mode is out of range"
		return;
	}

	if (input.Sea_temperature[0] != 'W' && 
	    input.Sea_temperature[0] != 'I' && 
	    input.Sea_temperature[0] != 'C') {
	    input.Sea_temperature[0] = 'W';
	}

	(input.Chan_occup == 0 || input.Chan_occup == 1) ? input.Chan_occup : input.Chan_occup=0;
	if (input.PointDistance < 0.03 || input.PointDistance > 1){input.PointDistance = 0.1;};

	HcmTerrain terra;
	terra.PathToTopo = input.Topo_path;
	terra.PathToMorpho = input.Morpho_path;
	terra.stepProfile = input.PointDistance;

	if (Trimmer(input.Tx_Ant_typ_H).empty()) {
	    std::strcpy(input.Tx_Ant_typ_H, "000ND00");
	}
	if (Trimmer(input.Tx_Ant_typ_V).empty()) {
	    std::strcpy(input.Tx_Ant_typ_V, "000ND00");
	}
	if (input.Tx_Type_of_Ant == 0 || input.Tx_Type_of_Ant == 1){//(E/I)
		input.Tx_Type_of_Ant == 0 ? output.Tx_ant_type_corr = 0.0 :	output.Tx_ant_type_corr = 2.1;
	} else {
		output.HCM_error = 1033;//, "Error in type of Tx antenna (E/I)"},
		return;
	};
	if (input.Tx_Longitude < -180 || input.Tx_Longitude>180){
		output.HCM_error = 1001;//"Error in geographical coordinates (Tx longitude, degrees)"
		return;
	}
	if (input.Tx_Latitude < -89.9 || input.Tx_Latitude>89.9){
		output.HCM_error = 1005;//"Error in geographical coordinates (Tx latitude, degrees)"
		return;
	}
	if (input.Tx_Power < -100 || input.Tx_Power>100){
		output.HCM_error = 1034;//"Error in power"
		return;
	}
	output.Power_to_Rx = input.Tx_Power - output.Tx_ant_type_corr;

	if (input.Tx_H_Ant < 0 || input.Tx_H_Ant>150){
		output.HCM_error = 1009;//"Error in Tx antenna height"
		return;
	}
	if (input.Tx_Serv_area < 0 || input.Tx_Serv_area>150){
		output.HCM_error = 1012;// "Error in radius of service area of Tx"
		return;
	}
	if (input.D_to_border > 999 || input.D_to_border == HCM4A_ERROR_VALUE_INT) {
		output.HCM_error = 1047;	// Distance to borderline is too long
		return;
	}


	input.Rx_Serv_area = 0;
	input.Rx_Freq = 0;
	std::strcpy(input.Rx_Desig_of_emis, "       ");
	input.Rx_H_Ant = 10;
	std::string txDesig(input.Tx_Desig_of_emis);
	std::string rxDesig(input.Rx_Desig_of_emis);
	output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
	switch(input.C_Mode) {
	case -1://-1	point to line calculation (t%=Channel occ., 10m)
		if(input.Tx_Freq >= 29.7 && input.Tx_Freq <= 47.0) {
			output.Perm_FS = 0.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 3.0;
			output.Info[4] = false;
			if (input.useAnnex1) input.D_to_border = 100; // annex1
		}
		else if(input.Tx_Freq >= 68.0 && input.Tx_Freq <= 74.8) {
			output.Perm_FS = 6.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 9.0;
			output.Info[4] = false;
			if (input.useAnnex1) input.D_to_border = 100; // annex1
		}
		else if(input.Tx_Freq >= 75.2 && input.Tx_Freq <= 87.5) {
			output.Perm_FS = 6.0;
			output.Table_CBR_D = 100.0;
			output.ERP_ref_Tx = 9.0;
			output.Info[4] = false;
			if (input.useAnnex1) input.D_to_border = 100; // annex1
		}
		else if(input.Tx_Freq >= 146.0 && input.Tx_Freq <= 149.9) {
			output.Perm_FS = 12.0;
			output.Table_CBR_D = 80.0;
			output.ERP_ref_Tx = 12.0;
			output.Info[4] = false;
			if (input.useAnnex1) input.D_to_border = 80; // annex1
		}
		else if(input.Tx_Freq >= 150.05 && input.Tx_Freq <= 174.0) {
			output.Perm_FS = 12.0;
			output.Table_CBR_D = 80.0;
			output.ERP_ref_Tx = 12.0;
			output.Info[4] = false;
			if (input.useAnnex1) input.D_to_border = 80; // annex1
		}
		else if(input.Tx_Freq >= 380.0 && input.Tx_Freq <= 385.0) {
			output.Perm_FS = 18.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 14.0;
			output.Info[4] = false;
			output.Info[18] = true;
			if (input.useAnnex1) input.D_to_border = 50; // annex1
		}
		else if(input.Tx_Freq >= 390.0 && input.Tx_Freq <= 395.0) {
			output.Perm_FS = 18.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 14.0;
			output.Info[4] = false;
			output.Info[18] = true;
			if (input.useAnnex1) input.D_to_border = 50; // annex1
		}
		else if(input.Tx_Freq >= 406.1 && input.Tx_Freq <= 430.0) {
			output.Perm_FS = 20.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 16.0;
			output.Info[4] = false;
			if (input.useAnnex1) input.D_to_border = 50; // annex1
		}
		else if(input.Tx_Freq >= 440.0 && input.Tx_Freq <= 470.0) {
			output.Perm_FS = 20.0;
			output.Table_CBR_D = 50.0;
			output.ERP_ref_Tx = 16.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 862.0 && input.Tx_Freq <= 960.0) {
			output.Perm_FS = 26.0;
			output.Table_CBR_D = 30.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 1710.0 && input.Tx_Freq <= 1785.0) {
			output.Perm_FS = 35.0;
			output.Table_CBR_D = 15.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else if(input.Tx_Freq >= 1805.0 && input.Tx_Freq <= 1880.0) {
			output.Perm_FS = 35.0;
			output.Table_CBR_D = 15.0;
			output.ERP_ref_Tx = 13.0;
			output.Info[4] = false;
		}
		else {
			output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
			output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
			output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
			output.Info[4] = true;
		}

		if ((output.Info[18] && txDesig.substr(0, 7) == "25K0G7W" && 
		     rxDesig.substr(0, 7) == "25K0G7W") ||
		    input.Chan_occup == 0) {
		    output.Time_percentage = 10;
		}
		else {
			output.Time_percentage = 1;
		}
		break;
	case -9://-9	point to line calculation (t%=10%, 3m)
		output.Time_percentage = 10;
		input.Rx_H_Ant = 3;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case -10://-10	point to line calculation (t%=10%, 10m)
		output.Time_percentage = 10;
		input.Rx_H_Ant = 10;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	case -11://-11	point to line calculation (t%=50%, 3m)
		output.Time_percentage = 50;
		input.Rx_H_Ant = 3;
		output.Table_CBR_D = HCM4A_ERROR_VALUE_DOUBLE;
		output.ERP_ref_Tx = HCM4A_ERROR_VALUE_DOUBLE;
		output.Perm_FS = HCM4A_ERROR_VALUE_DOUBLE;
		output.Info[4] = true;
		break;
	default:
		output.HCM_error = 1025; //"C_mode is out of range"
		return;
	}

	if (input.C_Mode > 0){
		if (input.Max_CBR_D_input < 0 || input.Max_CBR_D_input > 0){
			output.HCM_error = 1027;// "Error in input value of maximum cross border range
			return;
		}
		output.Info[6] = true;//Input value of maximum cross border range is used
		if(output.Info[4] && input.C_Mode < 0 && input.D_to_border < 0) {
			output.HCM_error = 1050;
			return;
		}
	}

	output.Perm_FS_from_table = output.Perm_FS;
	output.AnnexInFreqRange = false;
	if (input.useAnnex1 && output.Perm_FS_from_table>HCM4A_ERROR_VALUE_DOUBLE){
			output.AnnexInFreqRange = true;
	}else{
		if(input.Perm_FS_input >HCM4A_ERROR_VALUE_DOUBLE) {
			output.Info[5] = true;
			output.Perm_FS = input.Perm_FS_input;
		}
		else {
			if(output.Info[4]) {
				output.HCM_error = 1026; //"Error in input value of permissible field strength"},
				return;
			}
		}
	}

	output.Prot_margin = 0;




	PointToPoint_Input_Parameters inputLine;
	inputLine = input;
	inputLine.Rx_Freq = inputLine.Tx_Freq;

	// Select line data
	std::vector<double> nRecord(22), nFile(30800);
	std::vector<Coordinate> coCp(1400);
	int nCp = 0;
	int nAll = 0;
	int recX = 0;
	int recNX = -1;
	int count_in_Nlist = 0;
	std::vector<int> ListIndexes(3);
	std::vector<double> ListMaxFS(3);
	double longRxTmp, latRxTmp;
	int d2b = input.D_to_border;

	std::string filenameTestCutTx = std::string(input.Border_path, 256) + 
                                std::string(input.Land_from, 3) + 
                                ".all";

	std::string BorderFile = std::string(input.Land_from, 3) + 
	                         std::string(input.Land_to, 3) + 
	                         ".cbr";
	                         
	// all BORDERLINE centerpoints of the affected country:
	std::ifstream file(input.Border_path + BorderFile.substr(0, 7) + "000", std::ios::binary);
	if (!file) {
		output.HCM_error = 1048;// Selected line data not available
		return;
	}
	// Store all center points table 'Co_cp(i,j)'
	while (nCp < 1400 && file.read(reinterpret_cast<char*>(nRecord.data()), 176)) {
		coCp[nCp].longitude = nRecord[20] * RadToDeg;
		coCp[nCp].latitude = nRecord[21] * RadToDeg;
		nCp++;
	}
	file.close();
	nCp--;



	// Open line file and cache full line D_to_border
	file.open(input.Border_path + BorderFile, std::ios::binary);
	if (!file) {
		output.HCM_error = 1048;  // Selected line data not available
		return;
	}

	while (nAll < 1400 && file.read(reinterpret_cast<char*>(&nFile[nAll * 22]), 176)) {
		nAll++;
	}
	file.close();

	for (int i=0; i<=nAll*22; ++i){
		nFile[i] = nFile[i] * RadToDeg;
	}
	nAll--;



	for (int i = 0; i < 3; ++i) {
		ListIndexes[i] = 0;
		ListMaxFS[i] = -500.0;
	}


	// TEST EACH POINT
	double fsX = -999.9;
	for (int j = 0; j <= nAll; ++j) {
		for (int k = 0; k < 20; k += 2) {
			longRxTmp = nFile[22 * j + k];
			latRxTmp = nFile[22 * j + k + 1];
			double lo = input.Tx_Longitude;
			double la = input.Tx_Latitude;

			// Get Tx Lon Lan which
			CBR_CoordinatesM(longRxTmp, latRxTmp, lo, la, -d2b, input.Tx_Serv_area, filenameTestCutTx);

			int count = Test_cutCount(longRxTmp, latRxTmp, lo, la, coCp, nCp);
			if (count % 2 == 0){
				continue;
			}

			inputLine.Tx_Longitude = lo;
			inputLine.Tx_Latitude = la;
			inputLine.Rx_Longitude = longRxTmp;
			inputLine.Rx_Latitude = latRxTmp;

			PointToPointForLine(inputLine, output, terra);
			if (output.HCM_error >0) {
				continue;
			}

			if (output.Calculated_FS >= fsX) {
				fsX = output.Calculated_FS;
				recX = k;
				recNX = j;
			}
		}
	}
	
	if (recNX >= 0) {
		longRxTmp = nFile[22 * recNX + recX];
		latRxTmp = nFile[22 * recNX + recX + 1];
		double lo = input.Tx_Longitude;
		double la = input.Tx_Latitude;
		CBR_CoordinatesM(longRxTmp, latRxTmp, lo, la, -d2b, input.Tx_Serv_area, filenameTestCutTx);
		
		inputLine.Tx_Longitude = lo;
		inputLine.Tx_Latitude = la;
		inputLine.Rx_Longitude = longRxTmp;
		inputLine.Rx_Latitude = latRxTmp;

		PointToPointForLine(inputLine, output, terra);

		WriteDebugInformationOutput(input, output, terra);

	} else {
		output.HCM_error = 1047; //Distance to borderline is too long
	}


	WriteDebugInformationOutput(input, output, terra);
}