# encoding: utf-8
# This controller was added by william
class TagsController < ApplicationController
  layout "base_tags"
  
  before_filter :require_admin,:only => :show

  include CoursesHelper
  include ProjectsHelper
  include IssuesHelper
  include UsersHelper
  include BidsHelper
  include ForumsHelper
  include AttachmentsHelper
  include ContestsHelper
  include ActsAsTaggableOn::TagsHelper
  include TagsHelper
  include FilesHelper
  helper :projects
  helper :courses
  helper :tags
  include OpenSourceProjectsHelper

  before_filter :require_admin,:only => [:delete,:show_all]
  before_filter :require_login,:only => [:tag_save]

  # $selected_tags = Array.new
  # $related_tags = Array.new
  NUMBERS = Setting.tags_show_search_results

  # 预设几个可以添加的tag
  #@preTags = %w|预设A 预设B 预设C 预设D 预设E 预设F |
  
  # 接收参数解释：
  # params[:q]这是在其他页面点击tag，跳转到该页面后的结果显示 ;params[:selected_tags]，这是在过滤页面增删tag进行过滤传过来的参数
  # 最后是2个过滤何种数据，显示结果的控制参数params[:obj_id],params[:object_falg]
  # 0代表删除tag 1代表增加tag
  def index  

    @obj_id = params[:obj_id]
    @obj_flag = params[:object_flag]
    
    @selected_tags = Array.new   
    @related_tags = nil
    
    if params[:q]  
      @selected_tags << params[:q]
    else
      @do_what = params[:do_what]
      @tag = params[:tag]
      @selected_tags = params[:current_selected_tags]
      @selected_tags = @selected_tags.nil? ? Array.new : @selected_tags

      case @do_what
      when '0' then
        @selected_tags.delete @tag    #数组中删除有多方式 可以改用shift,pop
      when '1' then
        # 判断是否已存在该tag 主要用来处理分页的情况
        unless @selected_tags.include? @tag
          @selected_tags << @tag
        end
      end
    end

    @users_tags_num,@projects_tags_num,@issues_tags_num,@bids_tags_num,@contests_tags_num,
    @forum_tags_num, @attachments_tags_num, @open_source_projects_num = get_tags_size

    # 获取搜索结果 
    @obj,
    @obj_pages,
    @results_count,
    @users_results,
    @projects_results,
    @issues_results,
    @bids_results,
    @forums_results,
    @attachments_results,
    @contests_results,
    @courses_results,
    @open_source_projects_results= refresh_results(@obj_id,@obj_flag,@selected_tags)

    # 这里是做tag推荐用的， 用来生产推荐的tags
    unless @obj.nil?
      @tags = @obj.tag_list
      @tags -= @selected_tags
      # @selected_tags.each do |i|
      #   @tags.delete(i)
      # end    
      @related_tags = @tags
    else
      return
    end

  end

  # 增加已选的tag
  def add_tag
    @tag = params[:tag]
    @show_flag = params[:show_flag]
    
    $selected_tags << @tag
    $related_tags.delete(@tag)

    # 获取搜索结果 
    @obj,
    @obj_pages,
    @results_count,
    @users_results,
    @projects_results,
    @issues_results,
    @bids_results,
    @forums_results,
    @attachments_results,
    @contests_results,
    @courses_results,
    @open_source_projects_results= refresh_results(@obj_id,@show_flag)
  end

  # 删除已选tag 
  def delete_tag
    @tag = params[:tag]
    @show_flag = params[:show_flag]
    
    $related_tags << @tag
    $selected_tags.delete(@tag)

    # 获取搜索结果 
    @obj,
    @obj_pages,
    @results_count,
    @users_results,
    @projects_results,
    @issues_results,
    @bids_results,
    @forums_results,
        @attachments_results,
    @contests_results,
    @courses_results,
    @open_source_projects_results= refresh_results(@obj_id,@show_flag)   
  end

  def show_all
    @tags = ActsAsTaggableOn::Tag.find(:all)
  end

  # 完全从数据库删除tag
  # 这种删除方式是针对 印有该 tag所有对象来做删除的
  # 这样是从整个系统数据库中把该tag删除了
  def delete
    if params[:q]
      @tag = ActsAsTaggableOn::Tag.find_by_id(params[:q])
      @tag.delete     
      @taggings = ActsAsTaggableOn::Tagging.find_all_by_tag_id(@tag.id)
      @taggings.each do |tagging|
        tagging.delete
      end
    end     
  end
  
  # 只删除某个对象的该tag
  def remove_tag
    @obj = nil               
    @object_flag = nil
    
    if request.get? 
      # 获取传过来的tag_id taggable_id 和  taggable_type,通过2者确定要删除tag的对象
      @tag_name = params[:tag_name]
      @tag_id = (ActsAsTaggableOn::Tag.find_by_name(@tag_name)).id 
      @taggable_id = params[:taggable_id]                                   # 当做参数传时对象会变成字符串
      @taggable_type = numbers_to_object_type(params[:taggable_type])
      
      @obj = get_object(@taggable_id,params[:taggable_type])
      @object_flag = params[:taggable_type]
      
      # if can_remove_tag?(User.current,@taggable_id,@taggable_type)
      
      @taggings = ActsAsTaggableOn::Tagging.find_by_tag_id_and_taggable_id_and_taggable_type(@tag_id,@taggable_id,@taggable_type)

      unless @taggings.nil?
        @taggings.delete       
      end
      
      # 是否还有其他记录 引用了 tag_id
      @tagging = ActsAsTaggableOn::Tagging.find_by_tag_id(@tag_id)
      # 如果taggings表中记录已经不存在 ，那么检查tags表 作删除动作
      if @tagging.nil?
        @tag = ActsAsTaggableOn::Tag.find_by_id(@tag_id)
        @tag.delete unless @tag.nil?
      end
      # end
    end
  end

  # 只删除某个对象的该tag
  def remove_tag_new
    @obj = nil
    @object_flag = nil

    if request.get?
      # 获取传过来的tag_id taggable_id 和  taggable_type,通过2者确定要删除tag的对象
      @tag_name = params[:tag_name]
      @tag_id = (ActsAsTaggableOn::Tag.find_by_name(@tag_name)).id
      @taggable_id = params[:taggable_id]                                   # 当做参数传时对象会变成字符串
      @taggable_type = numbers_to_object_type(params[:taggable_type])

      @obj = get_object(@taggable_id,params[:taggable_type])
      @object_flag = params[:taggable_type]

      # if can_remove_tag?(User.current,@taggable_id,@taggable_type)

      @taggings = ActsAsTaggableOn::Tagging.find_by_tag_id_and_taggable_id_and_taggable_type(@tag_id,@taggable_id,@taggable_type)

      unless @taggings.nil?
        @taggings.delete
      end

      # 是否还有其他记录 引用了 tag_id
      @tagging = ActsAsTaggableOn::Tagging.find_by_tag_id(@tag_id)
      # 如果taggings表中记录已经不存在 ，那么检查tags表 作删除动作
      if @tagging.nil?
        @tag = ActsAsTaggableOn::Tag.find_by_id(@tag_id)
        @tag.delete unless @tag.nil?
      end

      if @obj && @object_flag == '6' && @obj.container.kind_of?(Course)
        @course = @obj.container
        @tag_list = get_course_tag_list @course
        @select_tag_name = params[:select_tag_name]
      end
      # end
    end
  end

  #更新某个tag名称
  def update_tag_name
    @tag_name = params[:tagName]
    @rename_tag_name = params[:renameName]
    @taggable_id = params[:taggableId]
    @taggable_type = numbers_to_object_type(params[:taggableType])
    @course_id = params[:courseId]

    @rename_tag = (ActsAsTaggableOn::Tag.find_by_name(@rename_tag_name))  #查找重命名后的tag
    @tag_id = (ActsAsTaggableOn::Tag.find_by_name(@tag_name)).id  #重命名前的tag_id
    @taggings = ActsAsTaggableOn::Tagging.find_by_tag_id_and_taggable_id_and_taggable_type(@tag_id,@taggable_id,@taggable_type) unless @taggable_id.blank?
    @obj = get_object(@taggable_id,params[:taggableType]) unless @taggable_id.blank?
    if  @taggable_id.blank? #如果没有传tag_id，那么直接更新tag_name就好了。但是要防止 重命名后的tag存在。
      #看重命名后的tag是否存在。如果存在的话，只需要更改taggings里边的id即可
      if @rename_tag
        @taggings = ActsAsTaggableOn::Tagging.find_by_tag_id_and_taggable_type(@tag_id,@taggable_type)
        @taggings.update_attributes({:tag_id=>@rename_tag.id})
      else #如果不存在，那么就直接更新该tag名称为新的名称
        (ActsAsTaggableOn::Tag.find_by_name(@tag_name)).update_attributes(:name=>@rename_tag_name)
      end
    else
      if(@rename_tag.nil?) #这次命名的是新的tag

        # 是否还有其他记录 引用了 tag_id
        @tagging = ActsAsTaggableOn::Tagging.where("tag_id = #{@tag_id}")
        # 如果taggings表中记录为 1 ，那么改变@tag_id对应的tag的名字
        if @tagging.count == 1
          @tag = ActsAsTaggableOn::Tag.find_by_id(@tag_id)
          @tag.update_attributes({:name=>@rename_tag_name})
        else #如果tagging表中的记录大于1，那么就要新增tag记录

          unless @obj.nil?
            @obj.tag_list.add(@rename_tag_name.split(","))
            @obj.save
          end
          #删除原来的对应的taggings的记录
          unless @taggings.nil?
            @taggings.delete
          end
        end
      else #这是已有的tag
        # 更改taggings记录里的tag_id
        unless @taggings.nil?
          @taggings.update_attributes({:tag_id=>@rename_tag.id})
        end
      end
    end

    @obj_flag =  params[:taggableType]
    if @obj && @obj_flag == '6' && @obj.container.kind_of?(Course)
      @course = @obj.container
      @tag_list = @tag_list = get_course_tag_list @course
    elsif @course_id
      @course = Course.find(@course_id)
      @tag_list = get_course_tag_list @course

      #这里要引用FilesController里的逻辑了。将资源库当前的文件列表刷新一遍。
      @flag = params[:flag] || false
      sort = ""
      @sort = ""
      @order = ""
      @is_remote = false
      @isproject = false

      sort = "#{Attachment.table_name}.created_on desc"

      @containers = [ Course.includes(:attachments).reorder(sort).find(@course.id)]

      show_attachments @containers
    elsif @obj &&  @obj_flag == '5'
      @forum = @obj
    end
    respond_to do |format|
      format.js
    end
  end

  def show_attachments obj
    @attachments = []
    obj.each do |container|
      @attachments += container.attachments
    end
    @all_attachments = User.current.admin? ? @attachments : visable_attachemnts(@attachments)
    @limit = 10
    @feedback_count = @all_attachments.count
    @feedback_pages = Paginator.new @feedback_count, @limit, params['page']
    @offset ||= @feedback_pages.offset
    #@curse_attachments_all = @all_attachments[@offset, @limit]
    @obj_attachments = paginateHelper @all_attachments,10
  end

  def tag_save
    @select_tag_name = params[:tag_for_save][:tag_name]
    @tags = params[:tag_for_save][:name]
    @obj_id = params[:tag_for_save][:object_id]
    @obj_flag = params[:tag_for_save][:object_flag]

    case @obj_flag
      when '1' then
        @obj = User.find_by_id(@obj_id)
      when '2' then
        @obj = Project.find_by_id(@obj_id)
      when '3' then
        @obj = Issue.find_by_id(@obj_id)
      when '4' then
        @obj = Bid.find_by_id(@obj_id)
      when '5' then
        @obj = Forum.find_by_id(@obj_id)
      when '6'
        @obj = Attachment.find_by_id(@obj_id)
      when '7' then
        @obj = Contest.find_by_id(@obj_id)
      when '8'
        @obj = OpenSourceProject.find_by_id(@obj_id)
      when '9'
        @obj = Course.find_by_id(@obj_id)
      when '10'
        @obj = Attachment.find_by_id(@obj_id)
      else
        @obj = nil
    end
    unless @obj.nil?
      @obj.tag_list.add(@tags.split(","))
    else
      return
    end
    if @obj.save
      logger.debug "#{__FILE__}:#{__LINE__} ===> #{@obj.to_json}"
    else
      logger.error "#{__FILE__}:#{__LINE__} ===> #{@obj.errors.try(:full_messages)}"
    end
    if @obj && @obj_flag == '6' && @obj.container.kind_of?(Course)
      @course = @obj.container
      @tag_list = @tag_list = get_course_tag_list @course
    end
    respond_to do |format|
      format.js
      format.html
    end
  end
  
  private 
  # 这里用来刷新搜索结果的区域
  # 函数的返回值 前2字段用来处理获取其他tag和分页 ，另外4个返回值为过滤结果
  def refresh_results(obj_id,obj_flag,selected_tags)  
    @users_results = nil
    @projects_results = nil
    @issues_results = nil
    @bids_results = nil
    @contests_results = nil
    @forums_results = nil
    @attachments_results = nil
    @open_source_projects_results = nil
    @obj_pages = nil
    @obj = nil
    @result = nil
    @courses_results = nil
    
    # 这里为了提高系统的响应速度 把搜索结果放到case中去了
    case obj_flag
    when '1' then
      @obj = User.find_by_id(obj_id)
      @obj_pages,@users_results,@results_count = for_pagination(get_users_by_tag(selected_tags))  
    when '2' then   
      @obj = Project.find_by_id(obj_id)
      @obj_pages,@projects_results,@results_count = for_pagination(get_projects_by_tag(selected_tags))
    when '3' then
      @obj = Issue.find_by_id(obj_id)
      @obj_pages,@issues_results,@results_count = for_pagination(get_issues_by_tag(selected_tags))
    when '4' then
      @obj_pages,@bids_results,@results_count = for_pagination(get_bids_by_tag(selected_tags))
      @obj = Bid.find_by_id(obj_id)
    when '5'
      @obj = Forum.find_by_id(obj_id)
      @obj_pages,@forums_results,@results_count = for_pagination(get_forums_by_tag(selected_tags))
    when '6'
      @obj = Attachment.find_by_id(obj_id)
      
      # modifed by Long Jun
      # this is used to find the attachments that came from the same project and tagged with the same tag.
      #@result = get_attachments_by_project_tag(selected_tags, @obj)
      @result = get_attachments_by_tag(selected_tags)
      @obj_pages, @attachments_results, @results_count = for_pagination(@result)
    when '7'
      @obj = Contest.find_by_id(obj_id)
      @obj_pages,@contests_results,@results_count = for_pagination(get_contests_by_tag(selected_tags))
    when '8'
      @obj = OpenSourceProject.find_by_id(obj_id)
      @obj_pages, @open_source_projects_results, @results_count = for_pagination(get_open_source_projects_by_tag(selected_tags))
    when '10'
        @obj = Attachment.find_by_id(obj_id)

        # modifed by Long Jun
        # this is used to find the attachments that came from the same project and tagged with the same tag.
        #@result = get_attachments_by_project_tag(selected_tags, @obj)
        @result = get_attachments_by_tag(selected_tags)
        @obj_pages, @attachments_results, @results_count = for_pagination(@result)
    when '9' then
      @obj = Course.find_by_id(obj_id)
      @obj_pages, @courses_results, @results_count = for_pagination(get_courses_by_tag(selected_tags))
    else
      @obj = nil
    end
    return [@obj,
          @obj_pages,
          @results_count,
          @users_results,
          @projects_results,
          @issues_results,
          @bids_results,
          @forums_results,
          @attachments_results,
          @contests_results,
          @courses_results,
          @open_source_projects_results]
  end

  def for_pagination(results)
    @offset, @limit = api_offset_and_limit({:limit => NUMBERS })  # 设置每页显示的个数
    @results_count = results.count
    @obj_pages = Paginator.new @results_count, @limit, params['page']   # 3个参数分别是：总数，每页显示数目，第几页
    @offset ||= @obj_pages.offset
    results =  results.offset(@offset).limit(@limit).all  # 这里默认设置为按时间排序
    return @obj_pages,results, @results_count
  end
  
  # 获取有某类对象的tag总数
  def get_tags_size
    @issues_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"Issue").count
    @projects_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"Project").count
    @users_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"User").count
    @bids_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"Bid").count
    forum_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"Forum").count
    attachment_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"Attachment").count
    @open_source_projects_num =  ActsAsTaggableOn::Tagging.where(taggable_type:"OpenSourceProject").count
    @contests_tags_num = ActsAsTaggableOn::Tagging.where(taggable_type:"Contest").count
    return @users_tags_num,@projects_tags_num,@issues_tags_num,@bids_tags_num, forum_tags_num, attachment_tags_num, @contests_tags_num, @open_source_projects_num
  end
  
  # 通过数字 来转换出对象的类型 
  # 1代表是user类型   2代表是project类型  3代表是issue类型   4代表需求
  # 这个函数 重构是可以移动到application_helper中去 
  # 当做一个全局的函数使用，有好几个地方使用到了
  def numbers_to_object_type(num)
    case num
    when '1'
      return 'Principal'
    when '2'
      return 'Project'
    when '3'
      return 'Issue'
    when '4'
      return 'Bid'
    when '5'
      return 'Forum'
    when '6'
      return 'Attachment'
    when '7'
      return 'Contest'
    when '8'
      return 'OpenSourceProject'
    when '9'
      return 'Course'
    when '10'
      return 'Attachment'
    else
      render_error :message => e.message
      return 
    end
  end


  
end
