/*
                                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

****************************************************************************************************
*/
// * * * M A P A  K O R E L A C J I * * *

char FROM mapa_load(void)
{
   FILE *stream;
   clock_t time=clock();
   char txt[MAX_LINE_LENGHT];
   struct mapa_struct *grupa,*old_grupa=NULL;
   struct podrzedne_struct *podrzedny,*old_podrzedny;
   struct okreslane_struct *okreslany,*old_okreslany;

   mapa_head=NULL; // przed wczytaniem mapa jest pusta (zabezpieczenie!)

   if ((stream=data_open(MAPA_FILE TYPE_DAT,"r"))==NULL)
   {
      // jeôli brak pliku itp., to tworzymy mapë korelacji automatycznie
      return mapa_create();
   }

   sprintf(txt,"(%.3fkB)\n",(float) file_lenght(stream)/1024);
   con_put(txt);

   // pierwszy znak - koniec bazy danych lub poczâtek nowej pozycji
   if (fgets(txt,MAX_LINE_LENGHT,stream)==NULL) goto loading_error;
   if (txt[0]!=POZYCJA_START) goto loading_error;

   for (;;)
   {
      // rezerwujemy pamiëê dla nowej grupy
      if ((grupa=(struct mapa_struct *) malloc(sizeof(struct mapa_struct)))==NULL) goto no_memory;
      grupa->next=NULL;
      grupa->orzecznik=NULL;
      grupa->podrzedne_head=NULL;
      grupa->okreslane_head=NULL;

      // wczytujemy wyraz podstawowy orzecznika
      if (fgets(txt,MAX_LINE_LENGHT,stream)==NULL) goto loading_error;
      txt[strlen(txt)-1]=NULL; // kasujemy ENTER

      // wpisujemy go do grupy
      if ((grupa->orzecznik=create_string(txt,strlen(txt)+1))==NULL) goto no_memory;

      if (mapa_head==NULL) mapa_head=grupa;
      else old_grupa->next=grupa;

      if (fgets(txt,MAX_LINE_LENGHT,stream)==NULL) goto loading_error;
      // musi byê znak rozpoczëcia listy orzeczników podrzëdnych
      if (txt[0]!=ORZECZNIKI_PODRZEDNE) goto loading_error;

      // odczytujemy ciâg orzeczników podrzëdnych
      for (old_podrzedny=NULL;;old_podrzedny=podrzedny)
      {
         if (fgets(txt,MAX_LINE_LENGHT,stream)==NULL) goto loading_error;
         // jeôli to koniec listy podrzëdnych i poczâtek okreôlanych to break
         if (txt[0]==PART_NEXT_START) break;

         // zapisujemy w pamiëci nowâ listë
         if ((podrzedny=(struct podrzedne_struct *) malloc(sizeof(struct podrzedne_struct)))==NULL) goto no_memory;
         podrzedny->next=NULL;
         podrzedny->orzecznik=NULL;

         // okreôlenie typu
         podrzedny->typ=FAKT_ZGODNY;
         if (txt[0]==MAPA_SPRZECZNY)
         {
            memcpy(txt,txt+1,strlen(txt));
            podrzedny->typ=FAKT_SPRZECZNY;
         }

         if ((podrzedny->orzecznik=create_string(txt,strlen(txt)))==NULL) goto no_memory;

         // doîâczamy do ciâgu podrzëdnych
         if (old_podrzedny==NULL) grupa->podrzedne_head=podrzedny;
         else old_podrzedny->next=podrzedny;
      }

      // odczytujemy ciâg faktów okreôlanych
      for (old_okreslany=NULL;;old_okreslany=okreslany)
      {
         if (fgets(txt,MAX_LINE_LENGHT,stream)==NULL) goto loading_error;
         // jeôli to koniec ciâgu
         if (txt[0]==POZYCJA_START) break;
         // jeôli to koniec bazy
         else if (txt[0]==DATA_END) goto END_FOR;
         txt[strlen(txt)-1]=NULL; // kasujemy ENTER

         // zapisujemy w pamiëci nowe fakty okreôlane
         if ((okreslany=(struct okreslane_struct *) malloc(sizeof(struct okreslane_struct)))==NULL) goto no_memory;
         okreslany->next=NULL;
         okreslany->fakt=NULL;

         // okreôlenie typu
         okreslany->typ=FAKT_ZGODNY;
         if (txt[0]==MAPA_SPRZECZNY)
         {
            memcpy(txt,txt+1,strlen(txt));
            okreslany->typ=FAKT_SPRZECZNY;
         }

        // odszukujemy wskaúnika do tego faktu
         if ((okreslany->fakt=fident_mother_fakt(NULL,txt))==NULL)
         {
            con_put("bîâd: mapa korelacji nie jest zgodna z bazâ faktów\n");
            goto loading_error;
         }

         // doîâczamy do ciâgu faktów okreôlanych
         if (old_okreslany==NULL) grupa->okreslane_head=okreslany;
         else old_okreslany->next=okreslany;
      }

      old_grupa=grupa;
   }
   END_FOR:

   fclose(stream);
   sprintf(txt,"liczba orzeczników/podrzëdnych/okreôlanych: %ld/%ld/%ld (%.3fkB) (%.3fs)\n",
                mapa_count_grupy(),mapa_count_podrzedne(),mapa_count_okreslane(),(float) mapa_memory_use()/1024,(float) (clock()-time)/CLK_TCK);
   con_put(txt);

   return RESULT_OK;

   // bîâd przy wczytywaniu
   loading_error:
   fclose(stream);
   con_put("bîâd: nie mogë odczytaê danych\n");
   mapa_erase();
   if (mapa_create()==RESULT_OK) return RESULT_OK;
   return RESULT_NO_OK;

   no_memory:
   fclose(stream);
   con_put("bîâd: brak pamiëci\n");
   mapa_erase();
   return RESULT_NO_OK;
}

