# encoding: utf-8

# Copyright (c) [2017] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "cwm/table"

require "y2partitioner/device_graphs"
require "y2partitioner/widgets/blk_devices_table"

module Y2Partitioner
  module Widgets
    # Table widget to represent a given list of devices in one of the
    # the main screens of the partitioner
    class ConfigurableBlkDevicesTable < BlkDevicesTable
      include Yast::I18n

      # Constructor
      #
      # @param devices [Array<Y2Storage::Device>]
      # @param pager [CWM::TreePager]
      # @param buttons_set [DeviceButtonsSet]
      def initialize(devices, pager, buttons_set = nil)
        textdomain "storage"

        @devices = devices
        @pager = pager
        @buttons_set = buttons_set
      end

      # @macro seeAbstractWidget
      def opt
        [:notify, :immediate]
      end

      # @macro seeAbstractWidget
      def init
        return if devices.empty? # do nothing if there is nothing in table

        initial_sid = UIState.instance.row_sid

        # if we do not have valid sid, then pick first available device.
        # Reason is to allow e.g. chain of delete like described in bsc#1076318
        self.value = row_id(valid_sid?(initial_sid) ? initial_sid : devices.first)
        handle_selected
      end

      # @macro seeAbstractWidget
      def handle(event)
        case event["EventReason"]
        when "SelectionChanged"
          handle_selected
        when "Activated"
          handle_activated
        end
      end

      # Handles the event generated by the user changing the selected row
      #
      # If a buttons set was provided in the constructor, this updates the set
      # to reflect the currently selected device.
      def handle_selected
        dev = selected_device
        buttons_set.device = dev if buttons_set && dev
        nil
      end

      # Handles the event generated by the user double clicking on a row (or
      # pressing Enter in ncurses)
      #
      # It jumps to the page associated to the selected device
      def handle_activated
        device = selected_device
        return nil if device.nil?

        target_page = pager.device_page(device)
        return nil if target_page.nil?

        pager.handle("ID" => target_page.widget_id)
      end

      # Device object selected in the table
      #
      # @return [Y2Storage::Device, nil] nil if anything is selected
      def selected_device
        return nil if items.empty? || !value

        sid = value[/.*:(.*)/, 1].to_i
        device_graph.find_device(sid)
      end

      # Adds new columns to show in the table
      #
      # @note When a column :column_name is added, the methods #column_name_title
      #   and #column_name_value should exist.
      #
      # @param column_names [*Symbol]
      def add_columns(*column_names)
        columns.concat(column_names)
      end

      # Avoids to show some columns in the table
      #
      # @param column_names [*Symbol]
      def remove_columns(*column_names)
        column_names.each { |c| columns.delete(c) }
      end

      # Fixes a set of specific columns to show in the table
      #
      # @param column_names [*Symbol]
      def show_columns(*column_names)
        @columns = column_names
      end

      # @macro seeAbstractWidget
      # @see #columns_help
      def help
        header = _(
          "<p>This view shows storage devices.</p>" \
          "<p>The overview contains:</p>" \
        )

        header + columns_help
      end

    private

      # @return [DeviceButtonsSet] optional buttons set that must be
      #   updated when the user changes the selection in the table
      attr_reader :buttons_set

      # @return [CWM::TreePager] general pager used to navigate through the
      #   partitioner
      attr_reader :pager

      # @return [Array<Y2Storage::Device>] list of devices to display
      attr_reader :devices

      DEFAULT_COLUMNS = [
        :device,
        :size,
        :format,
        :encrypted,
        :type,
        :filesystem_type,
        :filesystem_label,
        :mount_point,
        :start,
        :end
      ].freeze

      def device_graph
        DeviceGraphs.instance.current
      end

      def columns
        @columns ||= default_columns.dup
      end

      def default_columns
        DEFAULT_COLUMNS
      end
    end
  end
end
