# == Schema Information
# Schema version: 51
#
# Table name: poziomy_anotacji
#
#  poziomy_anotacji_id :integer         primary key
#  uzytkownik_id       :integer         not null
#  segmentation        :boolean         
#  sentences           :boolean         
#  morphosyntactic     :boolean         
#  word_senses         :boolean         
#  syntactic_words     :boolean         
#  named_entities      :boolean         
#  syntactic           :boolean         
#  created_at          :timestamp       
#  updated_at          :timestamp       
#

 #
 # This file is part of the Anotatornia suite.
 # 
 # Copyright © 2007, 2008, 2009, 2010 by Instytut Podstaw Informatyki
 # Polskiej Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 # Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 # 
 # This file may be distributed and/or modified under the terms of the
 # GNU General Public License version 3 as published by the Free Software
 # Foundation and appearing in the file COPYING included in the packaging
 # of this file.  (See http://www.gnu.org/licenses/translations.html for
 # unofficial translations.)
 # 
 # A commercial license is available from IPI PAN (contact
 # Michal.Ciesiolka.waw.pl or ipi.waw.pl for more
 # information).  Licensees holding a valid commercial license from IPI
 # PAN may use this file in accordance with that license.
 # 
 # This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 # THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 # PURPOSE.
 #

# tabela przechowuje informację, które poziomy anotacji są dostępne dla którego użytkownika. (Ale po co?)

require 'ramkowanie'

