# coding: utf-8

# This file is a part of TaCo: a morphosyntactic tagset converter
#
# License: GPL v. 3
# Author: Bartosz Zaborowski
#

require "#{File.dirname(__FILE__)}/helpers"

class TabMaker

CONTEXT_CAPS = true

OUTPUT_ORTH_FIX = true

def self.get_special_headers opts, special = "special"
  ret = []
  slcs = opts[:special_left_context_size]
  srcs = opts[:special_right_context_size]
  ret += (0..slcs).map{|x| special+"_base_#{x-slcs}"}
  ret += (1..srcs).map{|x| special+"_base_#{x}"}
  ret += (0..slcs).map{|x| special+"_orth_#{x-slcs}"}
  ret += (1..srcs).map{|x| special+"_orth_#{x}"}

  ret += (1..opts[:special_base_prefix_size]).map{|x| special+"_base_prefix_#{x}"}
  ret += (1..opts[:special_orth_prefix_size]).map{|x| special+"_orth_prefix_#{x}"}
  ret += (1..opts[:special_base_suffix_size]).map{|x| special+"_base_suffix_#{x}"}
  ret += (1..opts[:special_orth_suffix_size]).map{|x| special+"_orth_suffix_#{x}"}
  ret
end

def self.decode_special attrname, specials, value
  return "<null>" if value == "-"
  specials.each_pair do |k, v|
    next if k == :options
    if attrname =~ /#{k}_-?[0-9]+/
      pos = attrname[attrname.rindex("_")+1..-1].to_i
      pos += specials[:opts][:special_left_context_size] if k == "special_orth" || k == "special_base"
      return "'#{v[pos][value.to_i]}'"
    end
  end
  puts attrname.inspect
  puts specials.keys.inspect
  puts value
  raise
end

def self.get_special_values arr, i, opts, special_bases, special_orths, special_base_prefixes, special_orth_prefixes, special_base_suffixes, special_orth_suffixes
  ret = []
  slcs = opts[:special_left_context_size]
  srcs = opts[:special_right_context_size]

  ret += (0..slcs).map {|x| (special_bases[x].index(arr[i+x-slcs].first.base.downcase) || "-").to_s}
  ret += (1..srcs).map {|x| (special_bases[x+slcs].index(arr[i+x].first.base.downcase) || "-").to_s}
  ret += (0..slcs).map {|x| (special_orths[x].index(arr[i+x-slcs].first.orth.downcase) || "-").to_s}
  ret += (1..srcs).map {|x| (special_orths[x+slcs].index(arr[i+x].first.orth.downcase) || "-").to_s}

  ret += (1..opts[:special_base_prefix_size]).map{|x| (special_base_prefixes[x].index(arr[i].first.base.downcase.prefix(x)) || "-").to_s}
  ret += (1..opts[:special_orth_prefix_size]).map{|x| (special_orth_prefixes[x].index(arr[i].first.orth.downcase.prefix(x)) || "-").to_s}
  ret += (1..opts[:special_base_suffix_size]).map{|x| (special_base_suffixes[x].index(arr[i].first.base.downcase.suffix(x)) || "-").to_s}
  ret += (1..opts[:special_orth_suffix_size]).map{|x| (special_orth_suffixes[x].index(arr[i].first.orth.downcase.suffix(x)) || "-").to_s}
  return ret
end



def self.make_column_names tagset_in, tagset_out, options
  attrs_l = (0..(options[:left_context_size]-1)).to_a.reverse.map{|x| tagset_in.attrnames.map{|y| "l_in_#{y}_#{x}"}}.flatten
#  attrs_in = tagset_in.attrnames.map{|x| "in_#{x}"}
  attrs_r = (0..(options[:right_context_size]-1)).to_a.map{|x| tagset_in.attrnames.map{|y| "r_in_#{y}_#{x}"}}.flatten

#  attrs_l = (0..(options[:left_context_size]-1)).to_a.reverse.map{|x| "l_in_#{x}"}.flatten
  attrs_in = ["in"]
