
var airFolder = ""
//Папка с файлом air.ini. Напрмер для DGEN3 может быть так:
//var airFolder = "E:\\il2fb\\#DGEN\\00_INI\\com\\maddox\\il2\\objects\\"

var weapFolder = ""
//Папка с файлом weapons.properties. Например для DGEN3 может быть так:
//var weapFolder = "E:\\il2fb\\#DGEN\\00_INI\\i18n\\" 


var TextEditor="notepad"
var dWeapons = new Array;


var dAirini = new ActiveXObject("Scripting.Dictionary");


var ForReading = 1
//var TextEditor="C:\\Progra~1\\AkelPad\\AkelPad.exe"

var skinList = new Array;	//списко всех файлов из каталога \\PaintSchemes\\Skins

var nstr, section, misfile, nerr;	
nstr=0;

var fso = new ActiveXObject("Scripting.FileSystemObject");
var main_folder_path;	//каталог кампании
var main_folder;		//объект-каталог кампании
var OutFile, fo;		//файл отчета

var	WS = WScript.CreateObject("WScript.Shell"),
	Directory = WS.CurrentDirectory				//текущий каталог

//================================================================
//для удобстава обработки строк:
String.prototype.trimRight=function() 		// убирает все пробелы в конце строки
{
  return this.replace(/\s+$/,'');
}

String.prototype.trimLeft=function() 		// убирает все пробелы в начале строки
{
  return this.replace(/^\s+/,'');
}

String.prototype.trim=function()	 		// убирает все пробелы в начале и в конце строки
{
  return this.trimRight().trimLeft();
}
//================================================================


main()

function main() {
	var args = WScript.Arguments

	main_folder_path=""
	
	if (args.length == 0)
		main_folder_path=Directory					//параметра нет - берем текущий каталог
	else
		main_folder_path = args.item(0)
	/*
		for (var i = 0; i < args.length; i++) {
			var arg = args.item(i);
			main_folder_path += arg+" "
		}
		*/

		
	
	if (main_folder_path.length-1 == main_folder_path.lastIndexOf("\\")){
			main_folder_path=main_folder_path.substr(0,main_folder_path.length-1)
	}
	//main_folder_path теперь без завершающей обратной косой
	campName=main_folder_path.substr(main_folder_path.lastIndexOf("\\")+1)
	


	//Справка
	if (main_folder_path.charAt(0)=="?") {
		WScript.Echo("Проверка кампании.\nИспользование:\n	checkMis.js [Каталог] [Файл] \nКаталог - каталог кампании, по умолчанию - текущий.\nФайл - файл результата, по умолчанию - checkMis.txt")
		return
	}	

	//OutFile - имя файл результата 
	OutFile = main_folder_path+"\\checkMis.txt"
	
	//можно каталог кампании задать вручную здесь:
	//	main_folder_path="E:\\TEstJS\\Missions\\CAMPAIGN\\ru\\k+b"
	//можно задать файл результата проверок
	//	OutFile="E:\\TEstJS\\Missions\\CAMPAIGN\\ru\\k+b\\checkMis.txt"

//WScript.Echo(OutFile);
	
	fo = fso.CreateTextFile(OutFile, true, false);
	
//	WScript.Echo(main_folder_path);
	
	main_folder=fso.GetFolder(main_folder_path);
	
	var pth=Directory.slice(0,Directory.indexOf("Missions"))+"PaintSchemes\\Skins";
	
	if (fso.FolderExists(pth)) {
		skin_folder=fso.GetFolder(pth);
		DirWithSubFolders(skin_folder);		//обход PaintSchemes\Skins
	}
	
	readWeapons()
	readAirini()
	
	CheckCampaignFolder(main_folder);	//проверка
	
	fo.Close()

	
	showFile(OutFile)	//запустить блокнот для просмотра результата
}