class PoziomyAnotacji < ActiveRecord::Base
  
  belongs_to :uzytkownik
  
  POZIOMY = [
             # poziom, poprzedniki, następniki
             # kolejność — taka, w jakiej mają się wyświetlać na pasku.
             [:segmentation, [].freeze, [:sentences, :morphosyntactic].freeze ].freeze,
             [:sentences,  [:segmentation].freeze, [:syntactic_words].freeze ].freeze,
             [:morphosyntactic,  [:segmentation].freeze, [:word_senses, :syntactic_words].freeze ].freeze,
             [:word_senses,  [:morphosyntactic].freeze, [].freeze ].freeze, # fakt, że \ac{WSD} jest maksymalny, wykorzystuje #{Statusy.autozatwierdź_word_senses}
             [:syntactic_words,  [:morphosyntactic, :sentences].freeze, [:named_entities, :syntactic].freeze ].freeze,
             [:named_entities,  [:syntactic_words].freeze, [].freeze ].freeze,
             [:syntactic,  [:syntactic_words].freeze, [].freeze ].freeze
            ].freeze


    STATI = {
      :nie_dopuszczony => -1,
      :dopuszczony => 0,
      :zatwierdzony => 8, # jeśli Anotator zakończył (zaanotował lub odrzucił)
      :do_poprawki => 10,
      :do_konfrontacji => 10, # dla kompatybilności
      :po_poprawce => 12,
      :po_konfrontacji1 => 12, # dla kompatybilności
      :po_konfrontacji2 => 12, # dla kompatybilności
      :do_osądzenia => 14, # jeśli zostało zatwierdzony i nie przeszło weryfikacji
      :zweryfikowany => 16, # obaj Anotatorzy tak samo 
      :osądzany => 15, # było zweryfikowany, ale Zarządca coś w nim grzebnął, ale nie zatwierdził.
      :osądzony => 18, #  osądzony
      :anotaśne => [0, 10].freeze, # tzn. te, w~których anotator na pewno ma coś do zrobienia
      :oczekujące => [8, 12].freeze # tzn. te, w~których anotator czeka na partnera.
    }.freeze

    # używane do zmiany statusu akapit, w którym coś grzebiemy po jakimś etapie zatwierdzenia.
    STATI_obniz = { -1 => -1, 0 => 0,  8 => 0, 10 => 10, 12=>10, 14=>15,  15 => 15, 16 => 15, 18 => 15 }.freeze

    STATI_podnies = {# #{anotacja_controller.podnies_status} w wersji nk
      # Po lewej stronie strzałki występują liczby lub tablice. Liczby — gdy podnosimy statusek bez weryfikacji, tablice — gdy podnosimy znając wynik weryfikacji. Dlatego właśnie bez weryfikacji nie można statusu podnieść do #:zweryfikowany ani #{:osądzony}.
      -1 => 0,# nie dopuszczony #=> dopuszczony
      0 => 8,# dopuszczony (bez uwzględnienia werdyktu) #=> zatwierdzony
      [0, 0].freeze => 8, # dopuszczony i werdykt 0 (brak anotacji bliźniaczej) #=> zatwierdzony
      [0, 1].freeze => 16, # dopuszczony i werdykt 1 (zgodny)
      [0,-1].freeze => 10, # dopuszczony i werdykt $-1$ (niezgodność)
      8 => 8, # żeby nie krzyczało.
      [8, 0].freeze => 8, # zatwierdzony i jw. #=> zatwierdzony
      [8, 1].freeze => 16,# zatwierdzony i jw. #=> zweryfikowany
      [8, -1].freeze => 10, # zatwierdzony i jw. #=> do poprawki
      10 => 12, # do poprawki #=> po poprawce
      [10, 0].freeze =>12, # do poprawki i bd. #=> po poprawce
      [10, 1].freeze => 16, # do poprawki i zdodne #=> zweryfikowany
      [10, -1].freeze => 14, # do poprawki i niezgodne #=> do osądzenia
      12 => 12, # po poprawce bez wiedzy o wyniku weryfikacji #=> do osądzenia
      [12, 0].freeze => 12, # po poprawce i bd. #=> po poprawce (infinite loop?)
      [12, 1].freeze => 16, # po poprawce i zgodne #=> zweryfikowany
      [12, -1].freeze => 14, # po poprawce i niezgodne #=> do osądzenia
      14 => 15,# do osądzenia #=> osądzany
      [14, -1].freeze => 18,# do osądzenia #=> osądzony
      [14, 0].freeze => 18,# do osądzenia #=> osądzony
      [14, 1].freeze => 18,# do osądzenia #=> osądzony
      15 => 15,
      [15, -1].freeze => 18, # osądzany #=> osądzony
      [15, 0].freeze => 18, # osądzany #=> osądzony
      [15, 1].freeze => 18, # osądzany #=> osądzony
      18 => 18, # osądzony #=> osądzony (Arbiter może zmienić swój osąd)
      [18, -1].freeze => 18, # osądzony #=> osądzony (Arbiter może zmienić swój osąd)
      [18, 0].freeze => 18, # osądzony #=> osądzony (Arbiter może zmienić swój osąd)
      [18, 1].freeze => 18# osądzony #=> osądzony (Arbiter może zmienić swój osąd)
    }.freeze
    
    STATI_tekst = {
      -1 => "nie dopuszczony do an.",
      0 => "dopuszczony do an.",
      8 => "zatwierdzony",
      10 => "do poprawki",
      12 => "po poprawce",
      14 => "do osądzenia",
      16 => "zweryfikowany",
      15 => "osądzany",
      18 => "osądzony"
    }.freeze
    
    STATI_kr = {
      -1 => "&#8722;", # minus 8722, en dash 8211
      0 => "dop",
      8 => "zatw",
      10 => "dopo",
      12 => "popo",
      14 => "doos",
      16 => "zwer",
      15 => "osa",
      18 => "oso"
    }.freeze

  if true or AnoVersion.port == 8005  
    DZIAŁAJĄCE = [:segmentation, :sentences, :morphosyntactic, :word_senses].freeze
  else
    DZIAŁAJĄCE = [:segmentation, :sentences, :morphosyntactic].freeze
  end  


  def self.działające
    DZIAŁAJĄCE
  end # of self.działające
  
    # Poziomy maksymalne to z definicji te, które nie mają następników. Poziomy minimalne — te, które nie mają poprzedników. Definiujemy zmienne klasowe \rb{@@poziomy_maksymalne} i \ruby{@@poziomy_minimalne}, a~także metody \ruby{self.maksymalne} i \ruby{self.minimalne} dające odczyt tych zmiennych.
    tekscik = "
    @@poziomy_xxx = POZIOMY.collect{ |poz|
      poz[0] unless poz[yyy][0]
    }.compact.freeze

    def self.xxx
      @@poziomy_xxx
    end
    "
