//	GroupLevel.txt

#include <code\programmer\instruments.txt>



var arhivPriznakov(){
	R={};
	ap1={
		"typeof(x)",
		"((set)x).size()",
		"x.size()"
		};
	for(i=0;i<ap1.size();++i)R.push(PROGRAM(ap1[i]));
	return R;
}





var indexesForGroups(A){
	groups=(vector)(set)A;
	indexes={};
	for(i=0;i<A.size();++i)indexes.push(groups.find(A[i]));
	return indexes;
}




bool sovpaloIndexesGroups(A,B,C){
	groups=(vector)(set)A;
	for(i=0;i<groups.size();++i){
		first=1;
		X=0;
		for(j=0;j<B.size();++j)if(A[j]==groups[i]){
			if(first)X=B[j];
			first=0;
			if(X!=B[j])return 0;
			}
		}
	if(isset(C))return 1;
	return sovpaloIndexesGroups(B,A,1);
}




bool ProbaPriznakovFor1var(sys){
	A=indexesForGroups(sys->outputs);
	priznaki=arhivPriznakov(1);//от одной переменной
	priznakiOK={};
	Results={};
	for(i=0;i<priznaki.size();++i){
		P=priznaki[i];
		name=P.getNames(1)[0];
		P.replace(name,"Q");
		Result={};
		for(j=0;j<sys->inputs.size();++j){
			Q=sys->inputs[j];
			Result.push(eval(P));
			}
		B=indexesForGroups(Result);
		if(sovpaloIndexesGroups(A,B)){
			priznakiOK.push(P);
			Results.push(Result);
			}
		}
	if(priznakiOK.size()){
		i=0;
		if(priznakiOK.size()>1){
			vel={};
			for(i=0;i<priznakiOK.size();++i)vel.push(priznakiOK[i].getPower(1));
			i=vel.find(vel.min());
			}
		P=priznakiOK[i];
		P.replace("Q",sys->namesinput[0]);
		Result=Results[i];
		addResultOKGroup(sys,Result,P);
		return 1;
		}

	return 0;
}




void addResultOKGroup(sys,Result,P){
		//trace(P);
		S=(vector)(set)Result;
		if(Result==sys->outputs){
			P2=PROGRAM("return #");
			P2.setSub({0},P);
			P=P2;
			S={};
			}
		if(S.size()==2){
			X=S[0];
			i=Result.find(X);
			if(typeof(X)=="bool"){
				P2=PROGRAM("return !#?#:#");
				if(X)P2.setSub({0,0},P);else P2.setSub({0,0,0},P);
				}else{
				if({"string","vector"}.find(typeof(X))>=0)X=X.export();
				P2=PROGRAM("return #=="+X+"?#:#");
				P2.setSub({0,0,0},P);
				}
			X=sys->outputs[i];
			if({"string","vector"}.find(typeof(X))>=0)X=X.export();
			P2.setSub({0,1},PROGRAM(X));
			X=S[1];
			i=Result.find(X);
			X=sys->outputs[i];
			if({"string","vector"}.find(typeof(X))>=0)X=X.export();
			P2.setSub({0,2},PROGRAM(X));
			P=P2;
			}
		if(S.size()>2){
			str="i="+S.export()+".find("+(string)P+");";
			R={};
			for(i=0;i<S.size();++i)R.push(sys->outputs[Result.find(S[i])]);
			str+="return "+R.export()+"[i];";
			P=PROGRAM(str);
			}
		Xfunct={
			name:(*sys)["имя программы"],
			program:P,
			inputnames:sys->namesinput,
			outputnames:sys->namesoutput[0]
			};
		sys->functions.push(Xfunct);
}




bool ProbaDetailsContact(sys){
	A=indexesForGroups(sys->outputs);
	sovpaloList={};
	for(i=0;i<sys->newParams.size();++i){
		B=indexesForGroups(sys->newParams[i]);
		if(sovpaloIndexesGroups(A,B))sovpaloList.push(i);
		}
	if(sovpaloList.empty())return 0;
	ROK=0;
	nametype="";
	for(i=0;i<sys->outputs.size();++i){
		if(!i)nametype=typeof(sys->outputs[i]);
		if(nametype!=typeof(sys->outputs[i]))nametype="";
		}
	for(i=0;i<sovpaloList.size();++i){
		P=sys->newParamsF[sovpaloList[i]];
		if(nametype!=""){
			P2=PROGRAM("("+nametype+")#");
			P2.setSub({0},P);
			P3=P2;
			names=P3.getNames();
			numbersInPF={};
			for(j=0;j<names.size();++j){
				t=sys->newParamsF.find(PROGRAM(names[j]));
				if(t<0)break;
				numbersInPF.push(t);
				ReplaceVars(&P3,names[j],PROGRAM("V["+j+"]"));
				}
			if(j==names.size()){
				ok=1;
				for(j=0;j<sys->outputs.size();++j){
					V={};
					for(t=0;t<numbersInPF.size();++t)V.push(sys->newParams[numbersInPF[t]][j]);
					ok=(sys->outputs[j]==eval(P3));
					if(!ok)break;
					}
				if(ok){
					P3=PROGRAM("return #");
					P3.setSub({0},P2);
					Xfunct={
						name:(*sys)["имя программы"],
						program:P3,
						inputnames:sys->namesinput,
						outputnames:sys->namesoutput[0]
						};
					sys->functions.push(Xfunct);
					ROK=1;
					continue;
					}
				}
			}
		addResultOKGroup(sys,sys->newParams[sovpaloList[i]],P);
		ROK=1;
		}
	return ROK;
}




bool GroupLevel(sys){
	if(sys->namesinput.size()==1)if(ProbaPriznakovFor1var(sys))return 1;
	if(ProbaDetailsContact(sys))return 1;

	return 0;
}

