
#
# CBRAIN Project
#
# Copyright (C) 2008-2012
# The Royal Institution for the Advancement of Learning
# McGill University
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.
#

# Controller for managing Tool objects.
class ToolsController < ApplicationController

  Revision_info=CbrainFileRevision[__FILE__] #:nodoc:

  api_available :only => [:index, :show]

  before_action :login_required
  before_action :admin_role_required, :except  => [:index, :tool_config_select]

  # GET /tools
  # GET /tools.xml
  def index #:nodoc:
    @scope = scope_from_session
    scope_default_order(@scope, 'name')

    @base_scope = current_user.available_tools.includes(:user, :group)
    @tools = @scope.apply(@base_scope)

    respond_to do |format|
      format.js
      format.html # index.html.erb
      format.xml  { render :xml  => @tools.for_api }
      format.json { render :json => @tools.for_api }
    end
  end

  def tool_config_select #:nodoc:
    if params[:tool_id].blank?
      render plain: ""
      return
    end

    tool_id = params[:tool_id]
    @tool   = current_user.available_tools.find(tool_id)

    # All accessible bourreaux for this tool
    bourreau_ids  = @tool.bourreaux.map(&:id)
    @bourreaux    = Bourreau.find_all_accessible_by_user(current_user).where( :id => bourreau_ids)
    # All accessible tc for this tool on accessible bourreaux
    bourreaux_ids = @bourreaux.map(&:id)
    @tool_configs = ToolConfig.find_all_accessible_by_user(current_user).where(:tool_id => tool_id, :bourreau_id => bourreau_ids)
    # Reduce list of bourreaux, bourreaux need at least one config available
    bourreaux_ids = @tool_configs.map(&:bourreau_id)
    @bourreaux    = @bourreaux.where(:id => bourreaux_ids).all

    # Select a specific tool_config
    selected_by_default = current_user.meta["pref_bourreau_id"]
    @tool_config = @tool_configs.where(:bourreau_id => selected_by_default).last if (
      bourreaux_ids.include?(selected_by_default) &&
      @bourreaux.detect? { |b| b.id == selected_by_default && b.online? }
    )

    respond_to do |format|
      format.html { render :partial => 'tools/tool_config_select' }
      format.xml  { render :xml     => @tool_configs }
    end

  rescue
    # render :text  => "#{ex.class} #{ex.message}\n#{ex.backtrace.join("\n")}"
    render html: '<strong style="color:red">No Execution Servers Available</strong>'.html_safe
  end

  def new #:nodoc:
    @tool = Tool.new
  end

  # GET /tools/1/edit
  def edit #:nodoc:
    @tool      = current_user.available_tools.find(params[:id])
  end

  # POST /tools
  # POST /tools.xml
  def create #:nodoc:

    if params[:autoload]
      autoload_all_tools
      return
    end

    @tool = Tool.new(tool_params)

    task_class = @tool.cbrain_task_class_name || "CbrainTask::Object"
    task_class = task_class.demodulize
    subclass = CbrainTask.const_get(task_class) rescue Object
    unless subclass < CbrainTask # strictly subclass
      @tool.errors.add(:cbrain_task_class_name, "doesn't seem to be a code subclass of CbrainTask.")
    end

    respond_to do |format|
      if @tool.errors.empty? && @tool.save
        @tool.addlog_context(self,"Created by #{current_user.login}")
        flash[:notice] = 'Tool was successfully created.'
        format.html { redirect_to :action => :index, :format => :html}
        format.xml  { render :xml => @tool, :status => :created, :location => @tool }
      else
        format.html { render :action => :new }
        format.xml  { render :xml => @tool.errors, :status => :unprocessable_entity }
      end
    end
  end

  # GET /tools/1
  # GET /tools/1.xml
  # GET /tools/1.json
  def show
    @tool = current_user.available_tools.find(params[:id])

    respond_to do |format|
      format.html
      format.json { @tool.for_api }
      format.xml  { @tool.for_api }
    end
  end

  # PUT /tools/1
  # PUT /tools/1.xml
  def update #:nodoc:
    @tool = current_user.available_tools.find(params[:id])

    respond_to do |format|
      if @tool.update_attributes_with_logging(tool_params, current_user,
           %w( category cbrain_task_class_name select_menu_text url application_package_name application_type application_tags ) )
        flash[:notice] = 'Tool was successfully updated.'
        format.html { redirect_to(edit_tool_path(@tool)) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @tool.errors, :status => :unprocessable_entity }
      end
    end
  end


  # DELETE /tools/1
  # DELETE /tools/1.xml
  def destroy #:nodoc:
      @tool = current_user.available_tools.find(params[:id])
      @tool.destroy

      respond_to do |format|
        format.html { redirect_to :action => :index }
        format.js   { redirect_to :action => :index, :format => :js }
        format.xml  { head :ok }
      end
  end

  private

  def tool_params #:nodoc:
    params.require(:tool).permit(
      :name, :user_id, :group_id, :category, :license_agreements,
      :cbrain_task_class_name, :select_menu_text, :description, :url,
      :application_type, :application_tags, :application_package_name
    )
  end

  def autoload_all_tools #:nodoc:

    successes = []
    failures  = ""

    PortalTask.descendants.map(&:name).sort.each do |cbrain_task_class_name|
      next if current_user.available_tools.find_by_cbrain_task_class_name(cbrain_task_class_name) # already exists
      @tool = Tool.new(
                  :name                    => cbrain_task_class_name.demodulize,
                  :cbrain_task_class_name  => cbrain_task_class_name,
                  :user_id                 => User.admin.id,
                  :group_id                => User.admin.own_group.id,
                  :category                => "scientific tool"
                )
      success = @tool.save
      if success
        successes << @tool
      else
        failures += "#{cbrain_task_class_name} could not be added.\n"
      end
    end

    respond_to do |format|
      if successes.size > 0
        flash[:notice] = "#{view_pluralize(successes.size, "tool")} successfully registered:\n"
        successes.each do |tool|
          flash[:notice] += "Name: #{tool.name} Class: #{tool.cbrain_task_class_name}\n"
        end
      else
        flash[:notice] = "No unregistered tools found."
      end
      unless failures.blank?
        flash[:error] = failures
      end
      format.html { redirect_to tools_path }
    end

  end

end
