# == Schema Information
# Schema version: 51
#
# Table name: akapit
#
#  akapit_id               :integer         primary key
#  morph_id                :integer         not null
#  path_id                 :integer         not null
#  segmentation_xmlid      :text            
#  segmentation_xlink_href :text            
#  morphosyntactic_xmlid   :text            
#  created_at              :timestamp       
#  updated_at              :timestamp       
#  tresc                   :text            
#  incipit                 :text            
#

 #
 # 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.
 #

require 'ramkowanie'

class Akapit < ActiveRecord::Base
  
  belongs_to :morph
  has_many :token,  :order => "kolejnosc", :conditions => { :chosen => true }
  has_many :token_all, :class_name => "Token",  :order => "kolejnosc"

  has_many :token_incipny, :class_name => "Token", 
  :select => "akapit_id, token_id, orth, ns_nastepuje, ns_poprzedza",
  :conditions => { :chosen => true },
  :order => "kolejnosc",
  :limit => 11

  # „Wyjście morfoskładni ma nie zawierać segmentów odrzuconych. 
  # Informacja o~wszystkich wariantach segmentacyjnych jest tylko w~\file{ann_segmentation.xml}
  has_many :token_rejected, :class_name => "Token",  :order => :kolejnosc,
  :conditions => { :chosen => false }

  has_many :akapit_transzy, :order => "transza_id"
  has_one :akat0, :class_name => "AkapitTranszy", 
  :conditions => " akapit_transzy_id = (select min(akapit_transzy_id) from akapit_transzy atx where " +
    " atx.akapit_id = akapit_transzy.akapit_id )"

  has_many :statusy
  has_one :stat0, :class_name => "Statusy", :conditions => 
    "statusy_id = (select min( statusy_id ) from statusy sx where sx.akapit_id = statusy.akapit_id) " 

  has_many :komentarz, :order => :created_at

  has_many :token_segm, :class_name => "Token", :order => :kolejnosc,
  :conditions => "sg_choice_id is not null"
  # Uwaga! To wybiera także tokeny odrzuconych wariantów segmentacji, i~tak właśnie ma i~musi być.

  has_many :token_sup,  :class_name => "Token", :order => :kolejnosc,
  :conditions =>  "superancja is not null"

  has_many :sg_choice

  has_many :chosen_interps, :class_name => "Token", 
  :order => "kolejnosc", :conditions => {:czy_interp => true, :chosen => true}

  belongs_to :path

  has_many :końce_zdań, :class_name => "Token", :order => :kolejnosc,
  :conditions => { :czy_konczy_zdanie => true, :chosen => true }

  has_many :token_sens, :class_name => "Token", :order => :kolejnosc,
  :conditions => " exists ( select interpretacja_id from interpretacja i " +
    " where i.disamb='t' and i.cz_m_leksem_id is not null " +
    " and i.token_id=token.token_id )"


  
  def treść_z_tokenów( tokeństwo = :token )
    t166=self.send( tokeństwo ).reload
    (t166.collect{|t167|
       t167.orth +
       ( if t167.czy_konczy_zdanie? : ' ■'
         else ''
         end ) +
       (if t167.ns_nastepuje?
          # metoda bez znaku zapytania może źle działać przy niektórych bazach danych:
          # tam, gdzie fałsz jest przechowywany jako 0 ( if 0 => true )
          '' 
        else ' '
        end)
     }).join.strip + if tokeństwo == :token
                       ''
                       else '…'
                       end
  end # of #{treść_z_tokenów}


  def treść_pełna_spacjowana
    t168=self.token_all.reload
    (t168.collect{|tok169| tok169.orth }).join(' ').strip
  end # of tresc


  def treść_idowana
    t170=self.token.reload
    t170.collect {|tok171| "#{tok171.orth}(#{tok171.id})" }.join
  end # of #treść_idowana


  def tokslex
    # zwraca tablicę tokenów z interpretacjami:
    ## [
    ##    [orth1, interp11, interp12, …]
    ##    [orth2, interp21, interp22, …]
    ## …]
    self.token.reload.collect{|token|
      tl=Array.new
      tl<<(token.orth)
      token.interpretacja.each{|interpretacja|
        tl<<(if interpretacja.disamb 
               "&#x25b8; "
# >, x10fb georgian par. separator, x2023 triangle right, x203b X z czterema kropkami (reference mark)
# x25b8 small triangle right (bigger than the previous)

             else
               "&nbsp; &nbsp;"
             end +
             if interpretacja.disamb 
               "<b>"
             else
               ""
             end + 
             "<i>" +interpretacja.leksem.lemat + "</i> " +
             interpretacja.leksem.klasa_gram.klasa_gram_ozn +
             interpretacja.reszta_tagu +
             if interpretacja.disamb 
               "</b>"
             else
               ""
             end
             )
      }
      tl
    }
  end # of #{tokslex}.


  def self.zaanotowane( status_symbol=:zakończony, clauses_hash={} )
    # wynik ma dodatkową kolumnę uzid równą mniejszemu z identyf. użytkownika (o ile takowe występują)
    # Porządkujemy wg corpus_path_id, żeby wypisywać w chunkach-ścieżkach
    # pierwszy argument może też być dwuelementową tablicą [:status_od, :status_do]
    # a drugi argument to hash pseudo-opcji  :pogrupuj, :where i :having jak na razie.
    # Uwaga. Ta metoda zwróci także akapit odrzucone. Aby pominąć odrzucone, należy 
    # podać pseudo-opcję where => " zt.odrzucone = 'f'"

    logger.info "@@@@ szukam zaanotowanych: " + Time.now.to_s( :db )

    ssym = status_symbol
    ch = clauses_hash

    if status_symbol.kind_of?( Hash )
      ssym = ( status_symbol[ :status_symbol] || :zakończony )
      ch = status_symbol
      
    elsif PoziomyAnotacji.poziomy_x.include?( ssym )
      ch[ :poziom ], ssym = ssym,  :zakończony
    end

    betw = AkapitTranszy.status_betw( ssym )
       
    if poz = ( clauses_hash[ :poziom ] || clauses_hash[ :poziomy ] )
      # jeśli hasz parametrów zawiera klucz #{:poziom} lub #{:poziomy}, wybierzemy tylko akapity o~zadanym statusie na tym poziomie\di/tych poziomach anotacji, a~jeśli nie zawiera — to o~zadanym statusie na jakimkolwiek poziomie anotacji.
      kriterion = [ poz ].flatten.collect { |poz| " ( s.#{poz} #{betw} ) " }.join(" or ")
    else
      kriterion = PoziomyAnotacji.działające.collect{ |poz|
        " ( s.#{poz} #{betw} ) " }.
        join(" or ")
    end
    
    ##    uzidy = PoziomyAnotacji.poziomy_x.collect {    }
    # co Autor miał na myśli? chyba nic szczególnego, skoro z tego zrezygnował.

    if true # spróbowałem prewybierać tokeny, ale to wydłużyło ogólny czas renderowania widoku (i~czas wykonania tego zapytania oczywiście).
      sql = "select akapit.* " +
        " from akapit inner join statusy s using( akapit_id ) " +
        " where  ( #{kriterion} ) " +
        if clauses_hash[:where] : " and " + clauses_hash[:where]
        else ""   end +
        " group by akapit_id " +
        if clauses_hash[:having] : " having " + clauses_hash[:having]
        else "" end +
        " order by akapit_id "
    else
      h195 = {
        ##        :select => " akapit.*, token.* ",
        # nie ma potrzeby: Rails wybiorą wszystkie kolumny z~#akapit i~#{token}, nazywając je zresztą po swojemu

        :from => " (akapit inner join statusy s using( akapit_id ))  ", ##+
        ##        " inner join token using( akapit_id ) ",
        # #token zostanie dołączony przez #{:nclude} 
        
        :conditions =>         " ( #{kriterion} ) " + ## and token.chosen='t' 
        #        warunek  na #token wybrany znajdzie się w~warunku złączenia dodanego przez #{:include}
        if clauses_hash[:where] : " and " + clauses_hash[:where]
        else ""   end ,

        :group => "  akapit.akapit_id, token_id " + # bez #token_id zwracało po jednym przypadkowym tokenie
        if clauses_hash[:having] : " having " + clauses_hash[:having]
        else "" end ,
        
        ##        :order => " akapit.akapit_id, token.kolejnosc",
        :include => :token
      }
    end

    logger.info h195.inspect
    ##    wynik195 = self.find( :all, h195 )
    wynik195 = self.find_by_sql( sql )
    logger.info "@@@@ po wyszukaniu zaanotowanych: " + Time.now.to_s( :db ) +
      " (znalazłam #{wynik195.size})"
    return wynik195
    
  end # of #{self.zaanotowane}.


  def self.quasi_transza( limits )
    self.zaanotowane(
                     :zakończony, 
                     :where => " akapit.akapit_id between #{limits[0]} and #{limits[1]} " )
  end # of #{quasi_transza}.



  def xml_id
    if self.original_id : return self.original_id
    else return self.akapit_id.to_s 
    end
  end


  def self.init_minmax
    if (not  defined?( @@min_id )) or (not defined?( @@max_id ) )
      @@min_id = self.find_by_sql("select min(akapit_id) as lim from akapit")[0].lim.to_i
      @@max_id = self.find_by_sql("select max(akapit_id) as lim from akapit")[0].lim.to_i
    end
  end

  def self.min_id
    init_minmax
    return @@min_id
  end

  def self.max_id
    init_minmax
    return @@max_id
  end


  def dolicz_sensy_zweryf( param=nil )
    mozna=true
    unless param
      zt0=akapit_transzy[0]
    if zt.ma_status?(:>=, :zweryfikowany) and
        not zt.odrzucone?
      param = zt0.akat_hash
    else
      mozna=false
    end
    end# of #{unless param}.
    
    if mozna
      token.each{ |tok172|
        sa = SensAnot.znajdz( tok172.token_id, param )
        
        if sa
          sasl =  sa.sensy_leksemu
          sasl.sens_zweryf_count +=1
          sasl.save
        end # of #{if sa},
      }
    end#of #{if mozna},
  end# of #{dolicz_sensy_zweryf}.


  def self.autozatwierdź_segmentation ## ( akapit_od, akapit_do )
    # procedura, która akapit o jednoznacznej segmentacji oznaczy (nada status) jako zweryfikowany na poziomie segmentacji
    if self.find( :first ) and self.
        find_by_sql( 
                    [ "select count( distinct akapit_id ) as ile from statusy where " +
                     " not exists (select * from sg_choice sgc where " +
                      " sgc.akapit_id=statusy.akapit_id) and " +
                      " segmentation>=?",
                      AkapitTranszy::STATI[ :zweryfikowany ]] 
                    )[ 0 ].ile.to_i < 
        self.
        find_by_sql(
                    "select count( distinct akapit_id ) as ile from statusy where " +
                    " not exists (select * from sg_choice sgc where " +
                    " sgc.akapit_id=statusy.akapit_id) " )[0].ile.to_i
      # jeżeli liczba akapitów sg-zweryfikowanych jest mniejsza od (liczby akapitów zatranszowanych pomniejszonych o~liczbę akapitów nie mających wariantów segmentacyjnych) to:
      
      natror_id = Uzytkownik.natror.id

      self.find( :all, :conditions => 
                 " (select min(segmentation) from statusy s " +
                 " where s.akapit_id=akapit.akapit_id)" +
                 "<16 and not exists "+
                 " (select * from sg_choice sgc where sgc.akapit_id=akapit.akapit_id) "
                 ## { :akapit_id => akapit_od..akapit_do } 
                 ).each { |aka|
        if aka.akat0 and not aka.token_segm.reload[ 0 ]
          puts "#{aka.id}:"
          aka.akapit_transzy.each{ |akat|
            if akat.ma_status?( :segmentation, :<, :zweryfikowany )
              akat.set_status( :segmentation, :zweryfikowany, :tylko_to, natror_id )
              akat.propaguj_dopuszczalność( :segmentation )
              puts "       #{akat.id}"
            end
          }
        else puts "#{aka.id} ma warianty segmentacyjne lub nie jest zatranszowany"
        end
      }# of #{each aka},
      return true
    else
      return false
    end# of main #if
  end# of #{self.autozatwierdź_segmentation}.


  def self.ile_do_segmentacji
    # działa dobrze: sprawdzone przez \sql{select count(*) from (select distinct akapit_id from token where czy_segm='t');}
    self.find_all.collect do |aka|
      if aka.token_segm.reload[ 0 ]
        true
      else nil
      end
    end. # of #{collect aka}
      compact.size
  end# of #{self.ile_do_segmentacji}.


  ##  dopuść_posegmentowane 
  # \gobble{dowcip polegał na tym, że przy inicjalizacji tej klasy przy wlewaniu danych do bazy #{dopuść_posegmentowane} wykonywało się pusto.}

  def self.zaznacz_końce_ostatnich_zdań ## ( akapit_od, akapit_do )
    logger.info "@@@@ zaznaczam końce_ostatnich_zdań"
    końce_nie_zaznaczone = " select akapit_id " +
      " from akapit left outer join koniec_zdania_anot using( akapit_id ) " +
      " where koniec_zdania_anot_id is null " ## +
    ## " and akapit_id between #{akapit_od} and #{akapit_do}"
    if self.find_by_sql( " select 1 where exists (#{końce_nie_zaznaczone})" )[0]
    
      natror_id = Uzytkownik.natror.id
      AkapitTranszy.find( :first ) # iżby zainicjować

      logger.info "@@@@ naprawdę zaznaczam"
      self.connection.execute " insert into koniec_zdania_anot " +
        " ( created_at, akapit_id, akapit_transzy_id, uzytkownik_id, token_id ) " +
        " select current_timestamp, akapit_id, atr.akapit_transzy_id, #{natror_id}, token_id " +
        " from akapit_transzy atr inner join token t using( akapit_id ) " +
        " where token_id in " +
        " ( select max( token_id ) from token  " +
        " where akapit_id in (#{końce_nie_zaznaczone}) group by akapit_id) "
      # tu jest śliskość: opieramy się na porządku id-ów, a~tymczasem  decydująca jest \sql{kolejnosc}. Ale robimy to wyłącznie na danych dziewiczych, dla których \sql{kolejnosc}  i~\sql{token_id} są zgodne.
      true
    end # of main #if
  end # of #{self.zaznacz_końce_ostatnich_zdań}
  
  
  def self.zdezambiguuj_interpunkcje ## ( akapit_od, akapit_do )
    punteggiature_ambigui = "select interpretacja_id " +
      " from interpretacja inner join token using( token_id ) " +
      " where czy_interp='t' and ( disamb is null or disamb='f') " ## +
    ## " and akapit_id between #{akapit_od} and #{akapit_do}"
    
    if self.find_by_sql( " select 1 as esistenza where exists (#{punteggiature_ambigui}) ")[0]
      self.connection.execute " update interpretacja set disamb='t' " +
        " where interpretacja_id in ( #{punteggiature_ambigui} ) "
      true
    end
  end # of #{self.zdezambiguuj_interpunkcje}.

  ##  zdezambiguuj_interpunkcje


  text = '
  @tokXXXs = nil

  def tokXXXs
    unless @tokXXXs and @tokXXXs.size == self.token.reload.size
      @tokXXXs = self.token.collect{ |tNRNR| tNRNR.XXX }
    end
    @tokXXXs
  end' # of #{tokids} i #{tokorths} instance methods.

