#!/usr/bin/ruby -w
# Encoding: UTF-8
# frozen_string_literal: true
# =========================================================================== #
# This is the old ruby-gtk2 code for the gidnight commander.
# =========================================================================== #

module Gtk

class GidnightCommander < ::Gtk::Frame

  # ========================================================================= #
  # === create_toolbar
  #
  # Create our toolbar.
  # ========================================================================= #
  def create_toolbar
    # ======================================================================= #
    # The edit-button.
    # ======================================================================= #
    @button_edit = gtk_button(:edit)
    @button_edit.on_clicked {
      e 'Edit'
    }
    @button_edit.can_focus = false
    @button_edit.no_relief
    @toolbar.append_space
    @toolbar.append_with_space(@button_edit,'Edit')

    # ======================================================================= #
    # The find-button.
    # ======================================================================= #
    @button_find = gtk_button(:find)
    @button_find.on_clicked { e 'Find' }
    @button_find.can_focus = false
    @button_find.no_relief
    @toolbar.append_with_space(@button_find,'Find')

    # ======================================================================= #
    # The CopyFiles button (a checkbutton).
    # ======================================================================= #
    @button_check = gtk_check_button('CopyFiles',false)
    @button_check.set_active(false)
    @button_check.on_clicked { e 'Find' }
    @button_check.can_focus = false
    @button_check.no_relief
    @toolbar.append_with_space(@button_check, 'CopyFiles')

  end



  # ========================================================================= #
  # === create_combo_boxes
  # ========================================================================= #
  def create_combo_boxes
    @combo_box_left  = gtk_combo_box_text
    @combo_box_right = gtk_combo_box_text

    @combo_box_left.active  = 0
    @combo_box_right.active = 0
  end

  # ========================================================================= #
  # === create_skeleton                                          (create tag)
  # ========================================================================= #
  def create_skeleton
    create_entries # Create our gtk-entries in this widget next.
    create_toolbar
    create_combo_boxes
    create_gtk_liststore
    create_gtk_treeview
    create_scrolled_windows
  end

  def connect_skeleton
    # Add the two comboboxes next:
    mini_hbox = gtk_hbox(@combo_box_left, @combo_box_right)
    @vbox << mini_hbox
    mini_hbox2 = gtk_hbox(@scrolled_window_left, @scrolled_window_right)
    @vbox << mini_hbox2
    mini_hbox = gtk_hbox(entry_left?, entry_right?)
    @vbox << mini_hbox
    add(@vbox)
    show_all
  end

  # ========================================================================= #
  # === create_gtk_liststore
  #
  # Uses Gtk::ListStore. These lists contain the local and 
  # remote files.
  # ========================================================================= #
  def create_gtk_liststore
    @list_store_files_to_the_left  = gtk_list_store(String)
    @list_store_files_to_the_right = gtk_list_store(String)
  end

  # ========================================================================= #
  # === clear_liststores
  # ========================================================================= #
  def clear_liststores
    @list_store_files_to_the_left.clear
    @list_store_files_to_the_right.clear
  end

  # ========================================================================= #
  # === create_gtk_treeview
  #
  # We must attach the ListStore to our tree view.
  # Local files is to the left, remote files is to the right.
  # ========================================================================= #
  def create_gtk_treeview
    @tree_view_left_side  = ::Gtk::TreeView.new(@list_store_files_to_the_left)
    @tree_view_right_side = ::Gtk::TreeView.new(@list_store_files_to_the_right)
    @tree_view_left_side.modify_background(:normal, :darkblue)
    @tree_view_right_side.modify_background(:normal, :slateblue)
  end


# DEPRECATED
module Gtk

