=begin
TIG (c) 2015  

All rights reserved.    

# Name: Mirror

=end

module TIG

 module Mirror
		### tidy old version's PNG
		begin
			png = File.join(PLUGINS, "MI.png")
			File.delete(png) if File.exist?(png)
		rescue
		end
		### menus ##############################################################
		unless file_loaded?(__FILE__)
			###
			### Toolbar
			png=File.join(DATA, "#{NAME}.png")
			cmd=UI::Command.new("#{NAME} Selection"){ Sketchup.active_model.select_tool(MirrorTool.new()) }
			cmd.large_icon=png
			cmd.small_icon=png
			cmd.tooltip=NAME
			cmd.status_bar_text=DESC
			###
			tb=UI::Toolbar.new(NAME)
			tb.add_item( cmd )
			if tb.get_last_state==TB_NEVER_SHOWN
				tb.show
			elsif tb.get_last_state==TB_VISIBLE
				tb.restore
			end#if state
			###
			### Main menu
			UI.menu("Plugins").add_item( cmd )
			### Context menu
			UI.add_context_menu_handler{|menu|
				if Sketchup.active_model.selection[0]
					#menu.add_separator
					menu.add_item( cmd )
				end#if
			}#do context menu###

		end#if loaded
		file_loaded(__FILE__)
		###
		
