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

#include <vcl.h>
#include <math.h>
#include <stdio.h>
#include <cmath>
#include <inifiles.hpp>
#pragma hdrstop

#include "FrmMainF.h"
#include "DownloaderF.h"
#include "ThrDownloaderF.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "IdBaseComponent"
#pragma link "IdComponent"
#pragma link "IdHTTP"
#pragma link "IdTCPClient"
#pragma link "IdTCPConnection"
#pragma resource "*.dfm"
TForm1 *Form1;
extern long g_CompletedJobCnt;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    reMsg->Lines->Clear();

    Initialize();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Initialize()
{
    String sAppDir = ExtractFilePath(Application->ExeName);
    ChDir(sAppDir);

    TIniFile *pIniFile = NULL;
    String sIniFile = ChangeFileExt(ExtractFileName(Application->ExeName), ".ini");
    String sCfgFile = sAppDir + sIniFile;

    try
    {
        String sTmp;

        pIniFile = new TIniFile(sCfgFile);

        String sTitle = pIniFile->ReadString("APPLICATION", "TITLE", "�������� ���� �ٿ�ε�");
        Caption = sTitle;

        int nThreads = pIniFile->ReadInteger("MAP", "THREADS", 200);
        if (nThreads <  10) nThreads = 10;
        if (nThreads > 200) nThreads = 200;
        EdThreads->Text = String(nThreads);

        FDownloadUrl = pIniFile->ReadString("MAP", "URL",  "http://xdworld.vworld.kr:8080/2d/Base/service/%d/%d/%d.png").Trim();
        FSaveDir = pIniFile->ReadString("MAP", "SAVE", "C:\MAPDATA\VWorld\Base").Trim();
        EdURL->Text = FDownloadUrl;
        EdDir->Text = FSaveDir + "\\Base";

        EdLat1->Text = pIniFile->ReadString("MAP", "TOP",    "36.9784").Trim();
        EdLat2->Text = pIniFile->ReadString("MAP", "BOTTOM", "35.0188").Trim();
        EdLon1->Text = pIniFile->ReadString("MAP", "LEFT",   "127.3535").Trim();
        EdLon2->Text = pIniFile->ReadString("MAP", "RIGHT",  "131.6656").Trim();

    }
    __finally
    {
        if (pIniFile) delete pIniFile;
        pIniFile = NULL;
    }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    double Lon  = Edit1->Text.Trim().ToDouble();
    double Lat  = Edit2->Text.Trim().ToDouble();
    int    Zoom = Edit3->Text.Trim().ToIntDef(12);

    String sLog;
    sLog.printf(L"Lon: %.7f, Lat: %.7f, Zoom: %d", Lon, Lat, Zoom);
    reMsg->Lines->Add(sLog);

    sLog = getTileURL(Lon, Lat, Zoom);
    reMsg->Lines->Add(sLog);
}
//---------------------------------------------------------------------------
double asinh(double x)
{
    return log(x + sqrt(x*x + 1.0));
}
//---------------------------------------------------------------------------
#include <string.h>
char *strrstr( char *str, char *search )
{
    int len1 = strlen(str);
    int len2 = strlen(search);
    int pos = len1 - len2;
    char *result = NULL;


    // ���� �ϳ��� ���� ���ų� ã�� ���ڿ����̰� �� ũ�� ������.
    if( len1 == 0 || len2 == 0 || len1 < len2 )
        return NULL;


    while( pos >= 0 )
    {
         if( strncmp( str + pos, search, len2 ) == 0 )
        {
             result = str + pos;
             break;
         }
         pos--;
     }
     return result;
}

