// Lösungen zu "Richard Kaiser: C++ mit dem Borland C++Builder 2007", ISBN: 978-3-540-69575-2
// Copyright Richard Kaiser, 2007. http://www.rkaiser.de. All rights reserved.
// Diese Quelltexte dürfen in eigenen Programmen verwendet werden, wenn sie einen Hinweis auf die Quelle (die ersten beiden Zeilen) enthalten. In keinem Fall wird eine Haftung für direkte, indirekte, zufällige oder Folgeschäden übernommen, die sich aus der Nutzung ergeben.
// It is permitted to use this source text in programs of your own, provided that it contains a reference to the source (the first two lines above). All liabilities for use of the code are disclaimed.

#include <vcl\vcl.h>
#pragma hdrstop
#include "StringsU.h"
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------

#include "..\..\CppUtils\TestUtils.h"

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
#ifdef _DEBUG
initTestUtils();
bool test_StringAll(); // Prototyp
testUtilsSummary(Memo1, test_StringAll());
#endif
}

#include <string>
using std::string; // or: using namespace std;


// --------------- Aufgabe 4.1, 1. -------------------------

// siehe

#include "..\..\CppUtils\StringUt.h"

void __fastcall TForm1::stringToInt_Click(TObject *Sender)
{
string s=Edit1->Text.c_str();
bool success;
int x=stringToInt(s,success);
Memo1->Lines->Add(IntToStr(x)+" success="+BoolToStr(success,true));
}
      
void __fastcall TForm1::stringToDouble_Click(TObject *Sender)
{
string s=Edit1->Text.c_str();
bool success;
double x=stringToDouble(s,success);
Memo1->Lines->Add(FloatToStr(x)+" success="+BoolToStr(success,true));
}

void __fastcall TForm1::tostring_intClick(TObject *Sender)
{
int x=StrToInt(Edit1->Text);
string s=tostring(x);
Memo1->Lines->Add(s.c_str());
}

void __fastcall TForm1::tostring_doubleClick(TObject *Sender)
{
double x=StrToFloat(Edit1->Text);
string s=tostring(x);
Memo1->Lines->Add(s.c_str());
}


// --------------- Aufgabe 4.1, 2. -------------------------

// a)
struct Date_t {
  int day, month, year;
};

Date_t stringToDate(const string& date)
{
Date_t result;
bool success=true;
string::size_type p1 = date.find(".");
if (p1!=string::npos)
  {
    string dstr = date.substr(0,p1);
    string::size_type p2  = date.find(".",p1+1);
    if (p2!=string::npos)
      {
        string mstr = date.substr(p1+1,p2-p1-1);
        string ystr = date.substr(p2+1,date.length()-p1);

        bool succ;
        result.day   = stringToInt(dstr,succ);
        if (!succ) success=false;
        result.month = stringToInt(mstr,succ);
        if (!succ) success=false;
        result.year  = stringToInt(ystr,succ);
        if (!succ) success=false;
      }
    else success=false;
  }
else success=false;
if (!success)
  {
     Date_t failed={-1,-1,-1};
     result=failed;
  }
return result;
}

// b)
bool assertEqual(Date_t f, Date_t s, AnsiString msg,
                                            TCustomMemo* Memo=Form1->Memo1)
{
return assertTrue((f.day==s.day) && (f.month==s.month) && (f.year==s.year),
                  msg, Memo);
}

bool test_one_date(string s, int day, int month, int year)
{
Date_t d1=stringToDate(s);
Date_t d2={day,month,year};
return assertEqual(d1,d2,"test_one_date: "+AnsiString(s.c_str()));
}

bool test_StringToDate()
{
bool result = true;
// teste alle üblichen Kombinationen
// Jahr zweistellig, Tag und Monat einstellig und zweistellig
if (!test_one_date("1.2.07",1,2,7)) result=false;
if (!test_one_date("12.3.07",12,3,7)) result=false;
if (!test_one_date("1.12.07",1,12,7)) result=false;
if (!test_one_date("17.18.07",17,18,7)) result=false;

// Jahr vierstellig, Tag und Monat einstellig und zweistellig
if (!test_one_date("1.2.1920",1,2,1920)) result=false;
if (!test_one_date("12.3.1920",12,3,1920)) result=false;
if (!test_one_date("1.12.1920",1,12,1920)) result=false;
if (!test_one_date("17.18.1920",17,18,1920)) result=false;

// Teste unzulässige Formate. Das Programm sollte nicht abstürzen
//                            und -1 zurückgeben:
if (!test_one_date("",   -1,-1,-1)) result=false;
if (!test_one_date(".",  -1,-1,-1)) result=false;
if (!test_one_date("1",  -1,-1,-1)) result=false;
if (!test_one_date("1.", -1,-1,-1)) result=false;
if (!test_one_date("1.2",-1,-1,-1)) result=false;
if (!test_one_date("..", -1,-1,-1)) result=false;
if (!test_one_date("...",-1,-1,-1)) result=false;
if (!test_one_date("abc",-1,-1,-1)) result=false;
if (!test_one_date("1. Dezember ",-1,-1,-1)) result=false;
return result;
}

