# -*- encoding: UTF-8 -*-
# enfeditor version: 0.1.1.1
require 'enfeditor'
require 'logger'
require 'set'
require_relative './daimler_setting_common.rb'
include EnfEditor

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

  def exec_with_log( message, &block )
    @logger.info "#{message} Start..."
    yield
    @logger.info "#{message} done"
  end    

  def adjust_properties( session )
    base_dir = File.expand_path( File.dirname(__FILE__) )
    env_base_dir = ENV['ELY_MAPPING_FILE_BASE_DIR']
    base_dir = env_base_dir.gsub('\\', '/') if env_base_dir  
    mapper1 = UserPropertyMapper.new
    mapper1.load( base_dir + '/jt_v5.csv' )
    
    mapper2 = UserPropertyMapper.new
    custom_dir = base_dir + '/../../../../../custom'
    if File.directory?( custom_dir )
      mapper2.load( custom_dir + '/jt_v5.csv' )
    else
      mapper2.load( base_dir + '/custom_jt_v5.csv' )
    end    

    session.model.components.each do |compo|            
      # fixed attribute mapping
      mapper1.apply( compo )

      # general attribute mapping
      mapper2.apply( compo )

      # create system properties from user properties
      # delete user properties that are duplicated
      prop_key_set = Set.new
      part_number_found = false      
      compo.user_properties.each do |prop|
        if prop_key_set.include?( prop.key )
          prop.delete!
          next
        end
        prop_key_set.add( prop.key )        
        if prop.key == 'PartNumber' && prop.type == :text
          part_number_found = true
          compo.part_number = prop.value
          prop.delete!          
        elsif prop.key == 'Nomenclature' && prop.type == :text          
          compo.part_name = prop.value
          prop.delete!
        elsif prop.key == 'Revision' && prop.type == :text          
          compo.part_revision = prop.value
          prop.delete!
        elsif prop.key == 'Description' && prop.type == :text          
          compo.description = prop.value
          prop.delete!
        end
      end      

      # overwrite system property "revision"      
      prop = compo.first_user_property("Sequence")
      if !prop.nil? && prop.type == :text
        compo.part_revision = prop.value
        prop.delete!        
      end

      # handle user attribute with upper character key as fallback (single JT file case)
      compo.user_properties.each do |prop|        
        if !part_number_found && prop.key == 'PARTNUMBER' && prop.type == :text
          compo.part_number = prop.value
          prop.delete!
        elsif compo.part_name.nil? && prop.key == 'NOMENCLATURE' && prop.type == :text
          compo.part_name = prop.value
          prop.delete!
        elsif compo.part_revision.nil? && prop.key == 'REVISION' && prop.type == :text
          compo.part_revision = prop.value
          prop.delete!
        elsif compo.description.nil? && prop.key == 'DESCRIPTION' && prop.type == :text
          compo.description = prop.value
          prop.delete!
        end
      end      
    end
  end  

  def modify_component_name( session )
    session.model.components.each do |compo|
      ext_ref_file = compo.first_user_property( '$ComponentExternalFileName' )
      unless ext_ref_file.nil?
        compo.name = File.basename(ext_ref_file.value, ".*")
        ext_ref_file.delete!
      else
        native_file = compo.native_file_name
        if native_file && File.extname(native_file).downcase == ".jt"
          compo.name = File.basename(native_file, ".*")
        end        
      end
      part_number = compo.first_user_property( 'PartNumber' )
      if part_number.nil?
        compo.part_number = compo.name
      else
        compo.name = part_number.value
      end
    end
  end  

  def separate_feature_group(fg, elems, comprep)
    fg.child_elements.each do |elem|      
      elem = elem.cast # important      
      next unless elem.instance_of?(EnfEditor::EEBrepEdge) || elem.instance_of?(EnfEditor::EEBrepVertex)
      elems << elem

      geom_elem = nil
      type = :wire
      if elem.instance_of?(EnfEditor::EEBrepEdge)
        geom_elem = elem.curve
      elsif  elem.instance_of?(EnfEditor::EEBrepVertex)
        geom_elem = elem.point
        type = :point
      end
      next unless geom_elem.has_property("$Name")
      val = geom_elem.get_property("$Name")
      name = val.to_str
      next if name.empty?
      
      fg.separate_element(elem)
      new_fg = comprep.create_feature_group(name, type, [elem])      
    end    
  end

  def adjust_feature_groups( session )
    session.model.components.each do |compo|
      compo.comprep_list.each do |comprep|
        next unless comprep.comprep_type == 'brep'              

        elems = []
        comprep.feature_groups.each do |fg|
          separate_feature_group(fg, elems, comprep)

          # make volume name identical to feature group
          next if fg.name.empty?
          fg_children = fg.child_elements
          next unless fg_children.size == 1
          fg_child = fg_children[0].cast # important
          next unless fg_child.instance_of?(EnfEditor::EEBrepVolume)
          fg_child.name = fg.name
        end

        comprep.isolated_edges.each do |elem|
          next if elems.include?(elem)
          geom_elem = elem.curve
          next if geom_elem.nil?
          next unless geom_elem.has_property("$Name")
          val = geom_elem.get_property("$Name")
          name = val.to_str
          next if name.empty?
          comprep.create_feature_group(name, :wire, [elem])
        end

        comprep.isolated_vertices.each do |elem|
          next if elems.include?(elem)
          geom_elem = elem.point
          next if geom_elem.nil?
          next unless geom_elem.has_property("$Name")
          val = geom_elem.get_property("$Name")
          name = val.to_str
          next if name.empty?
          comprep.create_feature_group(name, :point, [elem])
        end
      end      
    end
  end  

  def execute( argv )
    EnfEditor::EESession.open( argv ) do |session|
      input = session.parameter['inputfile']
      outputfile = session.parameter['outputfile']      
      exec_with_log( "Reading enf:" + input.to_s ) do
        session.read_enf( input )
      end            

      exec_with_log( "Modify component name" ) do
        modify_component_name( session )
      end

      exec_with_log( "Adjusting properties" ) do
        adjust_properties( session )
      end      

      exec_with_log( "Adjusting feature groups" ) do
        adjust_feature_groups( session )
      end

      exec_with_log( "Writing enf:" + outputfile.to_s ) do
        session.write_enf( outputfile )
      end
    end
  rescue Exception => ex
    @logger.error "Failed."
    @logger.error ex
    raise ex
  else
    @logger.info "Complete."
  end
end

if $0 == __FILE__
  # main program
  exec = InterpretDaimlerSetting.new
  exec.execute( ARGV )
end