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

#include <vcl.h>
#pragma hdrstop

#include "Editor.h"
#include "Editor_add.h"
#include "knihovna.h"
#include <stdio.h>

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TMap Mapa;
int Node=0;
bool Saved=true;        //kvuli ukladani pri skonceni
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}



//funkce pro kresleni mapy---------------------------------------------------------------------------
void DrawNode(int centerX,int centerY,int size,TMap *Map,int ID)             //kresli krizovatku
{
if(Map->node[GetOrder(Map,ID)-1].terminal)
        {
        Form1->Canvas->RoundRect(centerX-4*size,centerY-4*size,centerX+4*size,centerY+4*size,2*size,2*size);
        }
else
        {
        Form1->Canvas->Ellipse(centerX-4*size,centerY-4*size,centerX+4*size,centerY+4*size);
        }
Form1->Canvas->TextOutA(centerX+size,centerY-7*size,AnsiString(Map->node[GetOrder(Map,ID)-1].name));
Form1->Canvas->TextOutA(centerX-size,centerY,AnsiString(ID));
}



void Redraw(TMap *Map) //vykresleni na canvas
{

Form1->Panel1->Visible=true;           //vycisteni obrazovky
Form1->Panel1->Visible=false;


//----------------------------vytvoreni rastru mapy
class TRastr
{
public:
int ID;              //ID krizovatky
bool set;               //ma umisteny sousedy
};

int wasChanged;           //znaci esi este doslo k nejake zmene
TRastr rastr[2*COUNT][2*COUNT];    //rastr na kterem bude rozlozena mapa podle poradi
for(int i=0;i<2*COUNT;i++)       //vycisteni rastru
        {
        for(int j=0;j<2*COUNT;j++)
                {
                rastr[i][j].ID=-1;
                rastr[i][j].set=false;
                }

        }
rastr[COUNT][COUNT].ID=Map->node[0].ID;
rastr[COUNT-1][COUNT].ID=Map->node[GetOrder(Map,rastr[COUNT][COUNT].ID)-1].neighbour[0];            //horni
rastr[COUNT][COUNT-1].ID=Map->node[GetOrder(Map,rastr[COUNT][COUNT].ID)-1].neighbour[1];
rastr[COUNT+1][COUNT].ID=Map->node[GetOrder(Map,rastr[COUNT][COUNT].ID)-1].neighbour[2];
rastr[COUNT][COUNT+1].ID=Map->node[GetOrder(Map,rastr[COUNT][COUNT].ID)-1].neighbour[3];
rastr[COUNT][COUNT].set=true;
int range=0;                        //pro zmenseni rozsahu hledani

while(wasChanged)
        {
        wasChanged=0;
        if(range<COUNT)
                {
                range++;
                }
        for(int i=COUNT-range;i<COUNT+1+range;i++)       //vyhledani dalsi krizovatky
                {
                for(int j=COUNT-range;j<COUNT+1+range;j++)
                        {
                        if(rastr[i][j].ID>=0 && !rastr[i][j].set)       //pokud uz je umistena
                                {
                                if(Map->node[GetOrder(Map,rastr[i][j].ID)-1].terminal)       //toto je tu aby sousedama cilove stanice neprepisoval vedlejsi krizovatky
                                        {
                                        rastr[i][j].set=true;
                                        wasChanged++;
                                        }
                                else
                                {
                                for(int k=0;k<4;k++)
                                        {
                                        if(Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[k]==rastr[i][j-1].ID && rastr[i][j-1].ID>0) //zkontroluje krizovatku nalevo
                                                {
                                                int l=k+1;
                                                if(l>3)l=0;
                                                int tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i+1][j].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i][j+1].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i-1][j].ID=tmp;
                                                rastr[i][j].set=true;
                                                wasChanged++;
                                                }
                                        if(Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[k]==rastr[i+1][j].ID && rastr[i+1][j].ID>0) //zkontroluje krizovatku dole
                                                {
                                                int l=k+1;
                                                if(l>3)l=0;
                                                int tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i][j+1].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i-1][j].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i][j-1].ID=tmp;
                                                rastr[i][j].set=true;
                                                wasChanged++;
                                               }
                                        if(Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[k]==rastr[i][j+1].ID && rastr[i][j+1].ID>0) //zkontroluje krizovatku napravo
                                                {
                                                int l=k+1;
                                                if(l>3)l=0;
                                                int tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i-1][j].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i][j-1].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i+1][j].ID=tmp;
                                                rastr[i][j].set=true;
                                                wasChanged++;

                                                }
                                        if(Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[k]==rastr[i-1][j].ID && rastr[i-1][j].ID>0) //zkontroluje krizovatku nahore
                                                {
                                                int l=k+1;
                                                if(l>3)l=0;
                                                int tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i][j-1].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i+1][j].ID=tmp;
                                                if(l>3)l=0;
                                                tmp=Map->node[GetOrder(Map,rastr[i][j].ID)-1].neighbour[l++];
                                                if(tmp>0)rastr[i][j+1].ID=tmp;
                                                rastr[i][j].set=true;
                                                wasChanged++;
                                                }
                                }

                                        }
                                }

                        }
                }

        }
