class TasksController < ApplicationController
  skip_before_filter :populate_layout, :except => [:edit, :list_started, :move_down, :move_to_bottom, :move_to_top, :move_up, :new, :specify]
  
  verify :method => :post, :except => [ :new, :show, :edit, :list_started, :move_to_next_period],
  :redirect_to => { :controller => 'backlogs' }
  
  def list_started
    @tasks = Task.find_started
    @selected_task = Task.find_by_id(params[:id])
    back_or_redirect_to(:controller => '', :action => '') if @tasks.empty?
  end
  
  def new
    redirect_to params if request.post?
    params[:task].delete :file if params[:task]
    @task = Task.new params[:task]
    @task.backlog_id ||= @task.period && @task.period.most_frequent_backlog
    @backlogs = Backlog.find(:all, :order => 'name')
    @periods = Period.find_active_or_future
    @customers = Customer.find(:all)
  end
  
  def create
    if params[:task] && params[:task][:period_id] && params[:task][:period_id][0..0] == 'G'
      detour_to :controller => 'periods', :action => :new, :group_id => params[:task][:period_id][1..-1].to_i
      return
    end
    
    file = params[:task].delete(:file)
    
    @task = Task.new(params[:task])
    if @task.save
      flash[:notice] = 'Task was successfully created.'
      if file && file.is_a?(File)
        @task.task_files.create! :name => file.original_filename, :content_data => file.read, :content_type => file.content_type
      end
      @task.move_to_top
      if @task.period
        back_or_redirect_to :controller => 'periods', :action => 'show', :id => @task.period, :task => @task.id
      else
        back_or_redirect_to :controller => 'backlogs', :action => :edit, :id => @task.backlog, :task => @task.id
      end
    else
      populate_layout
      @backlogs = Backlog.find(:all, :order => 'name')
      @periods = Period.find_active_or_future
      render :action => 'new'
    end
  end
  
  def edit
    @task = Task.find(params[:id])
    @task.period_id = params[:task][:period_id] if params[:task] && params[:task][:period_id]
    @periods = Period.find_active_or_future
    @backlogs = Backlog.find(:all, :order => 'name')
    @customers = Customer.find(:all)
  end
  
  def update
    redirect_to(:controller => 'backlogs', :action => :index) unless params[:id]
    if params[:task] && params[:task][:description] == ''
      destroy
      return
    end
    @task = Task.find(params[:id])
    unless @task.period.nil? || @task.period.active_or_future? || (params[:task] && params[:task][:period_id] && params[:task][:period_id].to_i > 0 && (period = Period.find_by_id(params[:task][:period_id])) && period.active?)
      @task.errors.add(:period_id, "You may not update a task in an inactive period.  Move the task to an active period first.")
      back_or_redirect_to :controller => 'periods', :action => :show, :id => @task.period, :task => @task.id
      return
    end
    
    # TODO (uwe): This should be moved to the Task model: Task#period=
    if params[:task] && params[:task][:period_id]
      if params[:task][:period_id] != ''
        if params[:task][:period_id].to_i != @task.period_id
          @task.remove_from_list
          params[:task][:position] = Period.find(params[:task][:period_id]).tasks.size
        end
      else
        if @task.period_id != nil
          @task.remove_from_list
          @task.period = nil
          new_pos = @task.backlog.tasks.count(:conditions => 'period_id IS NULL AND parent_id IS NULL') + 1
          params[:task].delete(:period_id)
          params[:task][:position] = new_pos
        end
      end
    end
    
    file = params[:task].delete(:file)
    
    if params[:task] && @task.update_attributes(params[:task])
      flash[:notice] = 'Task was successfully updated.'
      if params[:estimate]
        @task.estimates.create! params[:estimate]
      end
      if file && file.is_a?(File)
        @task.task_files.create! :name => file.original_filename, :content_data => file.read, :content_type => file.content_type
      end
      if params[:estimate] && params[:estimate][:todo] && params[:estimate][:todo].to_i == 0
        unless @task.finished_at
          next_task = @task.lower_item || @task.higher_item
          @task.finish Task::COMPLETED, true
          @task.save!
          back_or_redirect_to :controller => 'periods', :action => :show, :id => @task.period, :task => next_task ? next_task.id : nil
        else
          back_or_redirect_to :controller => 'periods', :action => :show, :id => @task.period, :task => @task.id
        end
      else
        if @task.finished_at
          reopen
        else
          if @task.period
            back_or_redirect_to :controller => 'periods', :action => :show, :id => @task.period, :task => @task.id
          else
            back_or_redirect_to :controller => 'backlogs', :action => :show, :id => @task.backlog, :task => @task.id
          end
        end
      end
    else
      flash[:notice] = 'Task was not saved.'
      populate_layout
      edit
      render :action => 'edit'
    end
  end
  
  def destroy
    task = Task.find(params[:id])
    lower_item = task.lower_item
    task.destroy
    flash[:notice] = 'Task was successfully deleted.'
    redirect_to :controller => 'periods', :action => :show, :id => task.period, :task => lower_item ? lower_item.id : nil
  end
  
  def move_up
    task = Task.find(params[:id])
    task.move_higher
    flash[:notice] = "Task #{@focus_id} was successfully moved."
    redirect_to :controller => 'periods', :action => :show, :id => task.period, :task => task.id
  end
  
  def move_down
    task = Task.find(params[:id])
    task.move_lower
    redirect_to :controller => 'periods', :action => :show, :id => task.period, :task => task.id
  end
  
  def move_to_top
    task = Task.find(params[:id])
    task.move_to_top
    redirect_to :action => :list, :id => task
  end
  
  def move_to_bottom
    task = Task.find(params[:id])
    task.move_to_bottom
    redirect_to :action => :list, :id => task
  end
  
  # Move the indicated task to the indicated position.
  def move_to
    params[:id] = $1 if params[:id] =~ /^task_(\d*)/
    if params[:id] && task = Task.find(params[:id])
      if params[:target_id]
        if target_task = Task.find_by_id(params[:target_id])
          if task.parent_id != target_task.parent_id
            task.remove_from_list
            task.position = nil
            task.parent_id = target_task.parent_id
            task.backlog_id = target_task.backlog_id
            task.period_id = target_task.period_id
          end
          task.insert_at target_task.position
        end
      elsif params[:period_id] && params[:period_id].to_i != task.period_id
        task.remove_from_list
        task.period_id = params[:period_id]
        task.insert_at 1
        task.save!
      else
        flash[:notice] = "Target position is missing for move."
      end
    else
      flash[:notice] = "Task not found"
    end
    back_or_redirect_to :controller => 'periods', :action => :show_no_layout, :id => task.period_id, :task => task.id
  end
  
  def move_to_period
    params[:id] = $1 if params[:id] =~ /^task_(\d*)/
    @task = Task.find(params[:id])
    if request.post?
      period = params[:period_id] && Period.find(params[:period_id])
      if period && period.active_or_future?
        next_task = @task.higher_item ? @task.higher_item : @task.lower_item ? @task.lower_item : @task
        setup_remove
        @task.move_to_period period
        render :action => :move_to_period, :layout => false
      else
        rjs_detour_to :controller => 'periods', :action => :new, :period => {:party_id => @task.period.party_id}, :layout => false
      end
    else
      redirect_to :controller => 'periods', :action => :show, :id => @task.period, :task_id => @task.id, :layout => false
    end
  end
  
  def move_to_next_period
    @task = Task.find(params[:id])
    if @task.period
      next_period = @task.period.lower_item
      next_period = next_period.lower_item while next_period && next_period.passed?
      params[:period_id] = next_period && next_period.id
      move_to_period
    else
      rjs_redirect_to :action => :edit, :id => @task
    end
  end
  
  def finish
    @task = Task.find(params[:id])
    setup_remove
    @task.finish(Task::COMPLETED, true)
  end
  
  def abort
    @task = Task.find params[:id]
    setup_remove
    @task.abort
    render :action => :finish
  end
  
  def reopen
    @task = Task.find(params[:id])
    @task.reopen
    @task.reload
    finished_count = Task.count(:conditions => ['period_id = ? AND finished_at IS NOT NULL', @task.period_id])
    @last_finished = finished_count == 0
  end
  
  def start_work
    @task = Task.find(params[:id])
    @task.start_work
  end
  
  def end_work
    @task = Task.find(params[:id])
    next_quarter = Time.next_quarter
    if started_work = @task.started_work
      redirect_to({
        :controller => 'works',
        :action => :edit,
        :id => started_work,
            'work[task_id]' => @task.id,
            'work[started_at]' => started_work.started_at.iso8601,
            'work[completed_at]' => [next_quarter, started_work.started_at].max.iso8601,
            'work[hours]' => "%0.2f" % ((next_quarter - started_work.started_at).to_f / 3600),
            'estimate[todo]' => @task.todo
      })
    else
      @task.update_attributes(params[:task])
      redirect_to({
        :controller => 'works',
        :action => :new, 
            'work[task_id]' => @task.id,
            'work[started_at]' => Time.previous_quarter.iso8601,
            'work[completed_at]' => next_quarter.iso8601,
            'work[hours]' => "0.25",
            'estimate[todo]' => @task.todo
      })
    end
  end
  
  def specify
    parent_task = Task.find(params[:id])
    raise "Task is not open" unless parent_task.active? && (parent_task.period.nil? || parent_task.period.active_or_future?)
    if parent_task.children.empty?
      subtask_estimate = (parent_task.todo).ceil
      no_of_subtasks = (parent_task.todo / subtask_estimate).to_i
      subtask_estimate = parent_task.todo / no_of_subtasks
       (1..no_of_subtasks).each do |index|
        subtask = parent_task.children.build
        subtask.description = "#{parent_task.description} ##{parent_task.children.size}"
        subtask.initial_estimate = subtask_estimate
        subtask.save!
      end
      redirect_to :controller => 'periods', :action => :show, :id => parent_task.period, :task => parent_task.children.first
    else
      average_estimate = parent_task.children.reduce {|value, task, size| value + (task.initial_estimate / size)}
      subtask = parent_task.children.build
      subtask.description = "#{parent_task.description} ##{parent_task.children.size}"
      subtask.initial_estimate = average_estimate
      subtask.save!
      redirect_to :controller => 'periods', :action => :show, :id => parent_task.period, :task => parent_task.children.first
    end
    if started_work = parent_task.started_work
      flash[:notice] = "Pågående arbeid er flyttet til subtask"
      started_work.task = parent_task.children.last
      started_work.save!
    end
  end
  
  def set_task_description
    task = Task.find(params[:id])
    task.description = params[:value]
    task.save!
    render :text => task.description
  end
  
  private
  
end