eval tekscik.gsub( 'xxx', 'maksymalne').gsub('yyy', '2')
eval tekscik.gsub( 'xxx', 'minimalne').gsub('yyy', '1')
    
    @@poziomy_x = POZIOMY.dx

    def self.poziomy_x
      @@poziomy_x
    end

    NIE_DZIAŁAJĄCE = (@@poziomy_x - DZIAŁAJĄCE).freeze

    def self.nie_działające
      NIE_DZIAŁAJĄCE
    end
    
    def self.poprzedniki( poziom )
      POZIOMY[ poziomy_x.index( poziom ) ][1] & DZIAŁAJĄCE
    end

    def self.nastepniki( poziom )
      POZIOMY[ poziomy_x.index( poziom ) ][2] & DZIAŁAJĄCE
    end


    @@wyzsze = {}

    def self.wyzsze( poziom )
      # transitive closure operacji następnika.
      unless @@wyzsze[ poziom ] 
        upper = []
        succs = self.nastepniki( poziom )
        
        until succs == []
          succs1 = []
          succs.each{ |succ|
            upper << succ
            succs1 << self.nastepniki( succ )
          }
          succs = succs1.flatten.uniq
        end# of until
        @@wyzsze[ poziom ] = upper.uniq
      end
      @@wyzsze[ poziom ]

    end# of #{self.wyzsze}.


    @@poziomy_x.each{ |poz| self.wyzsze( poz )}

    
    NAZWY = {
      :segmentation => {:nom => 'segmentacja', :gen => 'segmentacji', :kr => 'seg' }.freeze,
      :sentences => {:nom => 'granice zdań', :gen => 'granic zdań', :kr => 'sn' }.freeze,
      :morphosyntactic =>{:nom => 'morfoskładnia', :gen => 'morfoskładni', :kr => 'ms' }.freeze,
      :word_senses => {:nom => 'sensy słów', :gen => 'sensów słów', :kr => 'wsd' }.freeze,
      :syntactic_words => {:nom => 'słowa składniowe', :gen => 'słów składniowych', :kr => 'synw' }.freeze,
      :named_entities => {:nom => 'byty nazwane', :gen => 'bytów nazwanych', :kr => 'nen' }.freeze,
      :syntactic => {:nom =>'a. składniowa', :gen => 'a. składniowej', :kr => 'syn' }.freeze
    }.freeze
    
    def self.krótkie( poziomy )
      if poziomy.kind_of?( Symbol )
        NAZWY[ poziomy ][:kr]
      elsif poziomy.kind_of?( Array )
        poziomy.collect { |po|
          NAZWY[ po ][:kr] }
      else
        raise "PoziomyAnotacji.krótkie: type of the argument (#{poziomy.inspect}) not supported."
      end
    end # of #{self.krótkie}

    tekscik = 
      "@@poziomy_xxx = {}

    @@poziomy_x.each{ |poz|
      @@poziomy_xxx[poz] = NAZWY[poz][:xxx]}.freeze

    def self.xxx( poziom )
      @@poziomy_xxx[ poziom ]
    end

    @@all_xxx = @@poziomy_x.collect{ |poz|
      self.xxx( poz )}.freeze

    def self.all_xxx
      @@all_xxx
    end

    @@działające_xxx = DZIAŁAJĄCE.collect { |poz| self.xxx( poz )}.freeze

    def self.działające_xxx
      @@działające_xxx
    end
    "