### main CODE
###
 class MirrorTool
		
    def initialize
			@MIRROR_AT_POINT = 1
			@MIRROR_AT_LINE  = 2
			@MIRROR_AT_PLANE = 3
    end
    
    def reset()
			@pts = []
			@state = 0
			@transformationType = nil
			@trans = nil
			@point = nil
			@line = nil
			@linev = nil
			@plane = nil
			@planeNormal = nil
			@pointOnPlane = nil
			@ip = Sketchup::InputPoint.new
			@ip1 = Sketchup::InputPoint.new
			@ip2 = Sketchup::InputPoint.new
			@ip3 = Sketchup::InputPoint.new
			@msg = "#{NAME}:  Pick First Point"
			Sketchup::set_status_text(@msg)###
			@drawn = false
    end
    
    def activate
			@model=Sketchup.active_model
			@ss=@model.selection
			@locked=[]
			@ss.grep(Sketchup::Group).each{|e|
				@locked << e if e.locked?
			}
			@ss.grep(Sketchup::ComponentInstance).each{|e|
				@locked << e if e.locked?
			}
			@ss.remove(@locked) if @locked[0]
			if @ss.empty?
				@ss.add(@locked) if @locked[0]
				Sketchup::set_status_text("#{NAME}: NO Valid Selection !")
				UI.beep if Sketchup.version.to_i>15 
				UI.messagebox("Select Something Valid BEFORE Using #{NAME}...")
				Sketchup.send_action("selectSelectionTool:")
				return nil
			end
			self.reset()
    end
    
    def deactivate(view)
			view.invalidate if @drawn
			@ip1 = nil
			@ip2 = nil
			@ip3 = nil
    end
    
    def resume(view=nil)
      Sketchup::set_status_text(@msg)
    end
    
    def getExtents
      bb=Geom::BoundingBox.new
      case @state
       when 0 # We are getting the first point
         if @ip.valid? && @ip.display?
            bb.add(@ip.position)
         end
       when 1
         bb.add(@pts[0]) if @pts[0]
       when 2
         bb.add(@pts[1]) if @pts[1]
      end
      return bb
    end
    
    def onMouseMove(flags, x, y, view)
      case @state
        when 0 # getting the first end point
            @ip.pick(view, x, y)
            if @ip.valid? && @ip != @ip1
                @ip1.copy!(@ip)
            end
            view.invalidate
            view.tooltip = @ip.tooltip if @ip.valid?
        when 1 # getting the second end point
            @ip.pick(view, x, y, @ip1)
            if @ip.valid? && @ip != @ip2
                @ip2.copy!(@ip)
                @pts[1] = @ip2.position
            end
            view.invalidate
            view.tooltip = @ip.tooltip if @ip.valid?
        when 2 # getting the third end point
            @ip.pick(view, x, y, @ip2)
            if @ip.valid? && @ip != @ip3
                @ip3.copy!(@ip)### v3.4
                @pts[1] = @ip3.position
            end
            view.invalidate
            view.tooltip = @ip.tooltip if @ip.valid?
      end
    end
    
    def onLButtonDown(flags, x, y, view)
        @ip.pick(view, x, y)
        if @ip.valid?
          case @state
            when 0
							if @ip.valid?
								@pts[0] = @ip.position
								@msg = "#{NAME}:  Hit RETURN to Mirror at Point or Pick Point 2"
								Sketchup::set_status_text(@msg)
								@state = 1
							end
            when 1
							if @ip.valid? && @ip != @ip1
								@pts[1] = @ip.position
								@state = 2
								@msg = "#{NAME}:  Hit RETURN to Mirror at Line or Pick Point 3"
								Sketchup::set_status_text(@msg)
							end
            when 2
							if @ip.valid? && @ip != @ip1 && @ip != @ip2
								@pts[2] = @ip.position
								@state = 3
								view.invalidate
								self.mirror()
							end
          end
        end
    end
    
    def onCancel(flag, view)
			view.invalidate if @drawn
			self.reset()
    end
    
    def draw(view)
	    return unless @ip
        if @ip.valid? && @ip.display?
					@ip.draw(view)
					@drawn = true
        end
        if @state == 1
					view.set_color_from_line(@ip1, @ip)
					view.draw(GL_LINE_STRIP, @ip1.position, @ip.position)
					@drawn = true
        elsif @state == 2
					view.drawing_color = "gray"
					view.draw(GL_LINE_STRIP, @ip1.position, @ip2.position)
					view.set_color_from_line(@ip2, @ip)
					view.draw(GL_LINE_STRIP, @ip2.position, @ip.position)
					@drawn = true
        end
    end
    
    def onKeyDown(key, repeat, flags, view)
        if key == CONSTRAIN_MODIFIER_KEY && repeat == 1
					@shift_down_time = Time.now
					if view.inference_locked?
						view.lock_inference
					elsif @ip.valid?
						view.lock_inference(@ip)### v3.4
					end
        end
    end
    
    def onKeyUp(key, repeat, flags, view)
        if key == CONSTRAIN_MODIFIER_KEY && view.inference_locked? && (Time.now - @shift_down_time) > 0.5
          view.lock_inference
        end
        if key == 13 ### RETURN
					self.mirror()
					self.reset()
        end
    end
    
    def mirror()
      ###
      case @state
        when 1
					@transformationType = @MIRROR_AT_POINT
					@point = @ip1.position.clone
					@trans = Geom::Transformation.scaling(@point, -1.0)
					@model.start_operation("#{NAME} at Point", true)
        when 2
					@transformationType = @MIRROR_AT_LINE
					@line = [@ip1.position, @ip2.position] 
					@linev = Geom::Vector3d.new(@ip2.position.x-@ip1.position.x, @ip2.position.y-@ip1.position.y, @ip2.position.z-@ip1.position.z)
					@model.start_operation("#{NAME} at Line", true)
        when 3
					@transformationType = @MIRROR_AT_PLANE
					@plane = Geom.fit_plane_to_points(@ip1.position, @ip2.position, @ip3.position) 
					@planeNormal = Geom::Vector3d.new(@plane[0], @plane[1], @plane[2])
					@planeNormal.normalize!
					@pointOnPlane = @ip1.position
					@model.start_operation("#{NAME} at Plane", true)
      end
      @model.active_view.invalidate
    	### fix group glitch
      def group_miner(ents)
        ents.grep(Sketchup::Group).each{|e|
          if e.entities.parent.instances[1]
            begin
              e.make_unique
              self.group_miner(e.entities.to_a)
            rescue
              ###
            end
          end#if
        }#end each
      end#def
      sents=@ss.to_a
      ents=sents[0].parent.entities
      @ss.clear
      self.group_miner(sents)
			###
			### get ONLY glued instances
			@is2ds=[]
			sents.grep(Sketchup::ComponentInstance).each{|e|
				next unless e.definition.behavior.is2d?
				@is2ds << e.definition
			}
			@is2ds.uniq!
			###
			### make group
      copy_group=ents.add_group(sents)
      ### 
      gdef=copy_group.entities.parent
      gtr=copy_group.transformation
      new_group=ents.add_instance(gdef, gtr)
      self.group_miner(new_group.entities.to_a)
      ###
			new_center = new_group.bounds.center.clone
			mirror_point(new_center)
			t = nil
			t = Geom::Transformation.scaling(new_center, -1, -1, -1) if @state==1
			t = Geom::Transformation.rotation(new_center, @linev, 180.degrees) if @state==2
			tt=nil
			if @state==3
				xxx=@planeNormal.normalize.to_a[0].abs*-1
				yyy=@planeNormal.normalize.to_a[1].abs*-1
				zzz=@planeNormal.normalize.to_a[2].abs*-1
				xxx=1 if xxx>0
				yyy=1 if yyy>0
				zzz=1 if zzz>0
				xxx=-1 if xxx<=0 
				yyy=-1 if yyy<=0
				zzz=-1 if zzz<=0
				t = Geom::Transformation.scaling(new_center,xxx,yyy,zzz)
				tt= Geom::Transformation.rotation(new_center,@planeNormal,180.degrees)
			end#if
			new_group.transform!(t) if t   ### mirror
			new_group.transform!(tt) if tt ###
			transVec = Geom::Vector3d.new(new_center.x-new_group.bounds.center.x, new_center.y-new_group.bounds.center.y, new_center.z-new_group.bounds.center.z) 
			t = Geom::Transformation.translation(transVec)
			new_group.transform!(t)###then move
			### ending dialog...
			@msg = "#{NAME}: Erase Original Selection ?"
    	Sketchup::set_status_text(@msg)
			### we explode the copy always
			xents=[]; xents=new_group.explode if new_group.valid?
			nents=[]; xents.each{|e| nents << e if e.is_a?(Sketchup::Drawingelement) }
			@faces=ents.grep(Sketchup::Face)
			@faces.dup.each{|f| @faces.delete(f) unless f.valid?}
			self.gluer(nents)
			@ss.clear
			nents.each{|e|@ss.add(e) if e.valid?}
			###
			UI.beep if Sketchup.version.to_i>15
    	if UI.messagebox("#{NAME}: Erase Original Selection ? ",MB_YESNO,"")==6 ### 6=YES 7=NO
        copy_group.erase! if copy_group.valid?        
      else ### NO
        copy_group.explode if copy_group.valid?
	      @faces=ents.grep(Sketchup::Face)
			  @faces.dup.each{|f| @faces.delete(f) unless f.valid?}
				self.gluer(sents)
				@ss.clear
        sents.each{|e|@ss.add(e) if e.valid?}
    	end#if
			###
			@ss.add(@locked) if @locked[0]
			###
      @model.commit_operation
    	###
			self.reset()
			Sketchup.send_action("selectSelectionTool:")
			###
    end#def
	
		def gluer(gents)
			return nil unless @is2ds[0]
			return nil unless @faces[0]
			gents.grep(Sketchup::ComponentInstance).each{|instance|
				next unless instance.valid?
				next unless @is2ds.include?(instance.definition)
				tr=instance.transformation
				co=tr.origin
				cz=tr.zaxis
				@faces.to_a.each{|face|
					next unless face.valid?
					next unless face.parent==instance.parent
					if face.classify_point(co)==Sketchup::Face::PointInside && face.normal.parallel?(cz)
						instance.glued_to=face
						break
					end#if
				}
			}
		end### gluer
			
		def mirror_point(new_p)
			if @transformationType == @MIRROR_AT_PLANE
				if !new_p.on_plane?(@plane)
					mirrorp = new_p.project_to_plane(@plane)
					@trans = Geom::Transformation.scaling(mirrorp, -1.0)
					new_p.transform!(@trans)
				end
			elsif @transformationType == @MIRROR_AT_LINE
				if !new_p.on_line?(@line)
					mirrorp = new_p.project_to_line(@line)
					@trans = Geom::Transformation.scaling(mirrorp, -1.0)
					new_p.transform!(@trans)
				end
			elsif @transformationType == @MIRROR_AT_POINT
				if !(new_p == @point)
					new_p.transform!(@trans)
				end
			end
   end#def
    
 end # class MirrorTool

 end
 
end