void __fastcall TForm1::BtnDownloadClick(TObject *Sender)
{
    double Lon1  = EdLon1->Text.Trim().ToDouble();
    double Lat1  = EdLat1->Text.Trim().ToDouble();
    double Lon2  = EdLon2->Text.Trim().ToDouble();
    double Lat2  = EdLat2->Text.Trim().ToDouble();
    int    Zoom  = CbZoom->Text.Trim().ToIntDef(12);

    String sUrl = EdURL->Text.Trim();
    String tmpUrl = sUrl.UpperCase();
    bool isDaum = tmpUrl.Pos("DAUM") ? true : false;
    if (isDaum) {
        switch(Zoom) {
        case 19: Zoom =   1; break;
        case 18: Zoom =   2; break;
        case 17: Zoom =   3; break;
        case 16: Zoom =   4; break;
        case 15: Zoom =   5; break;
        case 14: Zoom =   6; break;
        case 13: Zoom =   7; break;
        case 12: Zoom =   8; break;
        case 11: Zoom =   9; break;
        case 10: Zoom =  10; break;
        case  9: Zoom =  11; break;
        case  8: Zoom =  12; break;
        case  7: Zoom =  13; break;
        case  6: Zoom =  14; break;
        }
    }

    DownloadMap(Lon1, Lat1, Lon2, Lat2, Zoom);
}
void __fastcall TForm1::DownloadMap(double Lon1, double Lat1, double Lon2, double Lat2, int Zoom)
{
#if 0
getXYZ: function(bounds) {
        var res = this.getServerResolution();
        var x = Math.round((bounds.left - this.maxExtent.left) /
            (res * this.tileSize.w));
        var y = Math.round((bounds.bottom - this.maxExtent.bottom) /
            (res * this.tileSize.h));
        var z = 14 - this.getServerZoom();

        if (this.wrapDateLine) {
            var limit = Math.pow(2, z);
            x = ((x % limit) + limit) % limit;
        }

        return {'x': x, 'y': y, 'z': z};
    },
#endif

#define min(x,y) (x)>(y)?(y):(x)
#define max(x,y) (x)>(y)?(x):(y)

    String sUrl = EdURL->Text.Trim();
    String sPath;
    String sDir = EdDir->Text.Trim() + "\\";
    ForceDirectories(sDir.c_str());


    int xmin = (int)(min(Lon1, Lon2)*pow(2, Zoom)/360.0+pow(2.0, Zoom)/2.0);
    int xmax = (int)(max(Lon1, Lon2)*pow(2, Zoom)/360.0+pow(2.0, Zoom)/2.0)+1;

#if 0
    //�̰� �̻��ϰ� �� ����
    double lat = asinh(tan(min(Lat1, Lat2)/360.0*2.0*M_PI));
    int   ymax = (int)(pow(2.0, Zoom)/2.0-lat*pow(2.0, Zoom)/(2.0*M_PI))+1;
           lat = asinh(tan(max(Lat1, Lat2)/360.0*2.0*M_PI));
    int   ymin = (int)(pow(2.0, Zoom)/2.0-lat*pow(2.0, Zoom)/(2.0*M_PI));
#else
    double dymin = (1.0 - log(tan(Lat1 * M_PI/180.0) + 1.0 / cos(Lat1 * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, Zoom);
    double dymax = (1.0 - log(tan(Lat2 * M_PI/180.0) + 1.0 / cos(Lat2 * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, Zoom);
    int    ymin = min(dymin, dymax);
    int    ymax = max(dymin, dymax);
    ymax++;
#endif

    reMsg->Lines->Clear();

    String sLog;
    //sLog.printf(L"xmin: %d, xmax: %d, ymin: %d, ymax: %d, latMin: %.7f, latMax: %.7f", xmin, xmax, (int)ymin, (int)ymax, latMin, latMax);
    sLog.printf(L"xmin: %d, xmax: %d, ymin: %d, ymax: %d", xmin, xmax, ymin, ymax);
    reMsg->Lines->Add(sLog);


    sPath.printf(L"%s%d\\", sDir.c_str(), Zoom);
    ForceDirectories(sPath.c_str());

    g_CompletedJobCnt = 0;
    FSuccessCnt  = 0;
    FThreadCnt   = (xmax-xmin)+1;
    FJobCnt      = ((xmax-xmin)+1) * ((ymax-ymin)+1);
    FTotalJobCnt = FJobCnt;

    ProgressBar1->Visible = true;
    ProgressBar1->Max = FJobCnt;
    ProgressBar1->Min = 0;
    ProgressBar1->Position = 0;

int MAX_THREADS = EdThreads->Text.Trim().ToIntDef(100);

    for (int ii = xmin; ii <= xmax; ii++)
    {
        sPath.printf(L"%s%d\\%d\\", sDir.c_str(), Zoom, ii);
        ForceDirectories(sPath.c_str());
    }

    char szTemp[512];
    memset(szTemp, 0x00, sizeof(szTemp));

    String sExt;
    char *pExt = strrstr(AnsiString(sUrl).c_str(), ".");
    pExt++;
    sExt.printf(L"%s", pExt);
    sExt = String(pExt);

#if 1
    sPath.printf(L"First Thread: %d", FThreadCnt);
    reMsg->Lines->Add(sPath);

    int nMaxJob = 0;
    if (FThreadCnt > MAX_THREADS)
    {
        nMaxJob = FThreadCnt / (MAX_THREADS);
    }

    int nJob = 0;
    FThreadCnt = 0;
    for (int ii = xmin; ii <= xmax; )
    {
        FThreadCnt++;
        nJob = ii + nMaxJob;
        if (nJob > xmax) nJob = xmax;

        sPath.printf(L"%s%d\\", sDir.c_str(), Zoom);
        ForceDirectories(sPath.c_str());

        TThrDownloader *pDownloader = new TThrDownloader(true, ChkDelOldMap->Checked);
        if (pDownloader)
        {
            pDownloader->FZoom    = Zoom;
            pDownloader->FXMin    = ii;
            pDownloader->FXMax    = nJob;
            pDownloader->FYMin    = ymin;
            pDownloader->FYMax    = ymax;
            pDownloader->FPath    = sPath;
            pDownloader->FFileExt = sExt;
            pDownloader->FURL     = sUrl;

            pDownloader->Resume();
        }

        ii += nMaxJob;
        ii++;
    }
    sPath.printf(L"Last Thread: %d", FThreadCnt);
    reMsg->Lines->Add(sPath);
    sLog.printf(L"xmin: %d, xmax: %d, ymin: %d, ymax: %d", xmin, xmax, ymin, ymax);
    reMsg->Lines->Add(sLog);
#endif

#if 0
    for (int ii = xmin; ii <= xmax; ii++)
    {
        sPath.printf(L"%s%d\\", sDir.c_str(), Zoom);
        ForceDirectories(sPath.c_str());

        TThrDownloader *pDownloader = new TThrDownloader(true);
        if (pDownloader)
        {
            pDownloader->FZoom    = Zoom;
            pDownloader->FXMin    = ii;
            pDownloader->FXMax    = ii+MAX_THREADS;
            pDownloader->FYMin    = ymin;
            pDownloader->FYMax    = ymax;
            pDownloader->FPath    = sPath;
            pDownloader->FFileExt = "png";
            pDownloader->FURL     = sUrl;

            pDownloader->Resume();
        }
    }
#endif
    BtnDownload->Enabled = false;
    Timer1->Enabled = true;
    Refresh();
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ApplicationEvents2Message(tagMSG &Msg, bool &Handled)
{
    int nThreadX = (int)Msg.wParam;
    int nJobCnt  = (int)Msg.lParam;

    String sLog;
    if (Msg.message == WM_DOWNLOAD_COMPLETE)
    {
        sLog.printf(L"%d download completed. %d success.", nThreadX, nJobCnt);
        reMsg->Lines->Add(sLog);

        FSuccessCnt += nJobCnt;
        FThreadCnt--;
        if (FThreadCnt == 0)
        {
            reMsg->Lines->Add("Download Completed.................");
            BtnDownload->Enabled = true;
            ProgressBar1->Visible = false;
        }
    }
    else
    if (Msg.message == WM_DOWNLOAD_JOB)
    {
        //sLog.printf(L"%d download. %d EA.", nThreadX, nJobCnt);
        //reMsg->Lines->Add(sLog);

        FJobCnt -= nJobCnt;
    }
    else
    if (Msg.message == WM_DOWNLOAD_START)
    {
        //sLog.printf(L"%d download start.", nThreadX);
        //reMsg->Lines->Add(sLog);
    }

    if (Msg.message == WM_DOWNLOAD_COMPLETE ||
        Msg.message == WM_DOWNLOAD_JOB ||
        Msg.message == WM_DOWNLOAD_START)
    {
        ProgressBar1->Position = ProgressBar1->Position + 1;
        Application->ProcessMessages();
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    Timer1->Enabled = false;
    ProgressBar1->Position = g_CompletedJobCnt;
    Application->ProcessMessages();
    if (BtnDownload->Enabled == false)
    {
        if (FThreadCnt == 0 || g_CompletedJobCnt >= FTotalJobCnt)
        {
            reMsg->Lines->Add("Download Completed.................");
            BtnDownload->Enabled = true;
            ProgressBar1->Visible = false;
            Application->ProcessMessages();
            Timer1->Enabled = false;
        }
        else
        {
            Timer1->Enabled = true;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BtnDownloadAllClick(TObject *Sender)
{
    if (BtnDownload->Enabled == false) return;

    double Lon1  = 114.52724705906037;
    double Lat1  = 44.66724476853472;
    double Lon2  = 142.41054557562398;
    double Lat2  = 30.95707087688254;

    int    Zoom  = CbZoom->Text.Trim().ToIntDef(12);
    String sUrl = EdURL->Text.Trim();
    String tmpUrl = sUrl.UpperCase();
    bool isDaum = tmpUrl.Pos("DAUM") ? true : false;
    if (isDaum) {
        switch(Zoom) {
        case 19: Zoom =   1; break;
        case 18: Zoom =   2; break;
        case 17: Zoom =   3; break;
        case 16: Zoom =   4; break;
        case 15: Zoom =   5; break;
        case 14: Zoom =   6; break;
        case 13: Zoom =   7; break;
        case 12: Zoom =   8; break;
        case 11: Zoom =   9; break;
        case 10: Zoom =  10; break;
        case  9: Zoom =  11; break;
        case  8: Zoom =  12; break;
        case  7: Zoom =  13; break;
        case  6: Zoom =  14; break;
        }
        if (Zoom < 7 || Zoom > 14) return;
        if (Zoom <= 9) {
            Lon1  = 121.6024417969118;
            Lat1  = 38.7011141762058;
            Lon2  = 131.62197223312378;
            Lat2  = 32.63770774488186;
        }
    }
    else {
        if (Zoom < 6 || Zoom > 13) return;
        if (Zoom >= 11) {
            Lon1  = 121.6024417969118;
            Lat1  = 38.7011141762058;
            Lon2  = 131.62197223312378;
            Lat2  = 32.63770774488186;
        }
    }


    DownloadMap(Lon1, Lat1, Lon2, Lat2, Zoom);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::CboTypeClick(TObject *Sender)
{
    String type = CboType->Text.Trim();
    if (type == "Base") {
        EdURL->Text = "http://xdworld.vworld.kr:8080/2d/Base/service/%d/%d/%d.png";
        EdDir->Text = FSaveDir + "\\Base";
    }
    else if (type == "Hybrid") {
        EdURL->Text = "http://xdworld.vworld.kr:8080/2d/Hybrid/service/%d/%d/%d.png";
        EdDir->Text = FSaveDir + "\\Hybrid";
    }
    else if (type == "Satellite") {
        EdURL->Text = "http://xdworld.vworld.kr:8080/2d/Satellite/service/%d/%d/%d.jpeg";
        EdDir->Text = FSaveDir + "\\Satellite";
    }
}
//---------------------------------------------------------------------------