eval(  tekscik.gsub( 'xxx', 'gen'))
eval(  tekscik.gsub( 'xxx', 'nom'))
eval( tekscik.gsub( 'xxx', 'kr'))
# to nam daje metody \ruby{self.gen}, \ruby{self.nom} i \ruby{self.kr}, wszystkie trzy z 1 argumentem \<poziom>,
# oraz metody \ruby{self.all_gen}, \ruby{self.all_nom} i \ruby{self.all_kr} zwracające, a~także #{self.działające_nom} itd.

    
    def self.znajdz_u( uzid )
      ich = self.find_by_uzytkownik_id( uzid )
      unless ich 
        self.nadąż_za_użytkownikiem
        ich = self.find_by_uzytkownik_id( uzid )
      end
      ich
    end
    
    def widoczne
      wi = []
      @@poziomy_x.each { |poziom|
        wi << poziom if self.send( "#{poziom}?" )
      }
      return wi
    end # of #{widoczne}

    def verifiables( akat )
      sensowne = []
      as = akat.statuski
      as.each_index{ |i|
        sensowne << @@poziomy_x[i] if ( 8...16 ).include?( as[i] )
      }
      return sensowne
    end #of #{verifiables}

    def anotables( akat, rola_id )
      sensowne = []
      if Rola.zarzadca?( rola_id )
        maxim = 16
      else
        maxim = 14
      end
      as = akat.statuski
      as.each_index{ |i|
        sensowne << @@poziomy_x[i] if (0...maxim).include?( as[i] )
      }
      return sensowne
    end# of #anotables

    def anotaśne( akat, rola_id )
      sensowne = []
      if Rola.zarzadca?( rola_id )
        picipolo = 0...16
      else
        picipolo = STATI[ :anotaśne ]
      end
      as = akat.statuski
      as.each_index{ |i|
        sensowne << @@poziomy_x[i] if picipolo.include?( as[i] )
      }
      return sensowne
    end# of #anotaśne

    ##    def pokaźne( akat, rola_id )
    ##      ano = self.anotables( akat, rola_id )
    ##      wido =  self.widoczne
    ##      if ano & wido == []
    ##        (  wido + ano  ).uniq
    ##      else wido
    ##      end
    ##    end # of #{pokaźne}
    
    def z_pokaźnymi( akat, rola_id )
      z_poka = PoziomyAnotacji.new
      coś_wybrano = false

      self.attributes.each{ |key, val| # #dup jest za słabe.
        z_poka.send( "#{key}=", val #self.send( key ) 
                     ) unless "#{key}" == 'poziomy_anotacji_id'
        coś_wybrano = true if self.send( key ).class == TrueClass # korzystamy z~tego, że tylko kolumny poziomów mogą przyjmować wartości Boolowskie.
      }
      
      unless coś_wybrano
        ano =  self.anotaśne( akat, rola_id )
        ano = DZIAŁAJĄCE unless ano[0]
        ano.each{ |poz|
          z_poka.send( "#{poz}=", true ) }
      end

      z_poka
    end #of #{z_pokaźnymi!}
    
    def colspan
      #      wi = widoczne
      #      cs = wi.size
      #     cs -= 1 if wi.include?( :segmentation )
      #     cs -= 1 if wi.include?( :word_senses ) # sensy są w tej samej kolumnie co mf,
      #     cs += 1 if wi.include?( :syntactic )# składniowa jest w 2 kolumnach
      cs = 1 # morfosyntaks i ew. sensy
      cs += 2 if self.syntactic?
      return cs
    end

    def set_poziom( poziom, vartosc )
      self.send( "#{poziom}=", vartosc )
    end

    def trues
      @@poziomy_x.collect { |poz| 
        if self.send( "#{poz}?") : poz
        else nil
        end}.
        compact
    end


  
    def self.nadąż_za_użytkownikiem
      Uzytkownik.natror # żeby zainicjować
      self.connection.execute " insert into poziomy_anotacji( created_at, uzytkownik_id ) " +
        " select current_timestamp, u.uzytkownik_id from " + 
        " uzytkownik u left outer join poziomy_anotacji po " +
        " on u.uzytkownik_id=po.uzytkownik_id " +
        " where po.uzytkownik_id is null "
      
      self.connection.execute " delete from poziomy_anotacji " +
        " where uzytkownik_id in " +
        " ( select po.uzytkownik_id from poziomy_anotacji po left outer join uzytkownik u " +
        " on u.uzytkownik_id=po.uzytkownik_id " +
        " where u.uzytkownik_id is null ) "
      true
    end # of #{self.nadąż_za_użytkownikiem}

    
    def self.tylko_działające
      niedziałające = NIE_DZIAŁAJĄCE
      i=0
      self.find( :all ).each{ |po|
        niedziałające.each{ |nd|
          if po.send( "#{nd}?" )
            po.send( "#{nd}=", false )
            po.save!
            i += 1
          end
        }
      }
      return i
    end # of #{tylko_działające}

   
end


### Local Variables: 
### mode: ruby
### End:
