# Copyright 2007, jim.foltz@gmail.com
# Unfold
#
# 

# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#-----------------------------------------------------------------------------

require 'sketchup.rb'
#require "progressbar.rb"
#require "dev/debug"

class Sketchup::Selection
   def faces
      find_all {|e| e.typename == "Face"}
   end
end




class UnfoldTool

   def initialize
      @@selected_faces = []
   end

   #attr_reader :msg

   def onLButtonDown(flags, x, y, view)
      ph = Sketchup.active_model.active_view.pick_helper
      ph.do_pick x, y
      ref = ph.best_picked

      if flags == 13 # Shift + Ctrl
	 p ref.plane
      end

      if ref.nil?
	 Sketchup.active_model.selection.clear
	 @@selected_faces = []
	 Sketchup.set_status_text "Unfold: Selection cleared. Select face to unfold."
	 return
      end

      if( ref.typename == "Face" )

	 # Select all faces on the same plane
	 if flags == 33 # ALT key
	    @@selected_faces = JF.select_plane(ref.plane)
	    # Sketchup.set_status_text "Unfold: Selected #{faces.length} faces."
	 end # end ALT key

	 if flags == 5  or JF.selected().length == 0 # Shift key
	    Sketchup.active_model.selection.toggle ref
	    @@selected_faces.push ref
	    Sketchup.set_status_text @msg
	    return
	 end

	 Sketchup.active_model.start_operation "Unfold"

	 if flags == 9 # Ctrl Key
	    # - swap ref with selected
	    st = ufold(JF.selected(), [ref], true)
	    #Sketchup.active_model.selection.toggle ref if st.nil?
	 else
	    # default operation
	    st = ufold([ref], JF.selected())
	    #Sketchup.active_model.selection.toggle ref if st.nil?
	 end # end Ctrl Key

	 if st
	    Sketchup.active_model.selection.add ref
	    Sketchup.active_model.selection.add JF.selected()
	 end

      end # if face picked

      if ref.typename == "Edge"
	 # Add flap?
      end # if edge picked

      Sketchup.active_model.commit_operation

   end # onLeftButtonDown

   def onLButtonDoubleClick(flags, x, y, view)
      ph = Sketchup.active_model.active_view.pick_helper
      ph.do_pick x, y
      ref = ph.best_picked
      @@selected_faces = JF.select_plane(ref.plane)

   end

   def onKeyDown(key, repeat, flags, view)
      txts=[ "  Unfold selected to next", "Ctrl = Match next to selected",
	    "Shift = Toggle selection", "Alt = Select plane" ]

      case key
      when 17 # Ctrl
	 txts[1] = "<<" + txts[1] + ">>"
      when 16 # Shift
	 txts[2] = "<<" + txts[2] + ">>"
      when 18 # Alt
	 txts[3] = "<<" + txts[3] + ">>"
      end
      Sketchup.set_status_text txts.join("  ")
   end
   def onKeyUp(key, repeat, flags, view)
      Sketchup.set_status_text @msg
   end

   def activate
      #puts "activate called."
      #Sketchup.active_model.selection.clear
      @msg = "<<Unfold selected to next>>  Ctrl = Match next to selected  Shift = Toggle selection  Alt = Select plane"
      Sketchup.set_status_text "Unfold: Select face to unfold  |  Shift = toggle, Alt = select plane. "
      #p selected()
      @@selected_faces = Sketchup.active_model.selection.faces
      #p @selected_faces
      #p @selected_faces.class
      @mo = JFModelObserver.new
      Sketchup.active_model.add_observer(@mo)
   end

   def deactivate(*args)
      #puts "deactivate called:#{args.inspect}"
      Sketchup.active_model.remove_observer(@mo)
   end

   def resume(view)
      if JF.selected().length != 0
	 msg = @msg
      else
	 msg = "Unfold: Select face to unfold."
      end
      Sketchup.set_status_text msg
   end

   def self.uselect
      if @@selected_faces.length > 1
	 face = @@selected_faces.pop
	 Sketchup.active_model.selection.remove(face)
      end
   end

   def ufold(ref, faces, rev = false)
      # Store selected faces
      curr_sel = Sketchup.active_model.selection.faces
      #print "sf:"
      #p @selected_faces
      if rev
      @@selected_faces.push(faces[0])
      else
      @@selected_faces.push(ref[0])
      end
      #d{:curr_sel}
      n1 = ref[0].normal
      #pb = ProgressBar.new(faces.size)
      faces.each_with_index {|f, i|
	 n2 = f.normal
	 angle = n1.angle_between n2
	 axis = Geom::intersect_plane_plane(ref[0].plane, f.plane)
	 next unless axis
	 g = Sketchup.active_model.entities.add_group(f)
	 g.transform! Geom::Transformation.rotation(axis[0], axis[1], -angle)
	 g.explode
	 #JF.select_plane(ref[0].plane)
	 #pb.update(i+1)
      }
      #Sketchup.active_model.selection.add ref
      Sketchup.active_model.selection.add @@selected_faces
   end
end #class UnfoldTOol


##################################################
# Support methods
# #################################################
#


module JF
   def self.selected
      Sketchup.active_model.selection.select { |e| e.typename == "Face" }
   end

   def self.select_plane(plane)
      factor = 10000
      faces = Sketchup.active_model.active_entities.select {|e| e.typename=="Face"}
      flag = true
      plane = plane.map { |e| (e*factor).to_i }

      faces.each do |face|
	 flag = true
	 fplane = face.plane.map { |e| (e*factor).to_i }
	 if plane != fplane
	    flag = false
	 end
	 if flag
	    #Sketchup.active_model.selection.clear
	    Sketchup.active_model.selection.add face
	 end
      end
      faces = Sketchup.active_model.selection.collect
      #Sketchup.active_model.selection.clear
      #Sketchup.active_model.selection.add faces
      #@@selected_faces = Sketchup.active_model.selection.faces
      faces
   end
end


class JFModelObserver < Sketchup::ModelObserver
   def onTransactionUndo(*args)
      #print "onTransactionUndo:"
      #p args
      UnfoldTool.uselect()
   end
end

menu_name = "Unfold Tool"
#menu_name = File.basename(__FILE__)
unless file_loaded?(menu_name)
   UI.menu("Plugins").add_item(menu_name) {
      Sketchup.active_model.select_tool UnfoldTool.new
   } 
   file_loaded(menu_name)
end