function readAirini(){
	
	if (airFolder.length == 0)
		airFolder = Directory.slice(0,Directory.indexOf("Missions"))+"#DGEN\\00_INI\\com\\maddox\\il2\\objects\\"
	
	if (!fso.FileExists(airFolder+"air.ini"))
		return
	
	var f = fso.OpenTextFile(airFolder+"air.ini", ForReading, false)
	var s = ""
	while (!f.AtEndOfStream){
//UT-1B             air.UT_1B 1                           NOINFO  r01   SUMMER
		s = f.ReadLine().trim()
		if (s.length == 0)
			continue
		if (s.substr(0,1) == '[')
			continue
		if (s.substr(0,1) == '/')
			continue
		if (s.substr(0,1) == '-')
			continue
		
		s=s.replace(/\s+/g,";")
//	WScript.Echo(s)
		scl=s.indexOf(";")
		weapName=s.substr(0,scl)

		s=s.substr(scl+1)
		scl=s.indexOf(";")
		airName=s.substr(0,scl)
		if (!dAirini.Exists(airName))
			dAirini.Add(airName,weapName)
//		WScript.Echo("*",airName,dAirini.Item(airName))
	}
	f.Close()

		
}


function readWeapons(){

	if (weapFolder.length == 0)
		weapFolder=Directory.slice(0,Directory.indexOf("Missions"))+"#DGEN\\00_INI\\i18n\\" 

	
	if (!fso.FileExists(weapFolder+"weapons.properties")){
//		WScript.Echo("Not exists "+i18folder+"weapons.properties")
		return;	//словарь вооружений пуст = не проверть вооружение
	
	}
	
	
	var f = fso.OpenTextFile(weapFolder+"weapons.properties", ForReading, false)
	var s = ""
	while (!f.AtEndOfStream){
		s = f.ReadLine().trim()
		if (s.length == 0)
			continue
		if (s.substr(0,1) == '#')
			continue
		s=s.replace(/\s+/g,';')
		scl=s.indexOf(";") 
		dWeapons[dWeapons.length]=s.substr(0,scl);
//		WScript.Echo("куфв цуфз:"+s.substr(0,scl)+":")
		
/*		
A-20G.default               Default
A-20G.40xParaF              40xParafrag Bombs
A-20G.2x20FragClusters      2x20 Fragmentation Bombs
A-20G.2x100                 2x100 lb. Bombs
*/
	}
	f.Close()
}

function hasWeapons(pName,wName){
	if (dWeapons.length == 0)
		return true
	
	if (wName == "default")
		return true
	
	airName=dAirini.Item("air."+pName)
	if (airName == undefined) {
		fo.WriteLine('\t\tВ air.ini нет класса '+"air."+pName+" cтр:"+n)
		return false
	} 
	
		
	pwName=airName+"."+wName

//	WScript.Echo(""+pName+" => "+dAirini.Item("air."+pName))
	for (var i in dWeapons)
		if (pwName == dWeapons[i])
			return true
	
//	WScript.Echo("Не найдено="+pwName+"="+pName+"."+wName)

	return false
}
	
		


//обход всех каталогов начиная с указанного в первом параметре
function DirWithSubFolders(_folder){
	EnumerateSkins (_folder);				//получение всех файлов bmp в каталоге
	
    var more_folders = new Enumerator(_folder.SubFolders);
    for (;!more_folders.atEnd();more_folders.moveNext())
        DirWithSubFolders (more_folders.item());		//обработка подчиненных каталогов
    
}


//Обработка всех файлов mis в очередном каталоге
function CheckCampaignFolder(_folder){
    var more_files = new Enumerator(_folder.Files);

	
	if (!fso.FileExists(_folder.Path+"\\campaign.ini")){
//		fo.WriteLine("Файл campaign.ini не найден в каталоге "+_folder)
		generate_campaign_ini(_folder.Path)
		checkCampaign(_folder.Path+"\\campaign.tmp")	
		fso.DeleteFile(_folder.Path+"\\campaign.tmp")

	} else
		checkCampaign(_folder.Path+"\\campaign.ini")	
	
}

function generate_campaign_ini(cmPath){
	var fcam = fso.CreateTextFile(cmPath+'\\campaign.tmp')

	f = fso.GetFolder(cmPath); 		
	fc = new Enumerator(f.files); 		
	for (; !fc.atEnd(); fc.moveNext()) {
		m=""+fc.item()
//		WScript.Echo(fc.item().Name+"\n")
		if (m.indexOf('.mis') != -1)
			fcam.WriteLine(fc.item().Name)
	}

	fcam.Close()
}


