/*
Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO

This file is part of QtSoundModem

QtSoundModem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

QtSoundModem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with QtSoundModem.  If not, see http://www.gnu.org/licenses

*/

// UZ7HO Soundmodem Port by John Wiseman G8BPQ
#include "UZ7HOStuff.h"

// TStringlist And String emulation Functions

// Dephi seems to mix starting counts at 0 or 1. I'll try making everything
// base zero. 

// Initialise a list

void CreateStringList(TStringList * List)
{
	List->Count = 0;
	List->Items = 0;
}


int Count(TStringList * List)
{
	return List->Count;
}

string * newString()
{
	// Creates and Initialises a string 

	UCHAR * ptr = malloc(sizeof(string));			// Malloc Data separately so it can be ralloc'ed
	string * New = (string *)ptr;
	New->Length = 0;
	New->AllocatedLength = 256;
	New->Data = malloc(256);

	return New;
}

void initString(string * S)
{
	S->Length = 0;
	S->AllocatedLength = 256;
	S->Data = malloc(256);
}

void initTStringList(TStringList* T)
{
	//string * New = newString();

	T->Count = 0;
	T->Items = NULL;

	//Add(T, New);
}



TStringList * newTStringList()
{
	TStringList * T = (TStringList *) malloc(sizeof(TStringList));
	string * New = newString();

	T->Count = 0;
	T->Items = NULL;

	Add(T, New);

	return T;
}


void freeString(string * Msg)
{
	if (Msg->Data)
		free(Msg->Data);

	free(Msg);
}

string * Strings(TStringList * Q, int Index)
{
	if (Index >= Q->Count)
		return NULL;

	return Q->Items[Index];
}

int Add(TStringList * Q, string * Entry)
{
	Q->Items = realloc(Q->Items,(Q->Count + 1) * sizeof(void *));
	Q->Items[Q->Count++] = Entry;

	return (Q->Count);
}


void mydelete(string * Source, int StartChar, int Count)
{
	 //Description
	//The Delete procedure deletes up to Count characters from the passed parameter Source string starting
	//from position StartChar.

	if (StartChar > Source->Length)
		return;

	int left = Source->Length - StartChar;

	if (Count > left)
		Count = left;

	memmove(&Source->Data[StartChar], &Source->Data[StartChar + Count], left - Count);

	Source->Length -= Count;
}
 

void Delete(TStringList * Q, int Index)
{
	// Remove item at Index and move rest up list
	// Index starts at zero
	
	if (Index >= Q->Count)
		return;

	// We should free it, so user must duplicate msg if needed after delete

	freeString(Q->Items[Index]);
//	free(Q->Items[Index]);

	Q->Count--;

	while (Index < Q->Count)
	{
		Q->Items[Index] = Q->Items[Index + 1];
		Index++;
	}
}

void setlength(string * Msg, int Count)
{
	// Set length, allocating more space if needed

	if (Count > Msg->AllocatedLength)
	{
		Msg->AllocatedLength = Count + 256;
		Msg->Data = realloc(Msg->Data, Msg->AllocatedLength);
	}

	Msg->Length = Count;
}

string * stringAdd(string * Msg, UCHAR * Chars, int Count)
{
	// Add Chars to string 

	if (Msg->Length + Count > Msg->AllocatedLength)
	{
		Msg->AllocatedLength += Count + 256;
		Msg->Data = realloc(Msg->Data, Msg->AllocatedLength);
	}

	memcpy(&Msg->Data[Msg->Length], Chars, Count);
	Msg->Length += Count;
	
	return Msg;
}

void Clear(TStringList * Q)
{
	int i = 0;

	if (Q->Items == NULL)
		return;

	while (Q->Count)
	{
		freeString(Q->Items[i++]);
		Q->Count--;
	}

	free(Q->Items);

	Q->Items = NULL;
}

// procedure move ( const SourcePointer; var DestinationPointer; CopyCount : Integer ) ;
// Description
// The move procedure is a badly named method of copying a section of memory from one place to another.
 
// CopyCount bytes are copied from storage referenced by SourcePointer and written to DestinationPointer
 
void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount)
{
	memmove(DestinationPointer, SourcePointer, CopyCount);
}

void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount)
{
	memmove(DestinationPointer, SourcePointer, CopyCount);
}



//Description
//The copy function has 2 forms. In the first, it creates a new string from part of an existing string. In the second, it creates a new array from part of an existing array.
 
//1.String copy
 
//The first character of a string has index = 1.

//Up to Count characters are copied from the StartChar of the Source string to the returned string.
//Less than Count characters if the end of the Source string is encountered before Count characters have been copied.


string * copy(string * Source, int StartChar, int Count)
{
	string * NewString = newString();
	int end = StartChar + Count;

	if (end > Source->Length)
		Count = Source->Length - StartChar;

	memcpy(NewString->Data, &Source->Data[StartChar], Count);

	NewString->Length = Count;

	return NewString;
}

// Duplicate from > to

void Assign(TStringList * to, TStringList * from)
{
	int i;

	Clear(to);

	if (from->Count == 0)
		return;

	// Duplicate each item

	for (i = 0; i < from->Count; i++)
	{
		string * new = newString();

		stringAdd(new, from->Items[i]->Data, from->Items[i]->Length);
		Add(to, new);
	}
}

string * duplicateString(string * in)
{
	string * new = newString();

	stringAdd(new, in->Data, in->Length);

	return new;
}


double pila(double x)
{
	//x : = frac(x); The frac function returns the fractional part of a floating point number.

	double whole;
	double rem;

	rem = modf(x, &whole);  // returns fraction, writes whole to whole

	if (rem != rem)
		rem = 0;

	if (rem > 0.5)
		rem = 1 - rem;

	return 2 * rem;
}

boolean compareStrings(string * a, string * b)
{
	if (a->Length == b->Length && memcmp(a->Data, b->Data, a->Length) == 0)
		return TRUE;

	return FALSE;
}

// This looks for a string in a stringlist. Returns index if found, otherwise -1

int  my_indexof(TStringList * l, string * s)
{
	int i;

	for (i = 0; i < l->Count; i++)
	{
		// Need to compare count and data - C doesn't allow struct compare

		if (l->Items[i]->Length == s->Length && memcmp(l->Items[i]->Data, s->Data, s->Length) == 0)
			return i;
	}
	return -1;
}