char FROM mapa_save(void)
{
#ifdef DEMO
   con_put("w wersji demonstracyjnej nie moûna zapisaê mapy korelacji\n");
   return RESULT_OK;
#else
   FILE *stream;
   struct mapa_struct *mapa;
   struct podrzedne_struct *podrzedny;
   struct okreslane_struct *okreslany;
   char txt[MAX_LINE_LENGHT];

   // zabezpieczenie - nie nagrywamy bazy jeôli jest pusta, nie kasujemy starej
   if (mapa_head==NULL) return RESULT_OK;

   if ((stream=data_open(MAPA_FILE TYPE_TMP,"w"))==NULL) return RESULT_NO_OK;

   for (mapa=mapa_head;mapa!=NULL;mapa=mapa->next)
   {
      // znak poczâtku nowej grupy orzecznikowej
      if (fprintf(stream,"%c\n",POZYCJA_START)<0) goto saving_error;

      // wyraz podstawowy orzecznika
      if (fprintf(stream,"%s\n",mapa->orzecznik)<0) goto saving_error;

      // lista orzeczników podrzëdnych
      if (fprintf(stream,"%c\n",ORZECZNIKI_PODRZEDNE)<0) goto saving_error;
      for (podrzedny=mapa->podrzedne_head;podrzedny!=NULL;podrzedny=podrzedny->next)
      {
         switch (podrzedny->typ)
         {
            case FAKT_ZGODNY:
               if (fprintf(stream,"%s\n",podrzedny->orzecznik)<0) goto saving_error;
               break;
            case FAKT_SPRZECZNY:
               if (fprintf(stream,"%c%s\n",MAPA_SPRZECZNY,podrzedny->orzecznik)<0) goto saving_error;
               break;
            default:
               con_put("bîâd: nie zostaî okreôlony typ podrzedny w mapie korelacji\n");
               break;
         }
      }

      // lista faktów okreôlanych
      if (fprintf(stream,"%c\n",PART_NEXT_START)<0) goto saving_error;
      for (okreslany=mapa->okreslane_head;okreslany!=NULL;okreslany=okreslany->next)
      {
      	if (fgrupa_get_body(okreslany->fakt->obiekt_head->podstawowe,okreslany->fakt->obiekt_head->ident_head->opis[0],txt)==RESULT_NO_OK) goto saving_error;

         switch (okreslany->typ)
         {
            case FAKT_ZGODNY:
               if (fprintf(stream,"%s\n",txt)<0) goto saving_error;
               break;
            case FAKT_SPRZECZNY:
               if (fprintf(stream,"%c%s\n",MAPA_SPRZECZNY,txt)<0) goto saving_error;
               break;
            default:
               con_put("bîâd: nie zostaî okreôlony typ okreôlany w mapie korelacji\n");
               break;
         }
      }
   }
   if (fprintf(stream,"%c\n",DATA_END)<0) goto saving_error;
   fclose(stream);

   copy_and_remove(MAPA_FILE TYPE_DAT,MAPA_FILE TYPE_OLD);
   if (copy_and_remove(MAPA_FILE TYPE_TMP,MAPA_FILE TYPE_DAT)==RESULT_NO_OK) return RESULT_NO_OK;

   sprintf(txt,"zapisanych orzeczników/podrzëdnych/okreôlanych: %ld/%ld/%ld\n",
                mapa_count_grupy(),mapa_count_podrzedne(),mapa_count_okreslane());
   con_put(txt);

   return RESULT_OK;

   // bîâd w nagrywaniu danych
   saving_error:
   fclose(stream);
   remove(MAPA_FILE TYPE_TMP);
   con_put("bîâd: nie mogë zapisaê danych\n");
   return RESULT_NO_OK;
#endif
}