#  attrs_r = (0..(options[:right_context_size]-1)).to_a.map{|x| "r_in_#{x}"}.flatten



  specials = []
  specials = get_special_headers options

  orth = []
  if OUTPUT_ORTH_FIX
    if CONTEXT_CAPS
      orth += (0..(options[:left_context_size]-1)).to_a.reverse.map{|x| "l_orth_capital_#{x}"}
      orth << "orth_capital"
      orth += (0..(options[:right_context_size]-1)).to_a.map{|x| "r_orth_capital_#{x}"}
    else
      orth << "orth_capital"
    end
    orth += (1..options[:orth_prefix_size]).map{|x| "orth_prefix#{x}"}

    orth += (1..options[:orth_suffix_size]).map{|x| "orth_suffix#{x}"}
  end

  tag = ["out_tag"]

  return (orth + attrs_l + attrs_in + attrs_r + specials + tag)
end


# arr to tablica par tokenow

def self.make_line arr, i, options, special_bases, special_orths, special_base_prefixes, special_orth_prefixes, special_base_suffixes, special_orth_suffixes
  subarr = arr[i-options[:left_context_size]..i+options[:right_context_size]]
  this_arr = arr[i]

  subarrl = options[:left_context_size] == 0 ? [] : arr[i-options[:left_context_size]..i-1]
  subarrr = arr[i+1..i+options[:right_context_size]]

  attrs = subarrl.map {|a| a.first.positional_tag.map{|x| x.nil? ? "-" : x}}.flatten
  attrs << arr[i].first.tag
  attrs += subarrr.map {|a| a.first.positional_tag.map{|x| x.nil? ? "-" : x}}.flatten
#  attrs = subarr.map {|a| a.first.positional_tag.map{|x| x.nil? ? "-" : x}}.flatten
#  attrs = subarr.map {|a| a.first.tag}.flatten

  specials = []
  specials = get_special_values arr, i, options, special_bases, special_orths, special_base_prefixes, special_orth_prefixes, special_base_suffixes, special_orth_suffixes

  orth = []
  if OUTPUT_ORTH_FIX
    if CONTEXT_CAPS
      orth += subarr.map{|a| (a.first.orth[0] || "").upcase == a.first.orth[0] ? "t" : "f"}
    else
      orth << (this_arr.first.orth[0].upcase == this_arr.first.orth[0]) ? "t" : "f"
    end
    
    this_orth = this_arr.first.orth
    orth += (1..options[:orth_prefix_size]).map{|x| "'"+this_orth.prefix(x).downcase+"'"}

    orth += (1..options[:orth_suffix_size]).map{|x| "'"+this_orth.suffix(x).downcase+"'"}
  end

  begin
    tag = [this_arr.last.tag]
  rescue
    puts i
    puts subarr.inspect
    puts this_arr.inspect
    iii = arr.index{|a,b| a.orth.downcase != b.orth.downcase}
    puts "zlei #{iii}"
    puts arr[iii-1..iii+2]
    throw
  end
  return (orth + attrs + specials + tag)
end

# sents to tablica zdan
def self.make_tab sents, options = {}, special_orths = nil, special_bases = nil, special_orth_prefixes = nil, special_base_prefixes = nil, special_orth_suffixes = nil, special_base_suffixes = nil

  options[:special_left_context_size] ||= -1
  options[:special_right_context_size] ||= -1
  options[:special_orth_prefix_size] ||= 0
  options[:special_base_prefix_size] ||= 0
  options[:special_orth_suffix_size] ||= 0
  options[:special_base_suffix_size] ||= 0
  options[:left_context_size] ||= 0
  options[:right_context_size] ||= 0
  options[:orth_prefix_size] ||= 0
  options[:orth_suffix_size] ||= 0

  columns = make_column_names sents.first.file.corpus.tagset, sents.first.aligned_with.file.corpus.tagset, options
  tokpairs = []
  sents.each do |s|
    s.toks.each_with_index{|t,i| tokpairs << [t, s.aligned_with.toks[i]]}
  end

  maxlcontext = -[-options[:left_context_size], -options[:special_left_context_size]].flatten.min
  maxrcontext = [options[:right_context_size], options[:special_right_context_size]].flatten.max
  left = maxlcontext.times.to_a.map{|x| tokpairs[-x-1]}
  right = maxrcontext.times.to_a.map{|x| tokpairs[x]}

  arr = left+tokpairs+right

  rows = []
  
  tokpairs.length.times do |i_|
    i = i_+maxlcontext
    rows << make_line(arr, i, options, special_bases, special_orths, special_base_prefixes, special_orth_prefixes, special_base_suffixes, special_orth_suffixes)
  end
  return columns, rows
end

end