//Обработка всех файлов mis в очередном каталоге
function EnumerateSkins(_folder){
    var more_files = new Enumerator(_folder.Files);

    for (;!more_files.atEnd();more_files.moveNext()){
        one_file = more_files.item();
		fName=one_file.Name
		skinList[nstr]=""+fName
		nstr++
    }
}

function checkCampaign(fil){		//проверка одного файла кампании
	var fso, f, s, ForReading;

	var branch = true
	if (fil.indexOf(".tmp") != -1)
		branch = false
	
	if (branch)
		fo.WriteLine("Проверка кампании "+fil+"\n")
	else
		fo.WriteLine("Проверка одиночных миссий\n")
	

	
	ForReading = 1, s= "";
	fso = new ActiveXObject("Scripting.FileSystemObject");
	f = fso.OpenTextFile(fil, ForReading, false);

	n=0
	while (!f.AtEndOfStream){
		s = f.ReadLine()
		n++
		if (s.charAt(0)=="*")
			checkVideo(s,n)
		
		if (s.toLowerCase().indexOf("epiloguetrack") != -1)
			checkVideo(s,n)

		if (s.toLowerCase().indexOf(".mis") != -1){	//ветвящиеся мисии
			if (branch){
				ss = s.split(/\s/);	//слова по вайтспейс
				for (var i in ss)
					checkMisFIle(main_folder.Path + "\\" + ss[i])
			}else
				checkMisFIle(main_folder.Path + "\\" + s)
		}
	}

	f.Close()
}