char FROM mapa_erase(void)
{
   struct mapa_struct *grupa,*grupa_next;
   struct podrzedne_struct *podrzedny,*podrzedny_next;
   struct okreslane_struct *okreslany,*okreslany_next;

   // zabezpieczenie
   if (mapa_head==NULL) return RESULT_OK;

   for (grupa=mapa_head;grupa!=NULL;grupa=grupa_next)
   {
      grupa_next=grupa->next;
      free(grupa->orzecznik);

      for (podrzedny=grupa->podrzedne_head;podrzedny!=NULL;podrzedny=podrzedny_next)
      {
         podrzedny_next=podrzedny->next;
         free(podrzedny->orzecznik);
         free(podrzedny);
      }

      for (okreslany=grupa->okreslane_head;okreslany!=NULL;okreslany=okreslany_next)
      {
         okreslany_next=okreslany->next;
         free(okreslany);
      }

      free(grupa);
   }

   mapa_head=NULL;

   return RESULT_OK;
}

// * * * funkcje podajâce informacje iloôciowe o bazach * * *

ULONG FROM mapa_count_grupy(void)
{
   struct mapa_struct *grupa;
   ULONG ile=0;

   for (grupa=mapa_head;grupa!=NULL;grupa=grupa->next)
   {
      ile++;
   }

   return ile;
}

ULONG FROM mapa_count_podrzedne(void)
{
   struct mapa_struct *grupa;
   struct podrzedne_struct *podrzedny;
   ULONG ile=0;

   for (grupa=mapa_head;grupa!=NULL;grupa=grupa->next)
   {
      for (podrzedny=grupa->podrzedne_head;podrzedny!=NULL;podrzedny=podrzedny->next)
      {
         ile++;
      }
   }

   return ile;
}

ULONG FROM mapa_count_okreslane(void)
{
   struct mapa_struct *grupa;
   struct okreslane_struct *okreslany;
   ULONG ile=0;

   for (grupa=mapa_head;grupa!=NULL;grupa=grupa->next)
   {
      for (okreslany=grupa->okreslane_head;okreslany!=NULL;okreslany=okreslany->next)
      {
         ile++;
      }
   }

   return ile;
}

ULONG FROM mapa_memory_use(void)
{
   struct mapa_struct *grupa;
   struct podrzedne_struct *podrzedny;
   struct okreslane_struct *okreslany;
   char txt[MAX_LINE_LENGHT];
   ULONG ile=0;

   for (grupa=mapa_head;grupa!=NULL;grupa=grupa->next,ile+=sizeof(struct mapa_struct))
   {
      ile+=sizeof(char);
      ile+=strlen(grupa->orzecznik);
      for (podrzedny=grupa->podrzedne_head;podrzedny!=NULL;podrzedny=podrzedny->next,ile+=sizeof(struct podrzedne_struct))
      {
         ile+=sizeof(char);
         ile+=strlen(podrzedny->orzecznik);
      }
      for (okreslany=grupa->okreslane_head;okreslany!=NULL;okreslany=okreslany->next,ile+=sizeof(struct okreslane_struct))
      {
         if (fgrupa_get_body(okreslany->fakt->obiekt_head->podstawowe,okreslany->fakt->obiekt_head->ident_head->opis[0],txt)==RESULT_NO_OK) continue;
         ile+=strlen(txt);
      }
   }

   return ile;
}
