# == Schema Information
# Schema version: 51
#
# Table name: interpretacja
#
#  interpretacja_id       :integer         primary key
#  token_id               :integer         not null
#  lex_xmlid              :text            not null
#  msd_xmlid              :text            not null
#  path_id                :integer         not null
#  numer_lex_token        :integer         
#  reszta_tagu            :text            
#  leksem_id              :integer         
#  disamb                 :boolean         
#  dodana                 :boolean         
#  cz_m_leksem_id         :integer         
#  sensy_id               :integer         
#  created_at             :timestamp       
#  updated_at             :timestamp       
#  cz_m_leksem_przypisany :boolean         
#

 #
 # 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 Interpretacja < ActiveRecord::Base
  belongs_to :leksem
  belongs_to :token
  has_many :interpretacja_anot
  has_many :sens_anot
  has_one :sensy

  belongs_to :cz_m_leksem

  has_one :msd_opis, :foreign_key => :leksem_id
  # widok do generowania wypluwki, migr. 051. (2010/2/25)

  # nowo tworzonej interpretacji trzeba przypisać #{cz_m_leksem}. Ale to się przy wlaniu danych odbywa hurtowo. Trzeba więc tylko zadbać o dopisanie go w #{fc_by_fulltag}.
  
  def fulltag
    [self.leksem.klasa_gram.klasa_gram_ozn, self.reszta_tagu].compact.join(':')
  end


  def self.fc_by_fulltag( tokid, lemat, tag )# find or create by full tag
    # Uwaga. Ta metoda dotyka także innych klas i być może tworzy ich obiekty.
    raise "Niepoprawny lemat/tag »#{lemat}«/»#{tag}«" unless Tagset.check_tag( tag, lemat )[0]
    reszta_tagu = tag.split(':')
    kg = reszta_tagu.delete_at( 0 )
    reszta_tagu = if reszta_tagu[0] : reszta_tagu.join(':') end
    # sprawdzamy, czy już jest taka interpretacja:
    # przede wszystkim — czy jest taki leksem
    kg_id = KlasaGram.find_by_klasa_gram_ozn( kg ).id
    conds = { 
      :lemat => lemat,
      :klasa_gram_id => kg_id,
      :path_id => Token.find( tokid ).path_id 
      # tu chodzi o encję leksem, zlokalizowaną do ścieżki korpusu. Ta trójka parametrów określa encję #{leksem} jednoznacznie (jest uniczny indeks).
    }
    le = Leksem.find( :first, :conditions => conds )
    # Jeśli nie — to go tworzymy:
    unless le
      path_id, lex_xmlid, msd_xmlid = self.get_xmlids( tokid, lemat, kg_id ) # \label{interpretacja.rb:43}
      le = Leksem.create!( conds.update(
                                       :lex_xmlid => lex_xmlid
                                       ) )
      CzM.przypisz_leksemom
      le.reload
    end
    # A teraz sprawdzamy, czy jest taka interpretacja:
    conds = {
      :token_id => tokid,
      :leksem_id => le.id,
      :path_id => le.path_id,
      :reszta_tagu => reszta_tagu
    }
    intrpr = self.find( :first, :conditions => conds )
    unless intrpr 
      unless path_id and lex_xmlid and msd_xmlid # mogły zostać pobrane/obliczone w~wierszu \ref{interpretacja.rb:43}.
        old_path_id = nil
        old_path_id = path_id if path_id
        path_id, lex_xmlid, msd_xmlid = self.get_xmlids( tokid, lemat, kg_id )
        if old_path_id and path_id != old_path_id
          raise "@@@@ #Interpretacja.rb 63: path_id=#{path_id.inspect}, old_path_id=#{old_path_id.inspect}"
        end
      end
      intrpr = self.create!( conds.dup.update(
                                             :numer_lex_token => lex_xmlid.split('.')[-1] ,
                                             :disamb => false, # gdybyśmy tę oznaczali jako dyzambiguację w~tabeli interpretacja, to partner dostawałby listę koniecznie do zdezambiguowania — a tego przecież nie chcemy.
                                             :dodana => true,
                                             :lex_xmlid => lex_xmlid,
                                             :msd_xmlid => msd_xmlid,
                                             :path_id => path_id,
                                              :cz_m_leksem_id => le.cz_m_leksem_id  ,
                                              :cz_m_leksem_przypisany => true
                                         ) )
    end # of #{unless intrpr}.
      
    intrpr
  end # of #{self.fc_by_fulltag}


  def self.zainnij( int, interpretacje )
    nry_innych_lt = [ 0 ]
    inne_leksemidy_h = {}
    
    interpretacje.each { |i2| 
      if i2 != int
        nry_innych_lt << i2.numer_lex_token

        inne_leksemidy_h[ i2.leksem_id ] = i2.numer_lex_token
      end 
    }
    # teraz #nr_lt_y zawiera numery lexów naszego tokenu, 
    # zaś #lexids_h zawiera te-ż numery etykietowane #{leksem_id}\dy ami, dla łatwego wyszukania.

    [ nry_innych_lt, inne_leksemidy_h ]
  end# of #{self.zainnij}


  def  zainnij
    @nry_innych_lt, @inne_leksemidy_h = self.class.zainnij( self, self.token.interpretacja )
    [ @nry_innych_lt, @inne_leksemidy_h ]
  end # of instance #zainnij


  def self.get_xmlids( tokid, lemat, kgid )
    # mamy zwrócić tablicę #{[ path_id, lex_id, msd_id ]}.
    # pierwszy — łatwo.
    # z drugim jest subtelniej:  to ma być xmlid elementu <lex>, który ma być taki sam jak innych interpretacji tego tokenu tej encji #{leksem}, albo unikalny. I tak się dzieje.

    logger.info "@@@@ #{tokid.inspect} #{lemat.inspect} #{kgid.inspect}"
    path_id = Token.find( tokid ).path_id

    sql1 = " select interpretacja.* " +
      " from interpretacja inner join leksem using( leksem_id ) " +
      " where token_id=? "
    # #sql1 zwraca wszystkie interpretacje danego tokenu
    sql0 = sql1 + " and lemat=? and klasa_gram_id=?" ## and leksem.path_id=?
    # #sql0 zwraca interpretacje tego samego lex-a.
    ils0 =  self.find_by_sql( [sql0, tokid, lemat, kgid ] ) ##, path_id 
    # \rz4 człon warunku dodany 2009/9/8 po migracji 038, która wedle mego przekonania powinna była eliminować przypadek innej ścieżki dla leksemu niż dla tokenu i interpretacji. Ale tego nie robiła, jak boleśnie okazało się 2009/11/05.
    
    # #{lex_xmlid} ma postać #{\<nr akapitu w~pliku>.\<nr tokenu w~akapicie>.<nr lex-a w~tokenie>}
    # pierwsze dwa człony numeru są dla danego tokenu takie same.
    # #{msd_xmlid} jest j.w. plus #{.\<msd_nr>}
    
    ils1 = []  
    
    if ils0[0] # znaleźliśmy interpretację(e) tego tokenu o~takim leksemie
      path_id0 = ils0[0].path_id.to_i  # to zawsze jest i winna być ta sama #{path_id}.
      #     skoro znaleźliśmy interpretacje tego samego leksemu, to bierzemy max id zwiększony o 1.
      początek_ida = ils0[0].lex_xmlid.split('.')
      lex_id  = początek_ida.delete_at( -1 )
      msd_id = ils0.collect { |il| 
        il.msd_xmlid.split('.')[-1].to_i
      }.compact.max + 1

      logger.info "@@@ get_xmlids — gałązka gdy są idy: msd_id=#{msd_id}"
      
    else # nie ma interpretacyj o takim leksemie (będziemy mieli nowy <lex>)
         logger.info "@@@@ interpretacja w.120 — get_xmlids gałązka gdy nie ma  idów"
      ils1 = self.find_by_sql( [ sql1, tokid ] )
      if ils1[0]
        path_id0 = ils1[0].path_id.to_i # to zawsze jest jedna ścieżka
        początek_ida = ils1[0].lex_xmlid.split('.')[0,2]
        
        nry_lt, h_lt = self.zainnij( nil, ils1 )
        
        lex_id = nry_lt.max + 1
        
      else # ten token nie ma ani jednej interpretacji
        ## {\<akapit_nr>.\<token_nr>.<lex_nr> }
        ##        logger.info "@@@@ interpretacja w.131"
        początek_ida = [ Token.find( tokid ).akapit_id, tokid ]
        path_id0 = path_id
        lex_id = 1
      end
      msd_id = 1
    end

    unless początek_ida # tzn. gdy #ils0 lub #ils1 jest niepusta
      ##      logger.info "@@@@ interpretacja w.140"
      początek_ida = ( ils0 + ils1 ).collect{ |il| il.lex_xmlid.split('.') }.max
      początek_ida[-1] = początek_ida[-1].to_i + 1
      lex_id = początek_ida.delete_at(-1)
    end

    lex_id = (początek_ida + [ lex_id ]).join('.')
    msd_id = [ lex_id,  msd_id ].join('.')
    
    if path_id0 != path_id
      logger.info "@@@@ niespójność danej path_id? dla tokenu #{tokid} i ils0==#{ils0.inspect} i ils1==#{ils1.inspect}: path_id0==#{path_id0}, path_id==#{path_id}" 
    ##    logger.info "@@@@ interpretacja w.148 " +  [ path_id, lex_id, msd_id ].inspect
    end

    # 2010/2/18 to powodowało błąd powtórzonych lex_xmlidów w osobnych <lex>-ach, a chroniło przed błędem powodowanym przez przypisanie #{leksem}u z innej ścieżki.
    # Ale trzeba sprawdzić, czy znaleziony #{lex_xmlid} jest z naszego lex-a, bo jeśli nie, to trzeba utworzyć nowy. Pytanie, czy oprócz nas coś jest w „naszym lexie” rozpatrzono wyżej: #{ils0}
    
    #
    ##    if Leksem.find( :first, :conditions => { 
    ##                      :path_id => path_id, 
    ##                     :lex_xmlid =>  lex_id} )
    ##     pocz_lexida = lex_id.split('.')[0,2].join('.')
    ##     leksid207 = Leksem.find_by_sql( "select lex_xmlid from leksem where path_id=#{path_id} and lex_xmlid like '#{pocz_lexida}.%' ").
    ##       collect { |lex207| lex207.lex_xmlid.split('.')[-1].to_i}.
    ##       max + 1
    ##     
    ##     lex_id = "#{pocz_lexida}.#{leksid207}"
    ##     msd_id = "#{lex_id}.#{msd_id.split('.')[-1]}"
    ##
    ##   end # if found leksem of such ids

    return [ path_id, lex_id, msd_id ]

  end # of #{self.get_xmlids}


  def self.odsmiec( conditions = {} )
    # Usuwanie tagów dodanych a sierocych. Użyte także w klasie Token.
    conditions.merge!( :dodana => true )
    smieci = self.find(
                       :all, :conditions => conditions, :include => :interpretacja_anot
                       ).collect {|inte| 
      inte.id unless inte.interpretacja_anot[0]}.compact
    self.delete( smieci ) if smieci[0]
  end# of #{self.odsmiec}

  
  def cz_m_leksem_id_namierzony
    self.leksem.cz_m_leksem_id_namierzony
  end
  
end


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