/*
                                Denise-MYTH Artificial Intelligence.

                                  Copyright (C) 2000 Szymon Jessa

                                         WERSJA ANGIELSKA:

This  program  is free software; you can redistribute it and/or modify it under the terms of the GNU
General  Public  License  as  published  by  the  Free  Software Foundation; either version 2 of the
License, or (at your option) any later version.

This  program  is  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even  the  implied  warranty  of  MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You  should  have received a copy of the GNU General Public License along with this program; if not,
write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

                                           WERSJA POLSKA:

Niniejszy   program   jest  oprogramowaniem  wolnodostëpnym;  moûesz  go  rozprowadzaê  dalej  i/lub
modyfikowaê na warunkach Powszechnej Licencji Publicznej GNU, wydanej przez Fundacjë Wolnodostëpnego
Oprogramowania - wedîug wersji 2-giej tej Licencji lub którejô z póúniejszych wersji.

Niniejszy   program  rozpowszechniany  jest  z  nadziejâ,  iû  bëdzie  on  uûyteczny  -  jednak  BEZ
JAKIEJKOLWIEK  GWARANCJI,  nawet  domyôlnej  gwarancji  PRZYDATNOÔCI  HANDLOWEJ albo PRZYDATNOÔCI DO
OKREÔLONYCH ZASTOSOWAÏ. W celu uzyskania bliûszych informacji - Powszechna Licencja Publiczna GNU.

Z  pewnoôciâ  wraz  z niniejszym programem otrzymaîeô teû egzemplarz Powszechnej Licencji Publicznej
GNU; jeôli nie - napisz do Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

                                              KONTAKT:

snail: Szymon Jessa, ul. Warszawska 20/6, 89-600 Chojnice,
email: smoczek@ue.eti.pg.gda.pl (ew. noco@box43.gnet.pl)
phone: (052) 39-707-88

****************************************************************************************************
*/
// ************************************************
// * * * F A K T Y  I D E N T Y F I K A C J A * * *
// ************************************************