//проверка одного файла миссии
function checkMisFIle(fil){
	var fso, f, s, ForReading;

	fso = new ActiveXObject("Scripting.FileSystemObject");

	if (!fso.FileExists(fil)){
		fo.WriteLine("\t*** Отсутствует файл миссии "+fil)
		return
	}
	
	misfile=fil
	fo.WriteLine("\n\t"+fil)
	
	checkProperties(fil)
	
	ForReading = 1, s= "";
	f = fso.OpenTextFile(fil, ForReading, false);
	
	section=""
	n=0
	WindDirection = 0
	FlyDirection = 0
	WindSpeed = 0
	
	pSection="-"				//имя секции игрока
	pSection_way="-" 			//имя секции маршрута игрока
	
	pway=false					//признак обработки секции маршрута игрока
	psec=false					//признак обработки секции игрока
	
								//строки с координатами взлета, полета и посадки пока неопределены
	takeoff=""	
	normfly=""
	landing=""
	
	while (!f.AtEndOfStream){
		s = f.ReadLine()
		sl=s.trim().toLowerCase()
		n++						//номер стррки файла
		if (sl.charAt(0)=="[")	//текущая секция - может пригодится
			section=sl
		
		iw=s.indexOf(" air.")						
		if (iw !=-1) {								//нашли class air. Как его проверить?
			planeName=s.substr(iw+5).trim()
		}
		iw=s.indexOf("weapons ")						
		if (iw !=-1) {								//нашли class air. Как его проверить?
			weapons=s.substr(iw+8).trim()	//Занести в customList ?
			checkWeapons(planeName,weapons,n)
		}
		
		iw=sl.indexOf("plane$")						//стационарный объект - предпоследнее слово в строке - скин
		if (iw !=-1) {
			if (sl.indexOf(".bmp") == -1)			//нет скина, нечего проверять
				continue
			
			ik=sl.indexOf(".bmp")
			i1=sl.lastIndexOf(" ",ik)
			is=s.trim()			// sl преобразован в lowerCase имена скинов берем из исходной строки
			Skin=is.substr(i1+1,ik-i1+3)

			is=is.substr(iw+6)
			planeName=is.substr(0,is.indexOf(" ")-1)				//внести planeName в customList ?
			
			//WScript.Echo(planeName+":"+Skin);
			
			checkSkin(Skin,n)
			continue
		}

		if (sl.indexOf("map ") == 0)
			checkMap(s,n)		//как проверить карту ? Знать бы где получить список наименований установленных карт

		if (sl.indexOf("skin") == 0){
			is=s.trim()
			checkSkin(is.substr(is.indexOf(" ")+1),n)
			continue
		}

		if (sl.indexOf("pilot") == 0){
			checkPilot(s,n)
			continue
		}
		
		iw=sl.indexOf("winddirection ")				//направление ветра
		if (iw !=-1) {
			WindDirection=sl.substr(iw+14).trim()
			continue
		}
		
		iw=sl.indexOf("windspeed ")					//скорость ветра
		if (iw !=-1) {
			WindSpeed=sl.substr(iw+10).trim()
			continue
		}

		iw=sl.indexOf("player ")					//нашли секцию игрока
		if (iw == 0) {
			pSection=sl.substr(iw+7).trim()
			pSection_way="["+pSection+"_way"+"]"
			pSection="["+pSection+"]"
			continue
		}
		
		if (sl.charAt(0) == "[") {
			pway=false								//сброс по началу каждой секции
			psec=false
		}
		
		if (sl.indexOf(pSection) != -1) {			//началась секция игрока
			psec = true
			continue
		}
		
		if (sl.indexOf(pSection_way) != -1) {		//началась секция маршрута игрока
			pway = true
			continue
		}		
		
		if (psec) {									//находимся внутри секции игрока
			//WScript.Echo(n+" player " +pSection+ " " +section)	//можно что-то делать с командами секции игрока
		}
		
		if (pway) {									//внутри секции player_way
													//определим направление взлета-посадки
			iw=sl.indexOf("takeoff ")				//взлет
			if (iw !=-1) {
				takeoff=sl.substr(iw+8)
				//WScript.Echo(takeoff)
			}
			else{
				iw=sl.indexOf("takeoff_")				//взлет
				if (iw !=-1) {
					ib=sl.indexOf(" ")
					takeoff=sl.substr(ib+1)
					//WScript.Echo("_",takeoff,misfile)
				}
			}

			iw=sl.indexOf("normfly ")
			if (iw !=-1) 
				if (takeoff.length != 0){ 			//был взлет
					if (normfly.length == 0)		//первая точка после взлета
						normfly=sl.substr(iw+ 8)
				} else								//взлета не было, запоминаем все точки маршрута
					normfly=sl.substr(iw+8)			//в конце это будет последняя точка перед посадкой
					
			iw=sl.indexOf("landing ")
			if (iw !=-1) 
				landing=sl.substr(iw+8)

			continue
		}
	}

	//WScript.Echo(takeoff, " - " , normfly, " - " , landing )
	
	//начальная и конечная точки участка взлета или посадки
	P1 = []; P2 = []
	P1[0]=1; P1[1]=1 
	P2[0]=0 ; P2[1]=0 
	
	//
	//Направление взлета - посадки. Может не совпадать с направлением ВПП!
	//Направление взлета опредлеляется по последней взлетной точке (takeoff или takeoff_NNN) и второй точке маршрута (normfly)
	//При старте в воздухе направление посадки определяется по предпоследней (normfly) и точке посадки (landing)
	//Если старт в воздухе и посдки нет, то направление ветра не проверяется.
	//Полученный курс сравнивается с направлением ветра.
	//
	FlyDirection = 0	
	
	if (takeoff.length == 0)
		if (landing.length == 0)				//нет ни взлета ни посадки - нечего проверять
			; 						
		else {									//только посадка
			getCoord(normfly,P1)
			getCoord(landing,P2)
			FlyDirection = cAngle(P1,P2)
			checkWind(WindDirection,WindSpeed,FlyDirection,"Посадка")
		}
	else {										//взлет есть
		getCoord(takeoff,P1)
		getCoord(normfly,P2)
		FlyDirection = cAngle(P1,P2)
		checkWind(WindDirection,WindSpeed,FlyDirection,"Взлет")
	}
	
	f.Close()
}

function checkWind(windDir,windSpeed,flyDir,Type){
	if (windSpeed == 0)
		return
	fw=windDir-flyDir							//нормализуем по направлению полета
	if (fw<0)
		fw = fw + 360
	if (fw > 90 && fw < 270) {
		fo.WriteLine("\t\t"+Type+" против ветра "+" Курс:"+flyDir+" Ветер:"+windDir+" Скорость ветра:"+windSpeed)
	}
}