//------------------------------------------- vypocet rozmeru grafu
int vMax=0;
int vMin=0;
int hMax=0;
int hMin=0;

for(int i=COUNT-range;i<=COUNT+range;i++)                  //hledani nejsevernejsi krizovatky
        {
        for(int j=COUNT-range;j<=COUNT+range;j++)
                {
                if(vMin==0 && rastr[i][j].ID!=-1)
                        {
                        vMin=i;
                        }
                }
        }

for(int i=COUNT+range;i>=COUNT-range;i--)                  //hledani nejjiznejsi krizovatky
        {
        for(int j=COUNT+range;j>=COUNT-range;j--)
                {
                if(vMax==0 && rastr[i][j].ID!=-1)
                        {
                        vMax=i;
                        }
                }
        }

for(int j=COUNT-range;j<=COUNT+range;j++)                  //hledani nejzapadnejsi krizovatky
        {
        for(int i=COUNT-range;i<=COUNT+range;i++)
                {
                if(hMin==0 && rastr[i][j].ID!=-1)
                        {
                        hMin=j;
                        }
                }
        }

for(int j=COUNT+range;j>=COUNT-range;j--)                  //hledani nejjiznejsi krizovatky
        {
        for(int i=COUNT+range;i>=COUNT-range;i--)
                {
                if(hMax==0 && rastr[i][j].ID!=-1)
                        {
                        hMax=j;
                        }
                }
        }
//ShowMessage(vMax-vMin+1);
//ShowMessage(hMax-hMin+1);

//---------------------vypis do souboru

FILE *f;
f=fopen("rastr.txt","wt");
for(int i=COUNT-range;i<=COUNT+range;i++)
        {
        for(int j=COUNT-range;j<=COUNT+range;j++)
                {
                fprintf(f,"%3d",rastr[i][j].ID);
                }
        fprintf(f,"\n");
        }
fclose(f);



//----------------------------kresleni

int size=1;
if(Form1->Panel1->Height/(vMax-vMin+1) > Form1->Panel1->Width/(hMax-hMin+1))        //vypocet velikosti uzlu
        {
        size=Form1->Panel1->Width/((hMax-hMin+1)*20);
        }
else
        {
        size=Form1->Panel1->Height/((vMax-vMin+1)*20);
        }
//ShowMessage(AnsiString(vMin)+' '+AnsiString(vMax));
int offX=5*size+Form1->Panel1->Left;                //offset na X-ose
int offY=15*size+Form1->Panel1->Top;                //offset na Y-ose