char FROM fident_cmp_fpf_result(char ile_cmp,char ile_dat,char ile_checked,char pos_neg_cmp,char pos_neg_dat)
{
	/*
   ile_cmp - liczba grup simple_cmp
   ile_dat - liczba grup simple_dat
   ile_checked - liczba porównanych grup toûsamych (A=A, oraz B=B, B=NB, NB=B)
   pos_neg_cmp - typ pos/neg grupy orzeczeniowej simple_cmp
   pos_neg_dat - typ pos/neg grupy orzeczeniowej simple_dat

   dalsze grupy poza wypisanymi:

   + - muszâ istnieê,
   . - mogâ istnieê lub nie,
   - - nie mogâ istnieê

   PX = PX (pos X)
   NX = "nie "+X (neg X)
   OX = bez znaczenia typ pos_neg X
   =X = typy pos_neg obu grup muszâ byê takie same

   w przypadku wymaganego przyôpieszenia dziaîania moûna zoptymalizowaê kod
   tymczasem jednak warto zachowaê jasnoôê algorytmu

   przedstawiono WSZYSTKIE (tym razem chyba juû) moûliwe sytuacje, a dodatkowym
   zabezpieczeniem przy zmianie algorytmu jest komunikat o bîëdzie
   */

   char txt[MAX_LINE_LENGHT];

   /* 1)
   A PB C D - programista pisze zielony list
   A PB C D . programista pisze zielony list . do kolegi
   ZGODNY
   */
   if (ile_cmp==ile_checked && ile_dat>=ile_checked && pos_neg_cmp==GRUPA_POS && pos_neg_dat==GRUPA_POS) return FAKT_ZGODNY;

   /* 6)
   A NB C D . progamista nie pisze zielonego listu . do kolegi
   A NB C D - programista nie pisze zielonego listu
   ZGODNY
   */
   if (ile_cmp>=ile_checked && ile_dat==ile_checked && pos_neg_cmp==GRUPA_NEG && pos_neg_dat==GRUPA_NEG) return FAKT_ZGODNY;

   /* 11)
   A =B + programista (nie) pisze + list(u) do kolegi
   A =B - programista (nie) pisze
   ZGODNY
   */
   if (ile_checked<ile_dat && ile_checked==ile_cmp && pos_neg_cmp==pos_neg_dat) return FAKT_ZGODNY;

   /* 3)
   A PB C D . programista pisze zielony list . do kolegi
   A NB C D - programista nie pisze zielonego listu
   SPRZECZNY
   */
   if (ile_cmp>=ile_checked && ile_dat==ile_checked && pos_neg_cmp==GRUPA_POS && pos_neg_dat==GRUPA_NEG) return FAKT_SPRZECZNY;

   /* 4)
   A NB C D - programista nie pisze zielonego listu
   A PB C D . programista pisze zielony list . do kolegi
   SPRZECZNY
   */
   if (ile_cmp==ile_checked && ile_dat>=ile_checked && pos_neg_cmp==GRUPA_NEG && pos_neg_dat==GRUPA_POS) return FAKT_SPRZECZNY;

   /* 9)
   A PB C D + programista pisze zielony list + do kolegi
   A NB C D - programista nie pisze zielonego listu
   SPRZECZNY
   */
   if (ile_cmp>ile_checked && ile_dat==ile_checked && pos_neg_cmp==GRUPA_POS && pos_neg_dat==GRUPA_NEG) return FAKT_SPRZECZNY;

   // przy zaîoûeniu, ûe funkcja obejmuje wszystkie moûliwoôci i dalsze sâ jako BRAK_DANYCH
//   return FAKT_BRAK_DANYCH;

   /* 2)
   A PB C D + programista pisze zielony list + do kolegi
   A PB C D - programista pisze zielony list
   BRAK DANYCH
   */
   if (ile_cmp>ile_checked && ile_dat==ile_checked && pos_neg_cmp==GRUPA_POS && pos_neg_dat==GRUPA_POS)  return FAKT_BRAK_DANYCH;

   /* 5)
   A PB C D - programista pisze zielony list
   A NB C D + programista nie pisze zielonego listu + do kolegi
   BRAK DANYCH
   */
   if (ile_cmp==ile_checked && ile_dat>ile_checked && pos_neg_cmp==GRUPA_POS && pos_neg_dat==GRUPA_NEG)  return FAKT_BRAK_DANYCH;

   /* 7)
   A PB C D + programista pisze zielony list + do kolegi
   A PB C D - programista pisze zielony list
   BRAK DANYCH
   */
   if (ile_cmp>ile_checked && ile_dat==ile_checked && pos_neg_cmp==GRUPA_POS && pos_neg_dat==GRUPA_POS) return FAKT_BRAK_DANYCH;

   /* 8)
   A NB C D + programista nie pisze zielonego listu + do kolegi
   A PB C D - programista pisze zielony list
   BRAK DANYCH
   */
   if (ile_cmp>ile_checked && ile_dat==ile_checked && pos_neg_cmp==GRUPA_NEG && pos_neg_dat==GRUPA_POS) return FAKT_BRAK_DANYCH;

   /* 10)
   A OB C + programista pisze zielony list
   A OB C + programista nie pisze czerwonego listu
   BRAK DANYCH
   */
   if (ile_checked<ile_dat && ile_checked<ile_cmp) return FAKT_BRAK_DANYCH;

   // zabezpieczenie przydatne w przypadku zmiany warunków

	con_put("bîâd: sytuacja nie zostaîa przewidziana (brak danych)\n");
   sprintf(txt,"ile_cmp=%d\nile_dat=%d\nile_checked=%d\n",ile_cmp,ile_dat,ile_checked);
   con_put(txt);

	return FAKT_BRAK_DANYCH;
}

