#language = "JScript"
#tooltip="IP Address Information",1033,"IPアドレス情報",1041,"IP Address Information",1029,"IP-Adressinformationen",1031,"IP Address Information",1036,"Información de la dirección IP",3082,"Información de la dirección IP",2058,"Informazioni sull'indirizzo IP",1040,"IP 주소 정보",1042,"IP Adres informatie",1043,"IP 地址信息",2052,"IP 地址信息",1028
// Do not edit this file.  If you want to edit the file, please copy it into another folder.
// This file will be replaced with a newer version every time EmEditor is upgraded.
//

// In order to inspect the name of the country where the IP address is registered, 
// download "GeoLite2 Country: CSV Format" at:
// https://dev.maxmind.com/
// unzip and place the extracted CSV files in:
// If an EmEditor installer was used to install EmEditor (using the Registry):
//     C:\ProgramData\Emurasoft\EmEditor\data folder
// If a portable version of EmEditor is used (using INI files):
//     "data" subfolder of the EmEditor, i.e. X:\...\EmEditor\data
// It is recommended to download and update the above file periodically since the 
// database is updated frequently.

function ShowErrorTip( sFolder, sCountryFile )
{
		sText = "";
		switch( editor.LangID )	{
		case 1041:  // Japanese
			sText = '国名を表示するには、<a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a> をダウンロードして、解凍された GeoLite2-Country-Blocks-IPv4.csv と GeoLite2-Country-Locations-en.csv を次のフォルダに置いてください:';
			break;

		case 1029:  // Czech
			sText = 'Aby bylo možné zobrazit název země, stáhněte si databázi <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>, extrahujte ji a překopírujte soubor GeoLite2-Country-Blocks-IPv4.csv/GeoLite2-Country-Locations-en.csv do složky:';
			break;

		case 1031:  // German
			sText = 'Um den Ländernamen anzuzeigen, laden Sie die <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a> herunter, entpacken und legen Sie GeoLite2-Country-Blocks-IPv4.csv/GeoLite2-Country-Locations-en.csv in den Ordner:';
			break;

		case 1036:  // French
			break;
	
		case 3082:  // Spanish
		case 2058:  // Spanish
			sText = 'Para mostrar el nombre del país, descargue <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>, descomprima y coloque GeoLite2-Country-Blocks-IPv4.csv/GeoLite2-Country-Locations-en.csv en la carpeta:';
			break;

		case 1040:  // Italian
			sText = 'Per visualizzare il nome del paese, scarica il <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>, decomprimilo, e posiziona il file GeoLite2-Country-Blocks-IPv4.csv/GeoLite2-Country-Locations-en.csv nella cartella:';
			break;

		case 1042:  // Korean
			sText = '가명 표시를 위해, <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a> 다운로드하고, 압축 해제 후, 폴더 내 GeoLite2-Country-Blocks-IPv4.csv/GeoLite2-Country-Locations-en.csv를 여십시오:';
			break;

		case 1043:  // Dutch
			sText = 'Om de landsnaam weer te geven, download de <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>, unzip, en plaats GeoLite2-Country-Blocks-IPv4.csv/GeoLite2-Country-Locations-en.csv in de map:';
			break;

		case 2052:  // Simplified Chinese
			sText = '要显示国家名，请下载 <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>，请解压缩，并把 GeoLite2-Country-Blocks-IPv4.csv 和 GeoLite2-Country-Locations-en.csv 放在文件夹中：';
			break;

		case 1028:  // Traditional Chinese
			sText = '要顯示國家名，請下載 <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>，請解壓縮，并把 GeoLite2-Country-Blocks-IPv4.csv 和 GeoLite2-Country-Locations-en.csv 放在資料夾中：';
			break;
		}
	
		if( sText.length == 0 ) {
			sText = 'In order to display the country name, download <a href="https://dev.maxmind.com/">GeoLite2 Country: CSV Format</a>, unzip, and place GeoLite2-Country-Blocks-IPv4.csv and GeoLite2-Country-Locations-en.csv in the folder:';
		}
		ShowTip( sText + ' ' + sFolder, nTipFlag );
		Quit();
}

//// main code starts here
fso = new ActiveXObject("Scripting.FileSystemObject");
nTipFlag = eeShowTipActiveString;
if( !document )  Quit();
sIP = document.ActiveString;    // get Active String
if( sIP.length == 0 ) {         // if Active String is not found, try the selected string
	sIP = document.selection.Text;  
	nTipFlag = eeShowTipCurrentCaret;
}
if( sIP.length == 0 )  Quit();  // no string to inspect, quit the macro

if( sIP.indexOf( ":" ) != -1 )  { // IPv6 not supported, quit the macro
	ShowTip( "IPv6 not supported", nTipFlag );
	Quit();  
}
longIP = ip2long( sIP );
if( longIP < 0 || longIP >= 256 * 256 * 256 * 256 ) {
	Quit();  // IP address is invalid, quit the macro
}

