class DiscoversController < ::ApplicationController
  include Foreman::Controller::AutoCompleteSearch
  include Foreman::Controller::TaxonomyMultiple
  unloadable

  # Avoid auth for discovered host creation
  skip_before_filter :require_login, :require_ssl, :authorize, :verify_authenticity_token, :set_taxonomy, :session_expiry, :update_activity_time, :only => :create

  before_filter :find_by_name, :only => %w[show edit update destroy refresh_facts convert]
  before_filter :find_multiple, :only => [:multiple_destroy, :submit_multiple_destroy]
  before_filter :taxonomy_scope, :only => [:edit]

  helper :hosts

  layout 'layouts/application'

  def index
    hosts = ::Host::Discovered.search_for(params[:search], :order => params[:order])
    respond_to do |format|
      format.html { @hosts = hosts.list.paginate :page => params[:page] }
      format.json { render :json => hosts }
    end
  end

  # Importing yaml is restricted to puppetmasters, so instead we take the ip
  # as a parameter and use refresh_facts to get the rest
  def create
    Taxonomy.no_taxonomy_scope do
      host, imported = Host::Discovered.new(:ip => get_ip_from_env).refresh_facts
      respond_to do |format|
        format.yml {
          if imported
            render :text => _("Imported Host::Discovered"), :status => 200 and return
          else
            render :text => _("Failed to import facts for Host::Discovered"), :status => 400
          end
        }
      end
    end
  rescue Exception => e
    logger.warn "Failed to import facts for Host::Discovered: #{e}"
    render :text => _("Failed to import facts for Host::Discovered: %s") % (e), :status => 400
  end

  def show
    # filter graph time range
    @range = nil

    # summary report text
    @report_summary = nil
  end

  def destroy
    @host.destroy
    redirect_to :action => 'index'
  end

  def edit
    @host         = @host.becomes(::Host::Managed)
    @host.type    = 'Host::Managed'
    @host.managed = true
    @host.build   = true

    render :template => 'hosts/edit'
  end

  def update
    @host         = @host.becomes(::Host::Managed)
    @host.type    = 'Host::Managed'
    forward_url_options
    Taxonomy.no_taxonomy_scope do
      if @host.update_attributes(params[:host])
        process_success :success_redirect => host_path(@host), :redirect_xhr => request.xhr?
      else
        taxonomy_scope
        load_vars_for_ajax
        offer_to_overwrite_conflicts
        process_error :object => @host, :render => 'hosts/edit'
      end
    end
  end

  def refresh_facts
    if @host.is_a?(::Host::Discovered) and @host.refresh_facts
      process_success :success_msg => _("Facts refreshed for %s") % @host.name, :success_redirect => :back
    else
      process_error :error_msg => _("Failed to refresh facts for %s") % @host.name, :redirect => :back
    end
  end

  def multiple_destroy
  end

  def submit_multiple_destroy
    # keep all the ones that were not deleted for notification.
    @hosts.delete_if {|host| host.destroy}

    missed_hosts = @hosts.map(&:name).join('<br/>')
    if @hosts.empty?
      notice _("Destroyed selected hosts")
    else
      error _("The following hosts were not deleted: %s") % missed_hosts
    end
    redirect_to(discovers_path)
  end

  def auto_complete_search
    begin
      @items = Host::Discovered.complete_for(params[:search])
      @items = @items.map do |item|
        category = (['and','or','not','has'].include?(item.to_s.sub(/^.*\s+/,''))) ? 'Operators' : ''
        part = item.to_s.sub(/^.*\b(and|or)\b/i) {|match| match.sub(/^.*\s+/,'')}
        completed = item.to_s.chomp(part)
        {:completed => completed, :part => part, :label => item, :category => category}
      end
    rescue ScopedSearch::QueryNotSupported => e
      @items = [{:error =>e.to_s}]
    end
    render :json => @items
  end

  private

  def load_vars_for_ajax
    return unless @host

    @environment     = @host.environment
    @architecture    = @host.architecture
    @domain          = @host.domain
    @operatingsystem = @host.operatingsystem
    @medium          = @host.medium
  end

  # this is required for template generation (such as pxelinux) which is not done via a web request
  def forward_url_options(host = @host)
    host.url_options = url_options if @host.respond_to?(:url_options)
  end

  # if a save failed and the only reason was network conflicts then flag this so that the view
  # is rendered differently and the next save operation will be forced
  def offer_to_overwrite_conflicts
    @host.overwrite = "true" if @host.errors.any? and @host.errors.are_all_conflicts?
  end

  def find_by_name
    params[:id].downcase! if params[:id].present?
    @host = ::Host::Discovered.find_by_id(params[:id])
    @host ||= ::Host::Discovered.find_by_name(params[:id])
    return false unless @host
  end

  def find_multiple
    # Lets search by name or id and make sure one of them exists first
    if params[:host_names].present? or params[:host_ids].present?
      @hosts = Host::Discovered.where("id IN (?) or name IN (?)", params[:host_ids], params[:host_names] )
      if @hosts.empty?
        error _('No hosts were found with that id or name')
        redirect_to(discovers_path) and return false
      end
    else
      error _('No hosts selected')
      redirect_to(discovers_path) and return false
    end

  rescue => e
    error _("Something went wrong while selecting hosts - %s") % e
    redirect_to discovers_path
  end

  def get_ip_from_env
    # try to find host based on our client ip address
    ip = request.env['REMOTE_ADDR']

    # check if someone is asking on behave of another system (load balance etc)
    ip = request.env['HTTP_X_FORWARDED_FOR'] if request.env['HTTP_X_FORWARDED_FOR'].present?

    # Check for explicit parameter override
    ip = params.delete('ip') if params.include?('ip')

    # in case we got back multiple ips (see #1619)
    ip = ip.split(',').first
  end

  def taxonomy_scope
    if @host
      @organization = @host.organization
      @location = @host.location
    end

    if SETTINGS[:organizations_enabled]
      @organization ||= Organization.current
      @organization ||= Organization.my_organizations.first
    end
    if SETTINGS[:locations_enabled]
      @location ||= Location.current
      @location ||= Location.my_locations.first
    end
  end

end