Form1->Canvas->Pen->Width=size;            //tloustka cary
Form1->Panel1->Visible=false;
for(int i=vMin;i<=vMax;i++)
        {
        for(int j=hMin;j<=hMax;j++)
                {
                if(rastr[i][j].ID>=0)
                        {
                        int x=offX+(j-hMin)*20*size;                            
                        int y=offY+(i-vMin)*20*size;
                        DrawNode(x,y,size,&Mapa,rastr[i][j].ID);                //kresleni uzlu
                                                                                //kresleni cest

                        int tmp=GetOrder(Map,rastr[i][j].ID)-1;                  //zjisti poradi krizovatky
                        int tmpS=GetOrder(Map,rastr[i-1][j].ID)-1;     //zjisti poradi suseda nahore
                     //   int tmpZ=GetOrder(Map,rastr[i][j-1].ID)-1;     //zjisti poradi suseda nalevo
                     //   int tmpJ=GetOrder(Map,rastr[i+1][j].ID)-1;     //zjisti poradi suseda dole
                        int tmpV=GetOrder(Map,rastr[i][j+1].ID)-1;     //zjisti poradi suseda napravo
                        if(Map->edge[tmp][tmpS]>0)                     //nakresli svisle cesty
                                        {
                                        Form1->Canvas->Rectangle(x,y-4*size,x+1,y-16*size);// LineX(x-5*size,y+8);
                                        Form1->Canvas->TextOutA(x-2*size,y-12*size,AnsiString(Map->edge[tmp][tmpS]));
                                        }
                        if(Map->edge[tmp][tmpV]>0)                     //nakresli vodorovne cesty
                                        {
                                        Form1->Canvas->Rectangle(x+4*size,y,x+16*size,y+1);// LineX(x-5*size,y+8);
                                        Form1->Canvas->TextOutA(x+10*size,y+size,AnsiString(Map->edge[tmp][tmpV]));
                                        }
                        }
                }
        }

}


void TForm1::refresh(TObject *Sender)               //aktualizace formu
{
ComboBox1->Items->Clear();
ComboBox2->Items->Clear();
ComboBox3->Items->Clear();
for(int i=0;i<Mapa.count;i++)
        {
        ComboBox1->Items->Add(Mapa.node[i].ID);
        ComboBox2->Items->Add(Mapa.node[i].order);
        ComboBox3->Items->Add(Mapa.node[i].name);
        };
Edit2->Text="";
Edit3->Text="";
Edit4->Text="";
Edit5->Text="";
Edit6->Text="";
Edit7->Text="";
Edit8->Text="";
Edit9->Text="";
CheckBox1->Checked=false;
}