char FROM fident_cmp_fpf(struct obiekt_struct *obiekt_dat,struct simple_struct *simple_dat,
						       struct obiekt_struct *obiekt_cmp,struct simple_struct *simple_cmp,
							    char mode,char depth)
{
	/*
	mode:
	MODE_ZGODNOSC - kontrola zgodnoôci fpf w peînym zakresie
	MODE_TOZSAMOSC - kontrola zgodnoôci bez rdzenia i o danej gîëbokoôci

	obiekt_dat/simple_dat - fakt z bazy
	obiekt_cmp/simple_cmp - fakt do porównania

	algorytm:
	- pobieramy grupë z listy simple_cmp
	  - jeôli nie ma to WYJÔCIE
	  - jeôli jest to dalej
	- pobieramy grupë z listy simple_dat
	  - jeôli nie ma to WYJÔCIE
	  - jeôli jest to dalej
	- porównujemy funkcje obu grup
		- jeôli nie sâ zgodne to WYJÔCIE
		- jeôli sâ zgodne to dalej
	- porównujemy grupy podstawowe
		- jeôli nie sâ zgodne to WYJÔCIE
		- jeôli sâ zgodne to dalej
	- jeôli to grupy orzeczeniowe i sâ sprzeczne (POS/NEG), to notujemy to
	- skok na poczâtek
	*/

	char poz,gr_start=0,podst_cmp[MAX_LINE_LENGHT],podst_dat[MAX_LINE_LENGHT];
	char grupa_cmp,grupa_dat;
	char ile_checked,pos_neg_cmp,pos_neg_dat,cmp_len,dat_len;

	if (mode==MODE_TOZSAMOSC) gr_start=1;
	ile_checked=gr_start;

	if (depth==FULL_DEPTH)
   {
      cmp_len=simple_cmp->ile_grup;
      dat_len=simple_dat->ile_grup;
      depth=simple_cmp->ile_grup;
   }
   else
   {
      cmp_len=min(simple_cmp->ile_grup,depth);
      dat_len=min(simple_dat->ile_grup,depth);
   }

	depth=min(depth,min(simple_cmp->ile_grup,simple_dat->ile_grup));

   // zabezpieczenie dotyczy próby sprawdzania zbyt krótkich fp
   // (np. standardowe fpi jest takie)
   if (gr_start>=depth) return FAKT_BRAK_DANYCH;

	// zebranie danych o grupach orzeczeniowych
	if (fgrupa_get_body(obiekt_cmp->podstawowe,simple_cmp->opis[1],podst_cmp)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;
	if (fgrupa_get_body(obiekt_dat->podstawowe,simple_dat->opis[1],podst_dat)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;

	pos_neg_cmp=fgrupa_pos_neg(podst_cmp);
	pos_neg_dat=fgrupa_pos_neg(podst_dat);

	// wîaôciwa pëtla
	for (poz=gr_start;poz<depth;poz++)
	{
		grupa_cmp=simple_cmp->opis[poz];
		grupa_dat=simple_dat->opis[poz];

		// funkcje
		if (fgrupa_cmp_funkcja(obiekt_cmp->funkcja[grupa_cmp],obiekt_dat->funkcja[grupa_dat])==RESULT_NO_OK) break;

		// grupy podstawowe
		if (fgrupa_get_body(obiekt_cmp->podstawowe,grupa_cmp,podst_cmp)==RESULT_NO_OK) break;
		if (fgrupa_get_body(obiekt_dat->podstawowe,grupa_dat,podst_dat)==RESULT_NO_OK) break;

		if (fgrupa_cmp_body(podst_cmp,podst_dat)==GRUPA_BRAK_DANYCH) break;

		ile_checked++;
	}

	return fident_cmp_fpf_result(cmp_len,dat_len,ile_checked,pos_neg_cmp,pos_neg_dat);
}

char FROM fident_cmp_fpi(struct obiekt_struct *obiekt_dat,struct simple_struct *simple_dat,
							  struct obiekt_struct *obiekt_cmp,struct simple_struct *simple_cmp,char depth)
{
   /*
   funkcja porównujâca fpf (cmp) z fpi (dat)

   algorytm:
   ograniczenia algorytmu i warunki ogólne:
   - wymagana jest gîëbokoôê fpf==3
	- tylko jeôli badany fpf ma czîon orzeczeniowy 'byê'
   - grupa nr 3 w simple_cmp musi byê orzecznikiem

   porównanie w dziedzinie fpi:
   - rozpoznanie typów pos/neg grup orzeczeniowych (dat jest zawsze POS)
   - porównanie dalszych grup:
      - jeôli grupy nie ma, to zwracamy wynik pos_neg_cmp (przekonwertowany)
      - jeôli grupy BRAK DANYCH to:
         - jeôli fpf ma 3 grupy i
           jeôli grupa orzecznika obiekt_cmp jest toûsamoôciowa, np.:
           czîowiek jest CZÎOWIEKIEM, programista jest PROGRAMISTÂ to:
           - jeôli pos_neg_cmp==NEG to SPRZECZNY
           - jeôli pos_neg_cmp==POS to ZGODNY
         - jeôli nie jest toûsamoôciowa to BRAK DANYCH
      - jeôli grupy ZGODNE i pos_neg_cmp==NEG to SPRZECZNY
      - jeôli grupy ZGODNE i pos_neg_cmp==POS to ZGODNY
      - jeôli grupy SPRZECZNE i pos_neg_cmp==NEG to ZGODNY
      - jeôli grupy SPRZECZNE i pos_neg_cmp==POS to SPRZECZNY
   */

   char pos_neg_cmp;
   char podst_cmp[MAX_LINE_LENGHT],podst_dat[MAX_LINE_LENGHT];

   // max. gîëbokoôê 3
   if (depth==FULL_DEPTH) depth=max(simple_dat->ile_grup,simple_cmp->ile_grup);
	if (depth>3) return FAKT_BRAK_DANYCH;

   // jeôli fpf jest dîuûszy niû 3, to BRAK_DANYCH
   if (simple_cmp->ile_grup>3) return FAKT_BRAK_DANYCH;

	// czîon orzeczeniowy fpf musi mieê wyraz podstawowy 'byê'
   if (fgrupa_get_body(obiekt_cmp->podstawowe,simple_cmp->opis[1],podst_cmp)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;
   if (fgrupa_cmp_body(podst_cmp,"byê")==GRUPA_BRAK_DANYCH) return FAKT_BRAK_DANYCH;

   // rozpoznanie typów pos_neg grup orzeczeniowych
   pos_neg_cmp=fgrupa_pos_neg(podst_cmp);

   // jeôli kontrola odbywa sië na gîëbokoôci tylko 2 grup, to return pos_neg_cmp
   if (depth==2 || simple_cmp->ile_grup==2)
   {
      switch (pos_neg_cmp)
      {  
         case GRUPA_POS: return FAKT_ZGODNY;
         case GRUPA_NEG: return FAKT_SPRZECZNY;
      }
   }

   // grupa nr 3 w simple_cmp musi byê orzecznikiem
   if (obiekt_cmp->funkcja[simple_cmp->opis[2]]!=ORZECZNIK) return FAKT_BRAK_DANYCH;

   // warunek ogólny
   if (simple_cmp->ile_grup<3) return FAKT_BRAK_DANYCH;

   // jeôli grupa orzecznikowa jest toûsamoôciowa z podmiotem
   if (fgrupa_get_body(obiekt_cmp->podstawowe,simple_cmp->opis[2],podst_cmp)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;
   if (fgrupa_get_body(obiekt_dat->podstawowe,simple_dat->opis[0],podst_dat)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;

   if (fgrupa_cmp_body(podst_cmp,podst_dat)==GRUPA_ZGODNA)
      return (char) (pos_neg_cmp==GRUPA_POS ? FAKT_ZGODNY : FAKT_SPRZECZNY);  

   // warunek ogólny
   if (simple_dat->ile_grup<2) return FAKT_BRAK_DANYCH;

	// porównanie grup opisowych jeôli istniejâ
   if (fgrupa_get_body(obiekt_cmp->podstawowe,simple_cmp->opis[2],podst_cmp)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;
   if (fgrupa_get_body(obiekt_dat->podstawowe,simple_dat->opis[1],podst_dat)==RESULT_NO_OK) return FAKT_BRAK_DANYCH;

   switch (fgrupa_cmp_body(podst_cmp,podst_dat))
   {
      case GRUPA_BRAK_DANYCH: return FAKT_BRAK_DANYCH;
      case GRUPA_SPRZECZNA: return (char) (pos_neg_cmp==GRUPA_POS ? FAKT_SPRZECZNY : FAKT_ZGODNY);
      case GRUPA_ZGODNA: return (char) (pos_neg_cmp==GRUPA_NEG ? FAKT_SPRZECZNY : FAKT_ZGODNY);
   }

   // zabezpieczenie - przezorny zawsze przejëzyczony
   con_put("bîâd: funkcja fgrupa_cmp_body zwróciîa zîâ wartoôê\n");

   return FAKT_BRAK_DANYCH;
}

char FROM fident_cmp_fp(struct obiekt_struct *obiekt_dat,struct simple_struct *simple_dat,
							  struct obiekt_struct *obiekt_cmp,struct simple_struct *simple_cmp,
							  char mode,char depth)
{
	/*
	funkcja porównuje fakty proste w dziedzinie fpf i fpi bazy danych
	wyróûnia sië osobne tryby porównaï z fpf i fpi
	tryb fpf - kiedy simple_dat jest typu fpf
	tryb fpi - kiedy simple_dat jest typu fpi

   rozpoznanie trybów fpf/fpi:
   - jeôli druga grupa jest typu orzeczeniowego to jest to tryp fpf
   - w pozostaîych przypadkach tryb fpi

	opis dziaîania poszczególnych trybów - patrz odpowiednie funkcje

   UWAGA! jeôli porównujemy fpf, i BRAK_DANYCH to sprawdzamy jeszcze
          wnioskowanie przydawkowe i zwracamy ten wynik
	*/

   char result;

	// rozpoznanie trybu
   if (simple_dat->ile_grup>=2)
   {
   	switch (obiekt_dat->funkcja[simple_dat->opis[1]])
   	{
   		case ORZECZENIE_CZASOWNIKOWE:
	   	case LACZNIK:
		   	result=fident_cmp_fpf(obiekt_dat,simple_dat,obiekt_cmp,simple_cmp,mode,depth);
            if (result==FAKT_BRAK_DANYCH) result=fniosk_przydawkowe_simple(obiekt_dat,simple_dat,obiekt_cmp,simple_cmp);
            return result;
   		default:
		   	return fident_cmp_fpi(obiekt_dat,simple_dat,obiekt_cmp,simple_cmp,depth);
   	}
   }
   else
		return fident_cmp_fpi(obiekt_dat,simple_dat,obiekt_cmp,simple_cmp,depth);
}

char FROM fident_obiekt_simple(struct fakt_struct *fakt,struct obiekt_struct *obiekt_spr,struct simple_struct *simple_param,char depth,char mode)
{
	/*
	mode:
	MODE_ZGODNOSC - sprawdza wszystkie grupy
	MODE_TOZSAMOSC - pomija grupe rdzenia

   depth:
   w przypadku podania simple_spr depth okreôla gîëbokoôê sprawdzania tego fp

   UWAGA! w MODE_TOZSAMOSC jest czasowo wyîâczane wyôwietlanie view.wnioskowanie

	funkcja sprawdza obiekt (simple) z danymi w bazie o fakcie macierzystm fakt
	zwraca wartoôê:
	- FAKT_ZGODNY - gdy obiekt zgodny z danymi w bazie
	- FAKT_SPRZECZNY - gdy obiekt sprzeczny z danymi w bazie
	- FAKT_BRAK_DANYCH - gdy brak danych o obiekcie

	algorytm:
	- pobieramy obiekt z bazy w celu porównania ze sprawdzanym (obiekt_spr)
	  (jeôli nie ma juû obiektów w bazie, to wychodzimy z pëtli)
	- sprawdzamy wszystkie fakty proste obiektów (FP=FPI+FPF):
		- jeôli jakiô FP z bazy jest sprzeczny z FP z obiektu to
		  zapamiëtujemy to jako wykrytâ sprzecznoôê
		- jeôli wszystkie FP obiektu sâ ZGODNE z obiektem z bazy to FAKT_ZGODNY

	po wyjôciu z pëtli:
	- jeôli byîa wykryta sprzecznoôê, to FAKT_SPRZECZNY
	- jeôli nie wykryto sprzecznoôci, to:
      - jeôli wyîâczone wnioskowanie to return FAKT_BRAK_DANYCH
      - jeôli wîâczone wnioskowanie to return fniosk()

   UWAGA! jeôli wykryto tryb KLASYFIKACJI to nie sâ sprawdzane FPI!
	*/

	struct obiekt_struct *obiekt_dat=NULL; // obiekt z bazy faktów
	struct simple_struct *simple_dat=NULL,*simple_spr=NULL; // fp obiektu z bazy faktów
	char result=FAKT_BRAK_DANYCH; // ustalenie wstëpne wartoôci zwracanej
   char old,podano_simple=KOD_FALSE,klasyfikacja=KOD_FALSE;

   if (simple_param!=NULL) podano_simple=KOD_TRUE;
   else depth=FULL_DEPTH;

	// zabezpieczenie
	if (fakt==NULL)
   {
      // jeôli nie ma faktu macierzystego, to korzystamy tylko z fniosk_przydawkowe
      return fniosk_przydawkowe(obiekt_spr,simple_param);
   }

   // czy tryb KLASYFIKACJI?
   if (podano_simple==KOD_TRUE && depth==3 && mode==MODE_TOZSAMOSC) klasyfikacja=KOD_TRUE;

	for (obiekt_dat=fakt->obiekt_head;obiekt_dat!=NULL;obiekt_dat=obiekt_dat->next)
	{
		// czy obiekt_dat ma wszystkie lub podany FPF z obiekt_spr
		for (simple_spr=obiekt_spr->funkc_head;simple_spr!=NULL;simple_spr=simple_spr->next)
		{
         if (podano_simple==KOD_TRUE) simple_spr=simple_param;

         // przeszukujemy FPF obiektu_dat
			for (simple_dat=obiekt_dat->funkc_head;simple_dat!=NULL;simple_dat=simple_dat->next)
			{
				switch (fident_cmp_fp(obiekt_dat,simple_dat,obiekt_spr,simple_spr,mode,depth))
				{
					case FAKT_ZGODNY: goto NEXT_FPF;
					case FAKT_SPRZECZNY:
						result=FAKT_SPRZECZNY;
						goto NEXT_OBIEKT;
				}
			}

         // w trybie klasyfikacji pomijamy FPI
         if (klasyfikacja==KOD_TRUE) goto NEXT_OBIEKT;

 			// przeszukujemy FPI obiektu_dat
   		for (simple_dat=obiekt_dat->ident_head;simple_dat!=NULL;simple_dat=simple_dat->next)
	   	{
		   	switch (fident_cmp_fp(obiekt_dat,simple_dat,obiekt_spr,simple_spr,mode,depth))
			   {
  					case FAKT_ZGODNY: goto NEXT_FPF;
   				case FAKT_SPRZECZNY:
	   				result=FAKT_SPRZECZNY;
		   			goto NEXT_OBIEKT;
  				}
   		}

			goto NEXT_OBIEKT; // jeôli nie ma, to nastëpny obiekt
			NEXT_FPF:

         if (podano_simple==KOD_TRUE) break; // jeôli podano simple to kontrola tylko podanego

         continue; // jeôli jest, to nastëpny fpf
		}
		return FAKT_ZGODNY; // jeôli wszystkie fpf sâ zgodne

		NEXT_OBIEKT: continue;
	}

	// opcjonalne wnioskowanie gdy nie ma nic w tym obiekcie na poziomie 0
	if (result==FAKT_BRAK_DANYCH && deep_identify==KOD_TRUE)
   {
      if (mode==MODE_TOZSAMOSC)
      {
         old=view.wnioskowanie;
         view.wnioskowanie=KOD_FALSE;
      }

		result=fniosk_child(fakt,obiekt_spr);

      if (mode==MODE_TOZSAMOSC) view.wnioskowanie=old;
   }

	return result;
}

struct fakt_struct * FROM fident_mother_fakt(struct obiekt_struct *obiekt_ident,char *rdzen)
{
	// funkcja szuka faktu macierzystego, tj. takiego, ktory ma zgodny rdzen z:
	// - obiekt_ident, lub, jesli obiekt_ident=NULL:
	// - podanym rdzeniem 'rdzen'

	struct fakt_struct *fakt=NULL,*founded=NULL;

	if (fakt_head==NULL) return NULL;

	for (fakt=fakt_head;fakt!=NULL;fakt=fakt->next)
	{
		// zaleznie od typu wywolania rozne funkcje kontroli
		if (obiekt_ident!=NULL)
			{if (fident_cmp_rdzen_obiekt(fakt->obiekt_head,obiekt_ident)==RESULT_NO_OK) continue;}
		else
			{if (fident_cmp_rdzen_podst(fakt->obiekt_head,rdzen)==RESULT_NO_OK) continue;}

		if (founded!=NULL)
		{
			con_put("bîâd: zidentyfikowano fakty nadmiarowe (bîëdna baza faktów)\n");
			return NULL;
		}

		founded=fakt;
	}

	return founded;
}

char FROM fident_cmp_rdzen_obiekt(struct obiekt_struct *obiekt1,struct obiekt_struct *obiekt2)
{
	// porownanie rdzenia: czy obiekty majâ ten sam PIERWSZY czîon FPI
	// ten sam, gdy:
	// - ta sama grupa podstawowa (ta sama funkcja w zdaniu)

	char txt[MAX_LINE_LENGHT],nr1;

	// zabezpieczenie
	if (obiekt1==NULL || obiekt2==NULL) return RESULT_NO_OK;
	if (obiekt1->ident_head==NULL || obiekt2->ident_head==NULL) return RESULT_NO_OK;

   // zmienna przejôciowa definiujâca numer grupy z obiekt1 w obiekt2
	if (fgrupa_get_body(obiekt1->podstawowe,obiekt1->ident_head->opis[0],txt)==RESULT_NO_OK) return RESULT_NO_OK;
	if (fgrupa_exist(obiekt2,txt,obiekt1->funkcja[obiekt1->ident_head->opis[0]],&nr1,-1)!=GRUPA_ZGODNA) return RESULT_NO_OK;

	// sprawdzenie czy rdzeï obiekt2 jest ten sam co w obiekt1
	if (obiekt2->ident_head->opis[0]!=nr1) return RESULT_NO_OK;

	return RESULT_OK;
}

char FROM fident_cmp_rdzen_podst(struct obiekt_struct *obiekt,char *rdzen)
{
	// porownanie rdzenia: czy obiekt ma rdzen tozsamy z podanym,
	// czyli, czy jest:
	// - ta sama grupa podstawowa (ta sama funkcja w zdaniu)

	char podst[MAX_LINE_LENGHT];

	// zabezpieczenie
	if (obiekt==NULL || rdzen==NULL) return RESULT_NO_OK;
	if (obiekt->ident_head==NULL) return RESULT_NO_OK;

	// pobieramy rdzen obiektu i porownujemy z badanym
	if (fgrupa_get_body(obiekt->podstawowe,obiekt->ident_head->opis[0],podst)==RESULT_NO_OK) return RESULT_NO_OK;
	if (fgrupa_cmp_body(podst,rdzen)!=GRUPA_ZGODNA) return RESULT_NO_OK;

	return RESULT_OK;
}