eval text.gsub( 'XXX', 'id' ).gsub( 'NRNR', '173' )
eval text.gsub( 'XXX', 'orth' ).gsub( 'NRNR', '174' )
   
  def czy_posegm?
    self.akat0.ma_status?( :segmentation, :>=, :zweryfikowany )
  end



  def self.autozatwierdź_word_senses
    # procedura, która akapit o jednoznacznej segmentacji oznaczy (nada status) jako zweryfikowany na poziomie segmentacji
    Statusy.autozatwierdź_word_senses
  end# of #{self.autozatwierdź_word_senses}.

 
  def tree3levels
    # Zwrócimy drzewo, tj. tablicę tablic: tablicę zdań, z~których każde jest tablicą tokenów i~#{sg_choice}'ów

    tok_choice = self.token.dup

    self.token_segm.each { |ts|
      tok_choice[ self.tokids.index( ts.id ) ] = ts.sg_choice if ts.chosen?
    } # of each #{token_segm}
    # teraz #tok_choice jest tablicą tokenów i~#{choice}'ów.

    prev_index = 0
    sentences = self.końce_zdań.collect {|tok176|
      # zastępujemy token kończący zdanie przez tablicę tokenów od poprzedniego końca zdania do tego.
      curr_index = self.tokids.index( tok176.id )
      # uwaga: metoda #{token} zwraca tablicę złożoną tylko z~tokenów wybranych, ale możemy być pewni, że każda niejednoznaczność segmentacyjna (element #{choice}) ma w~tej tablicy reprezentanta.

      ##      puts "@@@@ akapit #{self.id}, tok176.id==#{tok176.id}"

      differance = curr_index - prev_index + 1
      start_index,  prev_index = prev_index, curr_index + 1
      tok_choice[ start_index, differance ].uniq # #uniq  żeby usunąć ewentualne duplikaty #{sg_choice}'ów.
    } # of #{końce_zdań.collect}

  end # of #{tree3levels}


  def tree2levels
    # Zwrócimy drzewo, tj. tablicę tablic: tablicę zdań, z~których każde jest tablicą (wybranych!) tokenów.
    
    prev_index = 0
    
    tok = self.token
    
    sentences = self.końce_zdań.collect {|tok176|
      # zastępujemy token kończący zdanie przez tablicę tokenów od poprzedniego końca zdania do tego.
      curr_index = self.tokids.index( tok176.id )
      # uwaga: metoda #{token} zwraca tablicę złożoną tylko z~tokenów wybranych, ale możemy być pewni, że każda niejednoznaczność segmentacyjna (element #{choice}) ma w~tej tablicy reprezentanta.

      ##      puts "@@@@ akapit #{self.id}, tok176.id==#{tok176.id}"

      differance = curr_index - prev_index + 1
      start_index,  prev_index = prev_index, curr_index + 1
      tok[ start_index, differance ]
    } # of #{końce_zdań.collect}

  end # of #{tree2levels}



  
  def responsibles3levels
    ## [segmentation, sentences, morphosyntactic ]
    [ :segmentation, :sentences, :morphosyntactic ].collect{ |poz|
      self.akapit_transzy.collect{ |a| 
        if anorka = a.anotatorka( poz )
          anorka.login
        end
      }.compact.join( ' + ')
    }
  end # of #{responsibles3levels}


 def tree_word_senses
    # Zwrócimy drzewo, tj. tablicę tablic: tablicę zdań sensowanych, z~których każde jest tablicą tokenów sensownych.
   # każde zdanie\dy tabliczka tokenów sensownych jest ubogacone na końcu tokenem swego końca (który nie musi być sensowny, a~gdyby był sensowny, to zostaje powtórzony).
   tok_sens = self.token_sens.dup
   
   if tok_sens[0]
     # aby podzielić tokeny sensowne na zdania, patrzymy na ich #{kolejnosc} i~odcinamy te, u~których jest ona mniejsza niż #kolejnosc kolejnego końca zdania.
     sentences = self.końce_zdań.collect {|tok176|
       # zastępujemy token kończący zdanie przez tablicę tokenów sensownych od poprzedniego końca zdania do tego.
       curr_sent = []
       
       while  tok_sens[0] and tok_sens[0].kolejnosc <= tok176.kolejnosc
         curr_sent << tok_sens.delete_at( 0 )
       end # of while
       if curr_sent[0]
         curr_sent << tok176 # to zwraca #{curr_sent}.
       else
         nil
       end         
     }.compact # of #{końce_zdań.collect}
     
     else
       return nil
     end
  end # of #{tree_word_senses}

  
  def responsibles_word_senses
    # zwraca string loginów anotatorek \ac{WSD} „Kizia + Mizia”.
    self.akapit_transzy.collect{ |a| 
      if anorka = a.anotatorka( :word_senses )
        anorka.login
      end
    }.compact.join( ' + ')
  end # of #{responsibles_word_senses}


  def self.skomentowane( wszystkie=nil )

    self.find_by_sql( "select j0.*, min(k2.akapit_transzy_id) as akapit_transzy_id from (" +
                      " select akapit.*, max(k.created_at) as kcrea " +
                      " from akapit inner join komentarz k using(akapit_id) " +
                      unless wszystkie : " where k.nowy = 't' " else '' end +
                      " group by akapit_id) as j0 " +
                      " inner join komentarz k2 " +
                      " on j0.kcrea=k2.created_at and j0.akapit_id=k2.akapit_id " +
                      " group by j0.akapit_id, kcrea order by kcrea "
                      )
  end # of #{self.skomentowane}
  

  @@strictease = Proc.new { |orths|
    if orths[-1] == :strict
      strict = orths.delete_at( -1 )
    else
      strict = nil
    end
    strict
  }

  @@orths_multijoin = Proc.new { |o215|
    sq215 = "" 
# sprawdziłem doświadczalnie: zwraca jedną kolumnę imieniem \sql{akapit_id}.
      o215.each_index { |i215| 
      if i215 > 0 
        sq215 += " inner join "
      end
      sq215 += "  token t#{i215}  "
      if i215 > 0
        sq215 += " on t#{i215-1}.akapit_id = t#{i215}.akapit_id "
      end
    }
    sq215 += " where "
    o215.each_index { |i215| 
      if i215 > 0
        sq215 += " and "
      end
      sq215 += " t#{i215}.orth=? "
    }
    sq215
  }


  @@orths_intersect = Proc.new { |o215|
    sq215 = "" 
# sprawdziłem doświadczalnie: zwraca jedną kolumnę imieniem \sql{akapit_id}.
      o215.each_index { |i215| 
      if i215 > 0 
        sq215 += " intersect "
      end
      sq215 += " select akapit_id from token where orth=? "
    }
    sq215
  }


  def self.znajdź_po_orthach( *orths )
    strict = @@strictease.call( orths )
    o = orths.join(' ').split
    ##    sq = " select t0.akapit_id from " + @@orths_multijoin.call( o )
    sq = @@orths_intersect.call( o )
    a = Akapit.find_by_sql( [" select * from akapit where akapit_id in (#{sq})", o].flatten )
    if strict
      a.collect { |x| if Regexp.new( Regexp.escape( o.join(' ') ) ) =~ x.treść_pełna_spacjowana : x end }.compact
    else
      a
    end
  end # of #znajdź_po_orthach


  def są_orthy?( *orths )
    strict = @@strictease.call( orths )
    o = orths.join(' ').split
    ##    sq = " select 1 from  " + @@orths_multijoin.call( o ) + " and t0.akapit_id=? "
    sq = " select 1 from ( " + @@orths_intersect.call( o ) + " ) where akapit_id=? "
    tid = Token.find_by_sql( [ sq, o, self.id ].flatten )[0]
    
    unless tid
      return false
    else # czyli zapytanie zwróciło rekord
      if strict
        if Regexp.new( Regexp.escape( o .join(' ') ) ) =~ self.treść_pełna_spacjowana 
          return true
        else return false
        end
      else # nie ścisłe, tj. nie musi być dopasowane w tej kolejności 
        return true
      end
    end 
  end # of #sprawdź_orthy
  


  def superancje
    # zwracamy hasz indeksowany symbolami poziomów, którego wartościami są tablice  tokenów zasuperowanych na danym poziomie.
    supy177 = Hash.new
    
    self.token( :refresh ).each{ |tok177|
      if ts177 = tok177.superancja
        ts177.each { |s177|          (supy177[s177] ||= []) << tok177 }
      end
    }

    supy177
    
  end # of #superancje


  @atrids, @trids = nil, nil

  def init_atrids
    unless @atrids and @trids
      @atrids, @trids = [], []
      self.akapit_transzy.each { |atr|
        @atrids << atr.id
        @trids << atr.transza_id
      }
      @atrids_join = @atrids.join(', ')
      @trids_join = @trids.join(', ')
      true
    end
  end

  
  def atrids_join
    init_atrids
    @atrids_join
  end
  
  def trids_join
    init_atrids
    @trids_join
  end
  
  # #dopuść_wsd jest metodą klasy #{Statusy}, odpalaną przy jej inicjacji.

  PF_OFFSET = 10
  # możliwe, że dla różnych poziomów anotacji ten offset powinien być rozmaity.

  def set_primafalsa( верыф, примафальса )
    tids = self.tokids
    if примафальса.kind_of?( Token )
       примафальса =  примафальса.id
    end
    primafalsa_index = tids.index( примафальса ).to_i
    if ( prima_off = primafalsa_index - PF_OFFSET ) >= 0
      верыф[ :primafalsa ] = tids[ prima_off ]
    end
  end # of #{set_primafalsa}


  def primus_sensibilis
    # uwaga! to działa wyłącznie po weryfikacji na poziomie \ac{MS}.
    ##    Token.find_by_sql( ["select * from token where kolejnosc=(select min( kolejnosc ) from token t inner join interpretacja i using( token_id) where i.disamb='t' and i.cz_m_leksem_id is not null and t.akapit_id=?)", self.id] )[0]
    self.token_sens.reload[0]
  end # of #{primus_sensibilis}


  def self.ile_pobranych
    self.find_by_sql(
                     " select count( distinct akapit_id ) as ile from akapit_transzy a " + 
                     " inner join transza t using( transza_id ) " +
                     " where t.uzytkownik_id is not null "
                     )[0].ile.to_i
  end # of #slef.ile_pobranych

  
  def update_treści
    self.tresc = self.treść_z_tokenów
    logger.info "@@@@ treść: " + self.tresc
    self.incipit = self.treść_z_tokenów( :token_incipny )
    logger.info "@@@@ incipit: " + self.incipit
    self.save!
  end
  
  
  def self.update_treści_null
    ret203 = false
    self.find_all_by_incipit( nil ).each { |aka203|
      puts "incipczę #{aka203.id}"
      aka203.update_treści
      ret203 = true unless ret203
    }
    return ret203
  end


  # #{self.usuń_puste} jest niepotrzebne: wypluwka się generuje i dla pustych.
  # w przypadku decyzji o użyciu tych metod do czasu obsługi płatnej doliczyć 15 min.

  def self.puste
    where213 = " where akapit_id in (select akapit_id from akapit a where not exists " +
      " (select * from token where akapit_id=a.akapit_id))"
    self.find_by_sql( " select * from akapit " + where213 )    
  end # of #{self.puste}
 
  def self.usuń_puste
    c213 =  self.connection
    where213 = " where akapit_id in (select akapit_id from akapit a where not exists " +
      " (select * from token where akapit_id=a.akapit_id))"

    c213.execute( "delete from statusy " + where213 )
    c213.execute( "delete from akapit_transzy " + where213 )
    c213.execute( "delete from akapit " + where213 )

  end # of #{self.usuń_puste}

  
end # of class.


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