void __fastcall TForm1::Button1Click(TObject *Sender)
{
int flag=1;
char cesta[30];"mapa.txt";
strcpy(cesta,Edit1->Text.c_str());
flag=Read(cesta,&Mapa);
if(flag!=0)
        {
        ShowMessage("Chyba pri nacitani souboru");
        }
else
        {
        ShowMessage("Mapa byla nactena ze souboru: "+AnsiString(cesta));
        }
refresh(Sender);                             //aktualizace formu

ComboBox2->Text=1;                          //toto je tam enom aby sa nastavily hodnoty po nacteni
ComboBox2Select(Sender);                    //na prvni krizovatku
Saved=true;
Button6Click(Sender);       //prime volani Redraw z nejakeho zahadneho duvodu zlobi
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Button2Click(TObject *Sender)
{
int flag=1;
char cesta[30];
strcpy(cesta,Edit10->Text.c_str());
flag=Save(cesta,&Mapa);
if(flag!=0)
        {
        ShowMessage("Chyba pri ukladani do souboru");
        }
else
        {
        ShowMessage("Mapa byla ulozena do souboru: "+AnsiString(cesta));
        }
Saved=true;
}
//---------------------------------------------------------------------------




void __fastcall TForm1::Button3Click(TObject *Sender)
{
if(Mapa.count>0)
{
int i=StrToInt(ComboBox2->Text)-1;
Mapa.node[i].ID=StrToInt(ComboBox1->Text);
strcpy(Mapa.node[i].name,ComboBox3->Text.c_str());
int flag=0;

int j=GetOrder(&Mapa,StrToInt(Edit3->Text))-1;
if(j==-1 && StrToInt(Edit3->Text)!=-1)
        {
        ShowMessage("Krizovatka "+Edit3->Text+" neexistuje");
        flag=1;
        }
else
        {
        if(StrToInt(Edit2->Text)>=0 && StrToInt(Edit2->Text)<32000)
                {
                Mapa.edge[i][j]=StrToInt(Edit2->Text);
                Mapa.edge[j][i]=StrToInt(Edit2->Text);
                }
        else if(StrToInt(Edit3->Text)!=-1)
                {
                Mapa.edge[i][j]=-1;
                }
        Mapa.node[i].neighbour[0]=StrToInt(Edit3->Text);
        }

j=GetOrder(&Mapa,StrToInt(Edit4->Text))-1;
if(j==-1 && StrToInt(Edit4->Text)!=-1)
        {
        ShowMessage("Krizovatka "+Edit4->Text+" neexistuje");
        flag=1;
        }
else
        {
        if(StrToInt(Edit7->Text)>=0 && StrToInt(Edit7->Text)<32000)
                {
                Mapa.edge[i][j]=StrToInt(Edit7->Text);
                Mapa.edge[j][i]=StrToInt(Edit7->Text);
                }
        else if(StrToInt(Edit4->Text)!=-1)
                {
                Mapa.edge[i][j]=-1;
                }
        Mapa.node[i].neighbour[1]=StrToInt(Edit4->Text);
        }

j=GetOrder(&Mapa,StrToInt(Edit5->Text))-1;
if(j==-1 && StrToInt(Edit5->Text)!=-1)
        {
        ShowMessage("Krizovatka "+Edit5->Text+" neexistuje");
        flag=1;
        }
else
        {
        if(StrToInt(Edit8->Text)>=0 && StrToInt(Edit8->Text)<32000)
                {
                Mapa.edge[i][j]=StrToInt(Edit8->Text);
                Mapa.edge[j][i]=StrToInt(Edit8->Text);
                }
        else if(StrToInt(Edit5->Text)!=-1)
                {
                Mapa.edge[i][j]=-1;
                }
        Mapa.node[i].neighbour[2]=StrToInt(Edit5->Text);
        }

j=GetOrder(&Mapa,StrToInt(Edit6->Text))-1;
if(j==-1 && StrToInt(Edit6->Text)!=-1)
        {
        ShowMessage("Krizovatka "+Edit6->Text+" neexistuje");
        flag=1;
        }
else
        {
        if(StrToInt(Edit9->Text)>=0 && StrToInt(Edit9->Text)<32000)
                {
                Mapa.edge[i][j]=StrToInt(Edit9->Text);
                Mapa.edge[j][i]=StrToInt(Edit9->Text);
                }
        else if(StrToInt(Edit6->Text)!=-1)
                {
                Mapa.edge[i][j]=-1;
                }
        Mapa.node[i].neighbour[3]=StrToInt(Edit6->Text);
        }


if(!flag)
        {
        Mapa.node[i].terminal=CheckBox1->Checked;
        ShowMessage("Krizovatka cislo "+AnsiString(i+1)+" byla zmenena");
        refresh(Sender);
        ComboBox2Select(Sender);
        Saved=false;
        }
}
else
        {
        ShowMessage("Neexistuje zadna krizovatka!");
        }
Button6Click(Sender);       //prime volani Redraw z nejakeho zahadneho duvodu zlobi

}
//---------------------------------------------------------------------------


void __fastcall TForm1::ComboBox1Select(TObject *Sender)
{
int i=0;
i=GetOrder(&Mapa,StrToInt(ComboBox1->Text))-1;
//while(StrToInt(ComboBox1->Text)!=Mapa.node[i].ID)i++;
ComboBox2->Text=Mapa.node[i].order;
ComboBox3->Text=Mapa.node[i].name;
Edit3->Text=Mapa.node[i].neighbour[0];
Edit4->Text=Mapa.node[i].neighbour[1];
Edit5->Text=Mapa.node[i].neighbour[2];
Edit6->Text=Mapa.node[i].neighbour[3];
Edit2->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[0])-1];
Edit7->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[1])-1];
Edit8->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[2])-1];
Edit9->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[3])-1];
CheckBox1->Checked=Mapa.node[i].terminal;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button4Click(TObject *Sender)
{
if(Mapa.count<100)
{
int i=Mapa.count++;
//ShowMessage(IntToStr(i));
Mapa.node[i].ID=0;
Mapa.node[i].order=i+1;
strcpy(Mapa.node[i].name,"Nova_Krizovatka");
Mapa.node[i].neighbour[0]=-1;
Mapa.node[i].neighbour[1]=-1;
Mapa.node[i].neighbour[2]=-1;
Mapa.node[i].neighbour[3]=-1;
Mapa.node[i].terminal=false;
for(int j=0;j<Mapa.count;j++)
        {
        Mapa.edge[i][j]=-1;
        Mapa.edge[j][i]=-1;
        };
ShowMessage("Byla pridana krizovatka");
refresh(Sender);

ComboBox2->Text=i+1;                          //toto je tam enom aby sa nastavily hodnoty po nacteni
ComboBox2Select(Sender);                    //na prvni krizovatku
Saved=false;
}
else
        {
        ShowMessage("Nelze pridat dalsi krizovatku");
        }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ComboBox2Select(TObject *Sender)
{
int i=0;
while(StrToInt(ComboBox2->Text)!=Mapa.node[i].order)i++;
ComboBox1->Text=Mapa.node[i].ID;
ComboBox3->Text=Mapa.node[i].name;
Edit3->Text=Mapa.node[i].neighbour[0];
Edit4->Text=Mapa.node[i].neighbour[1];
Edit5->Text=Mapa.node[i].neighbour[2];
Edit6->Text=Mapa.node[i].neighbour[3];
Edit2->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[0])-1];
Edit7->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[1])-1];
Edit8->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[2])-1];
Edit9->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[3])-1];
CheckBox1->Checked=Mapa.node[i].terminal;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ComboBox3Select(TObject *Sender)
{
int i=0;
while(ComboBox3->Text!=Mapa.node[i].name)i++;
ComboBox2->Text=Mapa.node[i].order;
ComboBox1->Text=Mapa.node[i].ID;
Edit3->Text=Mapa.node[i].neighbour[0];
Edit4->Text=Mapa.node[i].neighbour[1];
Edit5->Text=Mapa.node[i].neighbour[2];
Edit6->Text=Mapa.node[i].neighbour[3];
Edit2->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[0])-1];
Edit7->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[1])-1];
Edit8->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[2])-1];
Edit9->Text=Mapa.edge[i][GetOrder(&Mapa,Mapa.node[i].neighbour[3])-1];