void __fastcall TForm1::Button_4_1_2Click(TObject *Sender)
{
Date_t d=stringToDate(Edit1->Text.c_str());
Memo1->Lines->Add(Edit1->Text+": Tag="+IntToStr(d.day)+
           " Monat="+IntToStr(d.month)+
           " Jahr="+IntToStr(d.year));
}


// --------------- Aufgabe 4.1, 3. -------------------------

// a)
void tokenize_0(const string& s, string separators=";.,- ")
{ // ";.,- " ist ein Default Argument für den Parameter separators
  // Damit kann tokenize ohne Argument für den zweiten Parameter aufgerufen
  // werden. separators kann auch als lokale Variable definiert werden.
Form1->Memo1->Lines->Add("string Test: "+AnsiString(s.c_str()));
string::size_type pos_tok=s.find_first_not_of(separators);
while (pos_tok!=string::npos)
  { // token gefunden ab Position pos_tok
    string::size_type  pos_sep=s.find_first_of(separators,pos_tok);
    if (pos_sep==string::npos)
      pos_sep=s.length();
    string token=s.substr(pos_tok,pos_sep-pos_tok);

    Form1->Memo1->Lines->Add("'"+AnsiString(token.c_str())+"'");
    pos_tok=s.find_first_not_of(separators,pos_sep+1);
  }
}

void __fastcall TForm1::Button_4_1_3_testClick(TObject *Sender)
{
tokenize_0("");      // leerer String , keine Ausgabe
tokenize_0(" ");     // nur Separator, keine Ausgabe

tokenize_0("123");   // nur token, Ausgabe "123"
tokenize_0(";123");  // Separator am Anfang, ein token, Ausgabe "123"
tokenize_0("123;");  // Separator am Ende, ein token, Ausgabe "123"
tokenize_0(";123;"); // Separator am Anfang und Ende, ein token, Ausgabe "123"

tokenize_0("456 ab.xy");   //Ausgabe "456", "ab", "xy"
tokenize_0(" 456 ab.xy");  // Separator am Anfang, Ausgabe "789","ab","xy"
tokenize_0("456 ab.xy;");  // Separator am Ende, Ausgabe "789","ab","xy"
tokenize_0(" 456 ab.xy;"); // Separator am Anfang und am Ende, Ausgabe "789","ab","xy"
}


void __fastcall TForm1::Button_4_1_3Click(TObject *Sender)
{
tokenize_0(Edit1->Text.c_str()); // separator at the beginning and the end, output "789","ab","xy"
}


// --------------- Aufgabe 4.1.4 ---------------------------

// siehe StringUt.cpp

void __fastcall TForm1::Button_4_1_4Click(TObject *Sender)
{
AnsiString a1=Edit1->Text;
AnsiString a2=Edit2->Text;
string s1=a1.c_str();
string s2=a2.c_str();

double n=StringSimilarityNGram(s1,s2);
Memo1->Lines->Add("StringSimilarityNGram("+a1+","+a2+")="+
                     FloatToStr(n));
}


// --------------- Aufgabe 4.1.5 ---------------------------

void __fastcall TForm1::Button415Click(TObject *Sender)
{
AnsiString a1=Edit1->Text;
AnsiString a2=Edit2->Text;
string s1=a1.c_str();
string s2=a2.c_str();
string s;
int n=lcsLength(a1.c_str(),a2.c_str(),s);
Memo1->Lines->Add("lcs("+a1+","+a2+")='"+s.c_str()+"' n="
                       +IntToStr(n));
}


#ifdef _DEBUG
bool test_StringAll()
{
bool result=true;
if (!test_StringUtAll()) result=false;
if (!test_StringToDate()) result=false;
return result;
}
#endif