class GidnightCommander < ::Gtk::Frame # class: GidnightCommander

  # ========================================================================= #
  # === create_skeleton
  # ========================================================================= #
  def create_skeleton
    create_proc_objects
    create_gtk_liststore
    create_renderer
    create_image_and_event_box_and_middle_box
    create_entries
    create_combo_boxes
    create_gtk_treeview
    create_popup_menu
  end

  # ========================================================================= #
  # === create_combo_boxes
  # ========================================================================= #
  def create_combo_boxes
    register_changed_combo_box
    update_path_combo_boxes
  end

  # ========================================================================= #
  # === create_image_and_event_box_and_middle_box
  # ========================================================================= #
  def create_image_and_event_box_and_middle_box
    @main_image = gtk_image(directory_to_the_images?+'misc/RMC.jpg')
    @hbox_middle = gtk_hbox

    @event_box = gtk_event_box(@main_image)
    @event_box.on_button_press_event { |widget, event|  
      change_dir('..', which_side = :left) unless @hash_current_dir[:left] == '/'
    }
    @hbox_middle.pack_start @event_box
    create_small_event_box
    @hbox_middle.pack_start @event_box_for_cp_icon,false,false,3
    @hbox_middle.pack_start @combo_box_file_actions,false,false
  end
  
  # ========================================================================= #
  # === create_small_event_box
  # ========================================================================= #
  def create_small_event_box
    img = gtk_image(IMG+'/PC/LINUX/GNOME_APPLETS.png')
    @event_box_for_cp_icon = gtk_event_box.add(img)
    @event_box_for_cp_icon.signal_connect(:event) { |widget, event|
      case event.event_type
      when Gdk::Event::BUTTON_PRESS # d
        case @combo_box_file_actions.active_text
        when 'cp'
          @proc_object_copy_files.call
        end
      end
    }
  end
  # ^^^ port this for the copy action too
  
  def create_gtk_treeview
    @tree_view_column_left_side = ::Gtk::TreeViewColumn.new('Left', 
      @renderer, {text: 0})
    @tree_view_left_side.append_column(@tree_view_column_left_side)

    @tree_view_column_right_side = ::Gtk::TreeViewColumn.new('Right', 
      @renderer, {:text => 0})
    @tree_view_right_side.append_column(@tree_view_column_right_side)

    @tree_view_left_side.selection.mode  = ::Gtk::SelectionMode::MULTIPLE
    @tree_view_right_side.selection.mode = ::Gtk::SelectionMode::MULTIPLE

    enable_dragging

    fill_up_arrays
    fill_up_iters

    # ============================================================== #
    # The left side.
    # ============================================================== #
    @tree_view_left_side.on_button_press_event { |widget, event|
      if event.event_type == Gdk::Event::BUTTON2_PRESS # doppelklick, double
        invoke_selected_chdir_action(:left)
        @flag_selection = :left
      end
    }
    @tree_view_left_side.selection.signal_connect(:changed){ |tree_selection|
      tree_selection.selected_each { |model, path, iter| assign_selection(iter[0]) }
      @flag_selection = :left
    }
    @tree_view_left_side.signal_connect(:key_press_event) { |w,event|
      case Gdk::Keyval.to_name(event.keyval)
      when 'Return'
        invoke_selected_chdir_action(:left)
      end
    }

    # ============================================================== #
    # The right side:
    # ============================================================== #
    @tree_view_right_side.on_button_press_event { |widget, event|
      if event.event_type == Gdk::Event::BUTTON2_PRESS # doppelklick, double
        invoke_selected_chdir_action(:right)
        @flag_selection = :right
      end
    }
    @tree_view_right_side.selection.signal_connect(:changed){ |tree_selection|
      tree_selection.selected_each { |model, path, iter| assign_selection(iter.first) }
      @flag_selection = :right
    }
    @tree_view_right_side.signal_connect(:key_press_event) { |w,event|
      case Gdk::Keyval.to_name(event.keyval)
      when 'Return'
        invoke_selected_chdir_action(:right)
      end
    }
  end

  # ========================================================================= #
  # === invoke_selected_chdir_action
  #
  # This method will take the default treeview selection, and 
  # then invoke the change_dir method.
  #
  # Invoke it like so:
  #
  #   invoke_selected_chdir_action(:right, @tree_view_left_side)
  #
  # ========================================================================= #
  def invoke_selected_chdir_action(which_side)
    case which_side
    when :right
      change_dir(selection?(:right), :right)
    else
      change_dir(selection?(:left), :left)
    end
  end

  # ========================================================================= #
  # === reload_tree_view_update_path_combo_boxes
  # ========================================================================= #
  def reload_tree_view_update_path_combo_boxes
    reload_tree_view #
    update_path_combo_boxes
  end

  # ========================================================================= #
  # === reload_tree_view
  #
  # Will update both.
  # ========================================================================= #
  def reload_tree_view
    clear_liststores
    fill_up_arrays
    fill_up_iters
  end

  # ========================================================================= #
  # === fill_up_iter
  #
  # fills up iter. Supply :left or :right
  # ========================================================================= #
  def fill_up_iter(which_side)
    case which_side
    when :left
      @array_left_side.unshift '/..'
      @array_left_side.sort.each { |file|
        file = file.split('/').last
        if File.directory?(@hash_current_dir[:left]+'/'+file) && file != '..'
          file << '/' unless file.end_with? '/'
        end
        iter = @list_store_files_to_the_left.append
      }
    when :right
      @array_right_side.unshift '/..'
      @array_right_side.sort.each do |file|
        file = file.split('/').last
        if File.directory?(@hash_current_dir[:right]+'/'+file) && file != '..'
          file = file+'/'
        end
        iter = @list_store_files_to_the_right.append
      end
    when :both
      fill_up_iter(:left)
      fill_up_iter(:right)
    end
  end
  
  # ========================================================================= #
  # === create_renderer
  # ========================================================================= #
  def create_renderer
    @renderer = gtk_cell_renderer_text
    @renderer.set_property('background', 'lavender' )
    @renderer.set_property('foreground', 'black' )
  end

  # ========================================================================= #
  # === connect_skeleton
  #
  # skel tag.
  # ========================================================================= #
  def connect_skeleton
    small_vbox_left  = create_paned_vbox(@combo_box_left,  @entry_left)
    small_vbox_right = create_paned_vbox(@combo_box_right, @entry_right)

    # Now pack our two vboxes. They are on top.
    _hbox = create_paned_hbox(
      small_vbox_left, 
      small_vbox_right
    )

    hbox_for_paned_view = create_paned_hbox(
      @scrolled_window_left, 
      @scrolled_window_right
    )
        
    biggest_vbox = gtk_vbox
    biggest_vbox.pack_start(_hbox,false,true,0)
    biggest_vbox.pack_start(@hbox_middle,false,true,1)
    # Finally, add the two-paned view to our box.
    biggest_vbox.pack_start(hbox_for_paned_view)
    add(biggest_vbox)
  end

  # ========================================================================= #
  # === change_dir
  #
  # Changes dir. Also invokes reloading treeviews. You should supply
  # a second argument, denoting the side.
  # ========================================================================= #
  def change_dir
    else
      if File.exist? _
        case File.ftype(_)
        # === file
        when 'file'
          e @hash_current_dir[which_side].to_dir+target+' is '+
            'not a directory. Will not chdir into it.'
          # ok its not a dir, its probably a file, so lets copy it.
          file_action(@hash_current_dir[which_side].to_dir+target, which_side)
        # === directory
        when 'directory'
          e sdir("(#{Dir.pwd}):  #{_} is a directory.")
          cd _
          @hash_current_dir[which_side] = _
          @hash_entries[which_side].set_text _
        else
          e 'seltsam'
        end
        
      end
    end
    reload_tree_view_update_path_combo_boxes
    report_dirs
  end

  # ========================================================================= #
  # === register_changed_combo_box
  # ========================================================================= #
  def register_changed_combo_box
    @combo_box_left.on_changed { |widget, event|
      unless @combo_box_left.active_iter.nil?
        change_dir(@combo_box_left.active_text, :left)
      end
    }
    @combo_box_right.on_changed { |widget, event|
      unless @combo_box_right.active_iter.nil?
        change_dir(@combo_box_left.active_text, :left)
      end
    }
  end

  # ========================================================================= #
  # === file_action
  #
  # file_action decides what to do. It is a wrapper method around 
  # methods like copy_files. Usually this_method() will copy a file, but 
  # we can also move a file or remove a file via it.
  # ========================================================================= #
  def file_action(
      location_of_my_file, which_side
    )
    action = @combo_box_file_actions.active_text
    case action
    when 'cp'
      copy_files(location_of_my_file, which_side) if @button_check.active?
    else
      e 'NOCH NIT IMPLEMENTIERT! '+action.to_s
      e 'bissi dürfti.g...'
    end
  end

  # ========================================================================= #
  # === selection?
  #
  # Gives you what was selected.
  # ========================================================================= #
  def selection?(which_side = :left)
    array = []
    case which_side
    when :right
      @tree_view_right_side.selection.selected_each { |model, path, iter| 
p iter.class
        array << iter[0]
      }
    when :left
      @tree_view_left_side.selection.selected_each { |model, path, iter|
p iter.class
        array << iter[0]
      }
    end
    if array.size <= 1
      return array.to_s
    else
      return array
    end
  end
  
  # ========================================================================= #
  # === copy_files
  #
  # Used when selection is multiple. Calls copy_file sequentially
  # while doing so.
  # ========================================================================= #
  def copy_files(my_selection, which_side)
    if my_selection.is_a? String
      copy_file(my_selection, which_side)
    else
      my_selection.each { |tmp| copy_file(tmp, which_side) }
    end
  end
  
  # ========================================================================= #
  # === copy_file                                               (cp file)
  #
  # This copies a single file.
  #
  # DO NOT call it directly, call it from copy_files, please.
  # ========================================================================= #
  def copy_file(location_of_my_file, which_side)

    _ = @hash_current_dir[invert(which_side)]
    if Dir.exists?(location_of_my_file) && (@hash_current_dir[:left] == @hash_current_dir[:right])
      ewarn 'Wont copy the same file.'
    else
      if location_of_my_file.empty?
        ewarn 'You must supply/select at least one file!'
      else
        efancy 'Trying to copy '+sfancy(location_of_my_file)+' now.'
        begin
          FileUtils::Verbose.cp(location_of_my_file,_)
          reload_tree_view
        rescue ArgumentError => error
          # AFter we copied, we can delete it.
          # Probably exists already so try again.
          FileUtils.rm_f(location_of_my_file)
          FileUtils::Verbose.cp(location_of_my_file,_)
          reload_tree_view
        end
      end
    end
  end

  # ========================================================================= #
  # === create_proc_objects
  #
  # This makes our nice proc objects. A static method. proc tag.
  # @flag_selection is :left on default.
  #
  # WHEN THIS IS PORTED, WE WILL PROBABLY ABANDON PROCS HERE.
  # ========================================================================= #
  def create_proc_objects

    @proc_object_open_file = Proc.new {
      open_file_with_editor(selection?(@flag_selection))
    }

    @proc_object_play_video = Proc.new {
      play_video_file(selection?(@flag_selection))
    }
  
    @proc_object_copy_files = Proc.new {
      copy_files(selection?(@flag_selection), @flag_selection) 
    }

  end
  
  # ========================================================================= #
  # === update_path_combo_boxes
  #
  # Updates the combo boxes.
  # ========================================================================= #
  def update_path_combo_boxes

    @combo_box_left.model.clear
    @combo_box_right.model.clear

    @hash_current_dir[:left].split('/').sort {|x,y| y <=> x }.each do |string|
      @combo_box_left.append_text(string)
    end

    @hash_current_dir[:right].split('/').sort {|x,y| y <=> x }.each { |string|
      @combo_box_right.append_text(string)
    }

  end

  # ========================================================================= #
  # === create_popup_menu
  #
  # Sehr statisch, kann ein eigenes File haben. Macht ein popup 
  # Menu.
  # ========================================================================= #
  def create_popup_menu
    @menu = gtk_menu
    pad_to_this_amount = 26
    # Nun kann man items hinzufügen
    # Nota bene:
    # Es würde auch Gtk::ImageMenuItem existieren.
    my_label = 'Open file with '+ENV['MY_4ED']
    @item1 = ::Gtk::MyImageMenuItem.new(my_label,nil,pad_to_this_amount-my_label.size+4)
    @item1.signal_connect('activate') { @proc_object_open_file.call }
    @menu.append(@item1)

    my_label = 'Open image-file with GIMP'
    @item2 = ::Gtk::MyImageMenuItem.new(my_label,nil,pad_to_this_amount-my_label.size)
    @item2.signal_connect('activate') { @proc_object_open_image_file.call }
    @menu.append(@item2)

    my_label = 'Play Video'
    @item4 = ::Gtk::MyImageMenuItem.new(my_label,nil,pad_to_this_amount-my_label.size+8)
    @item4.signal_connect('activate') { @proc_object_play_video.call }
    @menu.append(@item4)

    my_label = 'Copy File(s)'
    @item5 = ::Gtk::MyImageMenuItem.new(my_label,nil,pad_to_this_amount-my_label.size+8)
    @item5.signal_connect('activate') { @proc_object_copy_files.call }
    @menu.append(@item5)
    
    @menu.show_all
    [
      @tree_view_right_side,
      @tree_view_left_side
    ].each { |array|
      array.on_button_press_event { |widget, event|
        if event.kind_of? Gdk::EventButton and event.button == 3
          @menu.popup(nil, nil, event.button, event.time)
        end
      }
      # auch mit Shift-F10
      array.signal_connect(:popup_menu) {
        @menu.popup(nil, nil, 0, Gdk::Event::CURRENT_TIME)
      }
    }
  end

  # ========================================================================= #
  # === enable_dragging
  #
  # Drag and drop.
  # ========================================================================= #
  def enable_dragging
    @tree_view_left_side.enable_model_drag_source(
      Gdk::Window::BUTTON1_MASK, [['GTK_TREE_MODEL_ROW', 0, 0] ], Gdk::DragContext::ACTION_COPY|Gdk::DragContext::ACTION_MOVE)
    @tree_view_left_side.enable_model_drag_dest([ 
      ['GTK_TREE_MODEL_ROW', 0, 0] ], Gdk::DragContext::ACTION_COPY|Gdk::DragContext::ACTION_MOVE)

    @tree_view_right_side.enable_model_drag_source(
      Gdk::Window::BUTTON1_MASK, [ ['GTK_TREE_MODEL_ROW', 0, 0] ], Gdk::DragContext::ACTION_COPY|Gdk::DragContext::ACTION_MOVE)
    @tree_view_right_side.enable_model_drag_dest([ 
      ['GTK_TREE_MODEL_ROW', 0, 0] ], Gdk::DragContext::ACTION_COPY|Gdk::DragContext::ACTION_MOVE)
  end