CheckBox1->Checked=Mapa.node[i].terminal;
}
//---------------------------------------------------------------------------



void __fastcall TForm1::Button5Click(TObject *Sender)
{
if(Mapa.count>1)
{
if(Application->MessageBox("Opravdu chcete smazat krizovatku?","Dotaz",MB_YESNO)==6)
        {
        int x=StrToInt(ComboBox2->Text)-1;
        for(int i=0;i<Mapa.count;i++)
                {
                for(int j=0;j<3;j++)
                        {
                        if(Mapa.node[i].neighbour[j]==Mapa.node[x].ID)
                                {
                                Mapa.node[i].neighbour[j]=-1;
                                }
                        }
                }
        DeleteNode(&Mapa,x);
        ShowMessage("Krizovatka byla smazana");
        refresh(Sender);
        if(x==0)
                {
                x=1;
                }
        ComboBox2->Text=x;
        ComboBox2Select(Sender);

        };
        Saved=false;
}
else
        {
        ShowMessage("Nelze smazat posledni krizovatku");
        }
Button6Click(Sender);       //prime volani Redraw z nejakeho zahadneho duvodu zlobi

}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormCreate(TObject *Sender)
{
Form1->Caption="Editor map";
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose)
{
if(!Saved)      if(Application -> MessageBox("Mapa nebyla ulozena! Prejete si skoncit?", "Dotaz",MB_YESNO | MB_ICONQUESTION)== mrYes)
                     CanClose = true;
                else CanClose = false;

}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button6Click(TObject *Sender)
{
Redraw(&Mapa);
}
//---------------------------------------------------------------------------


