CREATE OR REPLACE PROCEDURE WyznaczPoczecia IS

  cursor pary is
    select Matka.Imie Krowa, Ojciec.Imie Byk, Ojciec.NrBoksu
      from Bydlo Matka, Bydlo Ojciec
      where Matka.Plec  = 'K'
        and Ojciec.Plec = 'B'
        and Matka.NrBoksu = Ojciec.NrBoksu;
  cursor boksyjednomiejscowe is
    select nr
      from boksy
      where miejsca = 1;
  cursor wolneboksydwumiejscowe is
    select nr, count(imie)
      from bydlo, boksy
      where boksy.nr = bydlo.nrboksu (+)
      group by nr
      having count(imie) < 2;
  
  para1			pary%ROWTYPE;
  para2         	pary%ROWTYPE;
  v_nrboksu		boksy.nr%TYPE;  
  v_ilebydla		BINARY_INTEGER;
  jest			BOOLEAN;
  imie_lokatora		bydlo.imie%TYPE;  
  plec_lokatora 	bydlo.plec%TYPE;

begin
  insert into BydloPoczete (ImieMatki, ImieOjca)
    select Matka.Imie, Ojciec.Imie
      from Bydlo Matka, Bydlo Ojciec
      where Matka.Plec  = 'K'
        and Ojciec.Plec = 'B'
        and Matka.NrBoksu = Ojciec.NrBoksu;
  
  open pary;
  loop 
    fetch pary into para1;
    if pary%NOTFOUND then	-- liczba par byla parzysta, koniec
      close pary;
      return;
    end if;
    fetch pary into para2;
    if pary%NOTFOUND then	-- liczba par byla nieparzysta, trzeba
      exit;			-- rozbic te pierwsza	
    end if;

    -- zamieniamy byka z pary1 z krowa z pary2
    -- byk z pary1 do boksu pary2
    update bydlo
      set Nrboksu = para2.NrBoksu
      where imie = para1.Byk;
    -- krowa z pary2 do boksu pary1
    update bydlo
      set Nrboksu = para1.NrBoksu
      where imie = para2.Krowa;
  end loop;
  close pary;

  -- ASERCJA: zmienna para1 wskazuje ostatnia pare
  
  -- szukamy boksu jednomiejscowego

  open boksyjednomiejscowe;
  fetch boksyjednomiejscowe into v_nrboksu; 
  jest := boksyjednomiejscowe%FOUND;
  close boksyjednomiejscowe;
 
  if jest then
    begin
      -- lokator tego boksu
      select imie, plec into imie_lokatora, plec_lokatora
        from bydlo
        where nrboksu = v_nrboksu;
      -- lokator z jednomiejscowego boksu do boksu pary1
      update bydlo
        set Nrboksu = para1.NrBoksu
        where imie = imie_lokatora;
      if plec_lokatora = 'B' then
        -- krowa z pary1 do boksu jednomiejscowego
        update bydlo
          set Nrboksu = v_nrboksu
          where imie = para1.Krowa;
      else -- plec_lokatora = 'K'
        -- byk z pary1 do boksu jednomiejscowego
        update bydlo
          set Nrboksu = v_nrboksu
          where imie = para1.Byk;
      end if;
    exception
      when no_data_found then  -- nikogo tam nie ma, przenosimy tam byka
        update bydlo
          set nrboksu = v_nrboksu
          where imie = para1.byk;
    end;
    return;
  end if;

  -- ASERCJA nie ma boksu jednomiejscowego
  -- ASERCJA: zmienna para1 wskazuje ostatnia pare

  -- szukamy dobrego boksu dwumiejscowego
  open wolneboksydwumiejscowe;
  fetch wolneboksydwumiejscowe into v_nrboksu, v_ilebydla;
  jest := wolneboksydwumiejscowe%FOUND;
  close wolneboksydwumiejscowe;

  if jest then
    if v_ilebydla = 0 then
      -- przenosimy byka do tego boksu (nie gonimy ciezarnej krowy)
      update bydlo
        set nrboksu = v_nrboksu
        where imie = para1.byk;
    else -- v_ilebydla = 1 
      -- lokator tego boksu
      select imie, plec into imie_lokatora, plec_lokatora
        from bydlo
        where nrboksu = v_nrboksu;
      if plec_lokatora = 'K' then
        -- krowa z pary1 do boksu dwumiejscowego
        update bydlo
          set Nrboksu = v_nrboksu
          where imie = para1.Krowa;
      else -- plec_lokatora = 'B'
        -- byk z pary1 do boksu dwumiejscowego
        update bydlo
          set Nrboksu = v_nrboksu
          where imie = para1.Byk;
      end if;
    end if;
    return;
  end if;

  -- Wszystkie mozliwosci zawiodly  
  raise_application_error(-20066, 'Nie udalo sie rozdzielic pary ' ||
       para1.krowa || '-' || para1.byk || ' z boksu ' || para1.nrboksu || '.');
end;
/