function checkWeapons(planeName,weapons,n){
	
	if (!hasWeapons(planeName,weapons))
		fo.WriteLine('\t\tСамолет '+planeName+' не может быть вооружен '+weapons+" cтр:"+n)
}

function checkProperties(fil){
	var fso = new ActiveXObject("Scripting.FileSystemObject")
	pfile=fil.replace(/\.mis/,"_ru.properties")
	if (!fso.FileExists(pfile)){
		fo.WriteLine('\t\tНет текста миссии '+pfile)
		nerr++
	}
}

//проверка наличия файла видео
function checkVideo(s,n){
	k=s.indexOf(" ")
	var vfile=s.slice(k).trim().replace(/.mis/,'\\')
			
	var WshShell = WScript.CreateObject("WScript.Shell"),
		CurDir = WshShell.CurrentDirectory;

	var pth=CurDir.slice(0,CurDir.indexOf("Missions"));


	vfile=(pth+vfile).replace(/\\/g,'\\')

//	WScript.Echo(vfile)
	var fso = new ActiveXObject("Scripting.FileSystemObject")
	if (!fso.FileExists(vfile)){
		fo.WriteLine('\t\tНет видео '+vfile+ " стр:"+n)
		nerr++
	}
	
	if (!fso.FileExists(vfile+".msg")){
		fo.WriteLine('\t\tНет подписей видео '+vfile+".msg"+ " стр:"+n)
		nerr++
	}
}


function checkMap(map,n){
//	fo.WriteLine(" "+map)	//как проверить наличие карты в сборке?????
}


function checkSkin(Skin,n){
	Skin=Skin.replace(/\\/g," ")	//Обратную косую заменим на пробел
	if (!inList(skinList,Skin)){
		fo.WriteLine("\t\tНет скина. файл:" + " секц:" + section + " скин:" + Skin+ " стр:"+n)
		nerr++
	}
}


function checkPilot(s,n){
	s=s.trim()
	k=s.indexOf(" ")
	Pilot=s.substr(k+1)
	
	var fso = new ActiveXObject("Scripting.FileSystemObject")
	//	WScript.Echo("1"+Directory);
	pfile= Directory.substr(0,Directory.indexOf("Missions"))+"PaintSchemes\\Pilots\\"+Pilot
	if (!fso.FileExists(pfile)) {
		fo.WriteLine("\t\tНет экипировки пилота:" + " секц:" + section + " скин:" + Pilot+ " стр:"+n)
		nerr++
	}
}


//провека наличия строки str в списке List
function  inList(List,str){
	for (k in List){
		if (List[k] == str){
			return true
		}
	}
	return false
}


//координаты точки - первые два числа из строки sti занести в массив P
function getCoord(sti,P){
	var k,s
	s=sti.trim()
	k=s.indexOf(" ")
	P[0]=s.substr(0,k)
	s=s.substr(k+1).trim()
	k=s.indexOf(" ")
	P[1]=s.substr(0,k)
}


//
//вычисление угла в градусах между осью ординат и прямой 
//заданной координатами начальной и конечной точек
//
function cAngle(P1,P2) {
	var x1=P1[0],y1=P1[1]
	var x2=P2[0],y2=P2[1]
	
	var	a=x2-x1
	var b=y2-y1
	
	if (b == 0)						//чтоб переполнения сетки не было при очень маленьких b
		if (a > 0)
			return 90
		else
			return 270

	var aRad=Math.atan(a/b)			//в радианах
	var aDeg=aRad * 180/Math.PI		//перевод в граудусы

	//коррекция знаков 
	if (a > 0)
		if (b > 0)
			;
		else
			aDeg = 180 + aDeg
	else 
		if (b > 0) 
			aDeg = 360 + aDeg
		else
			aDeg =180 + aDeg
	
	aDeg=Math.round(aDeg)			//округлим до целого
	if (aDeg == 360)
		aDeg = 0

	return aDeg
}
	

//просмотр или еще что-нибудь с файлом отчета
function showFile(ofil){
	var oShell = WScript.CreateObject("WScript.Shell");
//	WScript.Echo(TextEditor+' ' +ofil);
	oShell.Run(TextEditor+' "' +ofil+'"');
}

