# -*- encoding: UTF-8 -*-
# enfeditor version: 1.0.0.0
require 'enfeditor'
require 'logger'
require 'csv'
include EnfEditor

class CSV::Row  
  def valid_for_prop_mapping?
    return false if self[:method].nil?
    method = self[:method].to_sym
    return false unless [:move, :copy, :delete, :create].include?( method )
    if method == :move || method == :copy
      return false if self[:source_key].nil?
      return false if self[:target_key].nil?
    end
    if method == :delete
      return false if self[:source_key].nil?
      return false unless self[:target_key].nil?
      return false unless self[:target_value].nil?
    end
    if method == :create
      return false if self[:target_key].nil?
      return false unless self[:source_key].nil?
      return false unless self[:source_value].nil?
    end
    return true
  end
end

module EnfEditor
  module UserPropertyUtils
    def first_user_property2( key, subtype=nil )
      self.user_properties.find {|prop| prop.key == key && (subtype.nil? || prop.subtype == subtype)}
    end
  end
end

class UserPropertyMapper
  def initialize
    @logger = Logger.new( STDOUT )
  end

  def load( csv_file )
    @csv_table = nil
    unless File.exist?( csv_file )
      @logger.info "CSV file for UserProperty mapping doesn't exist. \"" + csv_file.to_s + "\""
      return false
    end
    @logger.info "Loading CSV file for UserProperty mapping. \"" + csv_file.to_s + "\""
    begin
      # :encoding => "#{Encoding.locale_charmap}:UTF-8" : convert from ACP to UTF8
      # :converters => nil         : avoid numeric values and dates to be converted to specific types (leave as string)
      @csv_table = CSV.table( csv_file, :encoding => "#{Encoding.locale_charmap}:UTF-8", :converters => nil )
    rescue => e
      @logger.error "Invalid CSV file. \"" + e.message.chomp +  "\""
      @csv_table = nil
      return false
    end
    if @csv_table.empty?
      @logger.info "CSV file is empty."
      return false
    end
    unless @csv_table.headers == [:source_key, :source_value, :target_key, :target_value, :method, :comment]
      @logger.error "Invalid CSV file headers. \"" + @csv_table.headers.to_s.chomp + "\""
      @csv_table = nil
      return false
    end
    @csv_table.delete_if do |row|
      if row.valid_for_prop_mapping? == false
        @logger.error "Invalid CSV row found. Skipped. \"" + row.to_s.chomp + "\""
        true
      else
        false
      end
    end
  end  

  def apply( entity, subtype=nil )
    return if @csv_table.nil?    
    @csv_table.each do |row|      
      method = row[:method].to_sym
      case method
      when :move, :copy, :delete
        prop = entity.first_user_property2( row[:source_key].to_s, subtype )
        next if prop.nil?                                                   # user prop not found 
        next if row[:source_value] && row[:source_value].to_s != prop.value # user prop found but value doesn't match
        if method == :move || method == :copy
          prop_value = row[:target_value]
          prop_value = prop.value if prop_value.nil?
          entity.overwrite_user_property( row[:target_key].to_s, prop_value.to_s, prop.type )
        end
        if method == :move || method == :delete
          prop.delete! unless row[:source_key] == row[:target_key]
        end
      when :create
        prop_value = row[:target_value]
        prop_value = "" if prop_value.nil?
        entity.overwrite_user_property( row[:target_key].to_s, prop_value.to_s, :text )        
      else next
      end
    end
  end  
end