// "data" folder will be at:
// portable version (use INI):  X:\...\EmEditor\data\
// installer version (use REG): C:\ProgramData\Emurasoft\EmEditor\data\
sFolder = editor.FullName;   // EmEditor.exe full path
iBackslash = sFolder.lastIndexOf( "\\" );
sFolder = sFolder.substr( 0, iBackslash + 1 );
if( !fso.FileExists( sFolder + "eeUseIni.ini" ) ) {   // NOT EmEditor portable version
	wshShell = new ActiveXObject("WScript.Shell");
	sFolder = wshShell.ExpandEnvironmentStrings( "%PROGRAMDATA%\\Emurasoft\\EmEditor\\" );
}
sFolder += "data\\";
sPath = sFolder + "GeoLite2-Country-Blocks-IPv4.csv";  // get the full path for the first CSV file
if( !fso.FileExists( sPath ) ) {
	ShowErrorTip( sFolder );
}
try {
	f = fso.OpenTextFile(sPath, 1);        // try opening the CSV file
}
catch(err) {                  // Error opening the file. Possibly the file is not found
	Quit();
}
sText = f.ReadAll();          // read all the contents of the file
f.Close();

sLines = sText.split("\n");   // split the file with the newline character.
nCount = sLines.length;
iTop = 1;    // exclude the first heading line ("network")
iBottom = nCount - 1;
sCols = sLines[iBottom].split(",");
if( sCols.length == 1 ) {    // the last line might not contain any data
	iBottom--;
}
sCols = sLines[iBottom].split(",");
if( sCols.length == 1 ) {    // invalid data
	Quit();
}

// binary search
do {
	nDiff = iBottom - iTop;
	iMid = iTop + Math.floor(nDiff / 2);
	n = sLines[iMid].search( "," );
	if( n == -1 ) {  // invalid data
		Quit();
	}
    cidr = sLines[iMid].substr( 0, n ).split('/');
    nStart = ip2long(cidr[0]);
	if( longIP < nStart ) {
		iBottom = iMid;
	}
	else {
		nEnd = Math.pow(2, 32 - cidr[1]) + nStart - 1;
		if( longIP > nEnd ) {
			iTop = iMid + 1;
		}
		else {
			break; // found
		}
	}
} while( iTop < iBottom )

sCols = sLines[iMid].split(",");   // split a line into cell strings

sCols = sLines[iMid].split(",");
cidr = sCols[0].split('/');
nStart = ip2long(cidr[0]);
nEnd = Math.pow(2, 32 - cidr[1]) + nStart - 1;
if( longIP >= nStart && longIP <= nEnd ) {  // found
	geoname_id = sCols[1];
	sPath = sFolder + "GeoLite2-Country-Locations-en.csv";  // get the full path for the second CSV file (we use this English file because other language files need to be decoded from UTF-8, but Scripting.FileSystemObject doesn't support UTF-8).

	try {
		f = fso.OpenTextFile(sPath, 1);        // try opening the second CSV file
	}
	catch(err) {                  // Error opening the file. Possibly the file is not found
		ShowErrorTip( sFolder );
	}
	sText = f.ReadAll();          // read all the contents of the file
	f.Close();

	sLines = sText.split("\n");   // split the file with the newline character.
	nCount = sLines.length;
	iTop = 1;  // exclude the first line heading
	iBottom = nCount - 1;
	sCols = sLines[iBottom].split(",");
	if( sCols.length == 1 ) {    // the last line might not contain any data
		iBottom--;
	}
	sCols = sLines[iBottom].split(",");
	if( sCols.length == 1 ) {    // invalid data
		Quit();
	}

	// binary search
	do {
		nDiff = iBottom - iTop;
		iMid = iTop + Math.floor(nDiff / 2);
		n = sLines[iMid].search( "," );
		if( n == -1 ) {  // invalid data
			Quit();
		}
	    s = sLines[iMid].substr( 0, n );
	    if( geoname_id < s ) {
			iBottom = iMid;
		}
		else {
			if( geoname_id > s ) {
				iTop = iMid + 1;
			}
			else {
				break; // found
			}
		}
	} while( iTop < iBottom )
	
	sCols = sLines[iMid].split(",");
	sName = sCols[5];      // the 6th column contains the country name
	if( sName.length >= 2 ){
		if( sName[0] == '"' ) {
			sName = sName.substr( 1, sName.length - 2 );   // remove double quotation marks.
		}
	}
	ShowTip( sName, nTipFlag );
}
else {
	ShowTip( "Not found in database", nTipFlag );
}

// converts an IP address to the long value.
function ip2long( sIP )
{
	sNums = sIP.split(".");
	if( sNums.length != 4 )  return -1;
	l = parseInt( sNums[0] ) * 256 * 256 * 256 + parseInt( sNums[1] ) * 256 * 256 + parseInt( sNums[2] ) * 256 + parseInt( sNums[3] );
	return l;
}
