require "vizshot_gfdnavi"
require "pp"

class KnowledgeController < ApplicationController
  layout "gfdnavi", :except => [:list_without_layout, :show_without_layout, :category_search]
  before_filter :login_required, :except => [:index, :list, :list_without_layout, :show, :show_without_layout, :appear_comment_input_form, :fig2analysis, :category_search]
  verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :list }

  def index
    list
    render :action => 'list'
  end

  # == paginateを利用して、知見ドキュメントの一覧を表示する
  def list
    @user = (login=session[:user]) && User.find_by_login(login)
    
    # この部分のコードは仕方なく複雑な作りになっている。
    # paginate メソッドは内部的に find メソッドを使っているが
    # この find は Rails で定義されたオリジナルのものである。
    # 一方、使いたかったのは node.rb で再定義した find。
    # ということで、重複するが node.rb の find と同じような記述をした。
    # list_without_layout についても同様。
    if Knowledge.respond_to?("paginate")
      # for Rails 2.*
      other_readable_conditions = Node.conditions_to_read(@user)
      unless @user # 非ログイン状態
        conditions = " AND (#{other_readable_conditions})"
      else
        if @user.super_user
          conditions = ""
        elsif @user.groups == 0 # ユーザがグループに所属しない場合
          conditions = " AND (( (owner_id = #{@user.id}) OR (#{other_readable_conditions})))"
        else                    # ユーザが何らかのグループに所属する場合
          conditions = " AND (( (owner_id = #{@user.id}) OR NOT ((groups_readable & 1) = 0) OR (#{other_readable_conditions})))"
        end
      end
      
      # ソート
      unless params['sort']
        order = "mtime DESC"
      else
        case params['sort']
        when "time"
          sort_by = "mtime"
        when "author"
          sort_by = "creator"
        else
          sort_by = params['sort']
        end
        order = sort_by
        order += " DESC" if params['reverse_sort'] == 'reverse_sort'
      end
      
      # 絞り込み
      if params["commit"] == "Search"
        conditions += " AND (knowledges.category = \"#{params['category']}\")" unless params["category"] == ""
        conditions += " AND (knowledges.creator = \"#{params['creator']}\")" unless params["creator"] == ""
      end
      
      # ページングして表示する
      @knowledges = Knowledge.paginate_by_sql("SELECT knowledges.* FROM nodes, knowledges WHERE ((knowledges.node_id=nodes.id) AND (node_type=3) #{conditions} AND (knowledges.comment_on IS NULL)) ORDER BY #{order}", :page => params[:page], :per_page => GFDNAVI_PAGINATE_PER)
    else
      # for Rails 1.*
      @knowledge_pages, @knowledges = paginate :knowledges, :per_page => GFDNAVI_PAGINATE_PER
      @knowledge = Knowledge.find(:all, :user => @user, :order =>"mtime DESC")
    end
  end
  
  # == 他の画面に埋め込むために、
  # 画面上部のGfdnaviのメニューを出さずにlistを表示する
  # コメントの一覧表示などに使われる。
  def list_without_layout
    @list_without_layout = true
    @user = (login=session[:user]) && User.find_by_login(login)
    if params[:node_ids]
      node_ids = params[:node_ids]
    end
    
    # for Rails 2.*
    unless @user # 非ログイン状態
      conditions = " AND (#{other_readable_conditions})"
    else
      if @user.super_user
        conditions = ""
      elsif @user.groups == 0 # ユーザがグループに所属しない場合
        conditions = " AND (( (owner_id = #{@user.id}) OR (#{other_readable_conditions})))"
      else                    # ユーザが何らかのグループに所属する場合
        conditions = " AND (( (owner_id = #{@user.id}) OR NOT ((groups_readable & 1) = 0) OR (#{other_readable_conditions})))"
      end
    end

    # コメントの場合は古い順、そうでなければ新しい順に表示
    if params[:from] == "show_comments"
      order = "ORDER BY mtime"
    else
      order = "ORDER BY mtime DESC"
    end
    
    # Rails 1.* への対応
    if Knowledge.respond_to?("paginate")
      # for Rails 2.*
      @knowledges = Knowledge.paginate(:all, {:user => @user}, {:page => params[:page], :per_page => 5, :conditions => ["(node_id IN (?))", node_ids], :order =>"mtime DESC"})
    else
      # for Rails 1.*
      @knowledge_pages, @knowledges = paginate :knowledges, :per_page => 5
      @knowledges = []
      for nid in node_ids
        @knowledges.push(Knowledge.find(@user, :first, {:conditions => ["id = ?", nid]}))
      end
      @knowledges = @knowledges.uniq
      @knowledges.sort! {|a,b| b.mtime <=> a.mtime}
    end
    
    render :action => 'list'
  end

  # 知見ドキュメントの閲覧
  def show
    begin
      @user = (login=session[:user]) && User.find_by_login(login)
      @knowledge, @knowledge_figures, @comments, @image_paths, @image_widths, @image_heights, @caption_widths, @caption_heights = Knowledge.read_parameters_of_knowledge_document(params[:path], @user)
    rescue
      flash[:notice] = "The knowledge document doesn't exist."
      redirect_to :action => 'list'
    else
      @num_of_figure = 1 # コメント投稿欄を出現させたときに必要
    end
  end

  # 画面上部のGfdnaviのメニューを出さずにshowを実行する
  def show_without_layout
    @show_without_layout = true
    show
    render :action => 'show'
  end

  # list.rhtml -> new.rhtml (Click "New Knowledge" button.)
  def new
    @type = "new"
    @knowledge = Knowledge.new
    @user = (login=session[:user]) && User.find_by_login(login)
    @groups = @user.belonging_groups
    @num_of_figure = 1
  end

  # Click "Click a Knowledge Document with this/these Image(s)" button in Analysis
  def new_from_analysis
    @type = "new_from_analysis"
    @knowledge = Knowledge.new
    @user = (login=session[:user]) && User.find_by_login(login)
    @groups = @user.belonging_groups
    session[:knowledge] = Hash.new
    
    # 画面内にある絵の番号の配列を取得
    if (diagram_ids = session[:diagrams].dup)
      session[:knowledge_figure] = Hash.new
      session[:knowledge_figure]["diagram_ids"] = diagram_ids
    else
      raise "diagram is not found."
    end
    @num_of_figure = diagram_ids ? diagram_ids.length : 0
  end

  # Edit a knowledge document.
  # list.rhtml -> edit.rhtml (Click "Edit" link.)
  def edit
    @type = "edit"
    @user = (login=session[:user]) && User.find_by_login(login)
    @groups = @user.belonging_groups
    
    # 編集対象の文書の内容をあらかじめフォームに書き込んでおく
    @knowledge = Knowledge.find(:first, :conditions => ["path=?", params[:path]], :user => @user)
    unless @user == @knowledge.owner || @user.super_user
      flash[:notice] = "Sorry, you don't have the right to edit this document."
      redirect_to :action => "list"
    end
    session[:knowledge] = Hash.new
    session[:knowledge_figure] = Hash.new
    @figure_captions = Array.new
    @figure_paths = Array.new
    
    # 文書中の図についても同様
    knowledge_figures = @knowledge.knowledge_figures
    knowledge_figures.each do |kf|
      img = Image.find(kf.image_id, :user => @user)
      @figure_captions << kf.caption
      @figure_paths << img.path
    end

    @num_of_figure = @knowledge.knowledge_figures.length
  end

  # create a knowledge document in new.rhtml
  def create_from_new
    if params[:commit] == "Create"
      create
    else
      redirect_to :action => "new"
    end
  end

  # create a knowledge document in edit.rhtml
  def create_from_edit
    if (params[:commit] == "Save" || params[:commit] == "Save As")
      create
    else
      redirect_to :action => "edit", :path => params[:original_path]
    end
  end

  # == create a knowledge document in Analysis.
  # Save images in this method, and call create method to make a knowledge document.
  def create_from_analysis
    user = (login=session[:user]) && User.find_by_login(login)
    unless user
      redirect_to :controller=> "knowledge", :action => "index"
      return
    end
    
    ActiveRecord::Base::transaction do
      unless params[:commit] == "Create"
        redirect_to :action => "new_from_analysis"
      else
        # 画像を保存するためのパスチェック。
        # createメソッド内にも同じものがあるが、あちらは知見文書用。
        if check_path(params[:node]["path"]) == "path_error."
          redirect_to :action => "list"
          return
        end
        
        # === save images
        dirs = params[:node]["path"].split(File::Separator)[0..-2]
        dirname = dirs.join("/")
        dirname = dirname + "/" unless dirname == ""
        filename = params[:node]["path"].split(File::Separator)[-1]
        
        if params[:knowledge_figure]
          params[:knowledge_figure].each do |key, value|
            # determine realpath(絶対パス) for figure.
            case key.to_i
            when  0..9  then auto_figure_path = "image00" + key.to_s
            when 10..99 then auto_figure_path = "image0"  + key.to_s
            else             auto_figure_path = "image" + key.to_s
            end
            type = "diagram"
            name = value["filename"]
            
            if user.super_user
              value["figure_path"] = "/" + dirname + "." + filename + "/" + auto_figure_path
            else
              value["figure_path"] = "/usr/" + Knowledge.remove_scheme(user) + "/knowledge/" + dirname + "." + filename + "/" + auto_figure_path
            end
            
            # group
            group = params[:knowledge]["group_name"]
            
            # about groups
            unless params[:groups]
              groups = ['everyone']
              # raise "Check at least 1 group to visible!\n"
            else
              groups = params[:groups].values # Hash to Array
            end
            if groups[0] == 'everyone'
              other_mode = 4
              groups.shift
            else
              other_mode = 0
            end
            
            refs = Array.new
            var = Image.new
            
            diagram = DiagramCache.find(session[:diagrams][key.to_i - 1])
            viz = YAML.load(diagram.vizshot)
            ids = viz.get_variables.collect{|v|    # このブロックはとりあえずそのままにしているが、要対応
              if Variable===v && ! v.id
                from = v.fname
                to, pa = auto_file_path("data")
                File.move(from, to)
                v.path = pa + '/' + v.name
                v.owner = user
                v.other_mode = other_mode
                v.set_rgroups(groups) if groups.length > 0
                v.save!
              else
                v = Variable===v ? v : Variable.find(:first, :conditions=>["path=?",v],:user=>user)
              end
              refs << v.node
              v.id
            }
            var.vizshot = viz.to_yaml
            var.path = value["figure_path"] + ".png"
            name = var.name = File.basename(var.path)
            var.owner = user
            var.other_mode = other_mode
            var.node.set_rgroups(groups) if groups.length > 0
            
            from = value["diagram_path"]
            to = var.fname
            FileUtils.makedirs( File.dirname(to) )
            
            # 知見文書作成と同時に保存する画像にはkeyword_attributesはつけない

            
            ## If none, make directory.
            # make directories
            make_directories(var, user, groups, other_mode)

            # save images
            if var.save
              rtype = {"diagram"=>"draw", "data"=>"analyze"}[type]
              refs.each{|ref|
                NodeRelation.new(:name=>rtype, :reference=>ref, :referenced_by=>var.node).save!
              }
              FileUtils.copy( from, to )
            else
              flash[:notice] = "Failed to save images.\n"
              redirect_to :action => "list"
              return
            end
          end
        end
      end
      create
    end
  end

  # == create and save Knowledge Document
  # 変数 @knowledge と knowledge_figures に入力フォームから取得した値を代入して
  # 最後に save (temporary save も行う).
  # 
  # save, temporary save の場合分けは
  # * 一時保存ならバックアップのみ保存
  # * 上書き保存なら本体とバックアップの両方を保存
  # * そのほかの場合は本体のみ保存
  def create
#    print "========= create ==========\n"
#    print "params = "
#    pp params
    @user = (login=session[:user]) && User.find_by_login(login)
    add_a_comment_button_message = "Add a Comment on this document."
    
    # === knowledges table
    # * path check (上書き時、コメント時は自動でパスが決まっているので、チェックはしない)
    unless (params[:original_path] && params[:commit] == "Save") || (params[:commit] == add_a_comment_button_message) || (params[:commit] == "Temporary Save")
      if check_path(params[:node]["path"]) == "path_error."
        redirect_to :action => "list"
        return
      end
    end

    unless params[:commit]=="Save"
      @knowledge = Knowledge.new
    else
      # ==== Click "Save" button in edit.rhtml
      # * if "Save", insert all original data include "@Knowledge.id"
      begin
        @knowledge = Knowledge.find(:first, :conditions => ["path=?", params[:original_path]], :user => @user)
        @old_knowledge = Knowledge.new
        @old_knowledge.id = @knowledge.id
        @old_knowledge.attributes = @knowledge.attributes
        @old_knowledge.node.attributes = @knowledge.node.attributes
        @old_knowledge.knowledge_figures = @knowledge.knowledge_figures
      rescue
        raise "Specified knowledge is not found or not yours."
      end
    end

    # * about groups
    if (!params[:groups] || params[:commit] == add_a_comment_button_message)
      @groups = ['everyone']
    else
      # raise "Check at least 1 group to visible!\n" unless params[:groups]
      @groups = params[:groups].values # Hash to Array
    end
    
    if @groups[0] == 'everyone'
      other_mode = 4
      @groups.shift
    else
      other_mode = 0
    end
    @knowledge.other_mode = other_mode

    # * insert title, textbody(and change for RD-like format)
    #   , default_layout, horizontal number of figures
    #   , height/width, %/px, and size(number).
    horizontal_figures = params[:knowledge]["horizontal_figures"] || 1
    figures_size_status = params[:knowledge]["height_or_width"] == "width" ? 1 : 0
    figures_size_status += 2 if params[:knowledge]["percent_or_pixel"] == "pixel"
    figures_size_number = params[:knowledge]["figures_size_number"] || 100
    
    if params[:commit] == add_a_comment_button_message
      # for creating comment, insert knowledge.id to "comment_on"
      if (knowledge = Knowledge.find(:first, :conditions => ["path=?", params[:path]], :user => @user))
        @knowledge.attributes = {"comment_on" => knowledge.node_id}
      end
      # for creating comment, determine  "comment_number"      
      @knowledge.attributes = {"comment_number" => params[:knowledge]["comment_number"]}
    end

    @knowledge.attributes = {
      "category" => params[:knowledge]["category"],
      "title" => params[:knowledge]["title"],
      "creator" => params[:knowledge]["creator"],
      "textbody" => params[:knowledge]["textbody"],
      "description" => params[:knowledge]["description"],
      "default_layout" => params[:knowledge]["default_layout"] || 0,
      "horizontal_figures" => horizontal_figures,
      "figures_size_status" => figures_size_status,
      "figures_size_number" => figures_size_number
    }
    
    # === nodes table
    # * insert name, path, owner for knowledge.node
    @knowledge.name = params[:knowledge]["title"] + ".knlge"
    
    #   * 上書き時には、元のパスを用いる
    #   * それ以外の時は、入力されたパスを用いる
    if params[:commit] == "Save"
      begin
        @knowledge.path = params[:original_path]
      rescue
        flash[:notice] = "Unknown error. The path of original knowledge document doesn't exists."
        redirect_to :action => 'list'
      end
    else
      if params[:node]["path"] && params[:node]["path"] != ""
        filename = params[:node]["path"] + ".knlge"
      elsif params[:original_path]
        filename = params[:original_path] + ".knlge"
      else
        filename = ".knlge"
      end
      
      if @user.super_user
        @knowledge.path = "/" + filename
      else
        @knowledge.path = "/usr/"+ Knowledge.remove_scheme(@user) + "/knowledge/" + filename
      end
    end
    
    # 上書き保存時、たとえ元のユーザと別のユーザ(スーパーユーザなど)が書き換えたとしても、ownerは変更しない
    @knowledge.owner = @user unless params[:commit] == "Save"
    
    @knowledge.node.set_rgroups(@groups) if @groups.length > 0

    # if none, make directory.
    #   * path in the disc
    FileUtils.makedirs(File.dirname(@knowledge.fname)) or raise("failed to makedir")
    #   * path in gfdnavi
    make_directories(@knowledge, @user, @groups, other_mode)

    # === knowledge_figures table
    # if "Save", at first keep original knowledge_figures and keyword attributes 
    # that are already in the database. (delete them later.)
    if params[:commit]=="Save"
      old_knowledge_figures = KnowledgeFigure.find(:all, :conditions => ["knowledge_id = ?", params[:id]])
      old_keyword_attributes = KeywordAttribute.find(:all, :conditions => ["node_id = ?", @knowledge.node])
    end
    
    # paramsで渡された絵をArray(knowledge_figures)に格納
    knowledge_figures = Array.new
    if params[:knowledge_figure]
      params[:knowledge_figure].sort {|a, b| a[0].to_i <=> b[0].to_i}.each do |key, value| # 絵の順番を正しくソート
        figure_path = value["figure_path"]
        if figure_path && figure_path != ""
          unless img = Image.find(:first, :conditions => ["path=?", figure_path + ".png"], :user => @user)
            raise "Image file #{figure_path} is not found."
          end
          knowledge_figure = KnowledgeFigure.new(:caption => value["figure_caption"], :image_id => img.node_id)
          knowledge_figure.knowledge = @knowledge
          knowledge_figures.push(knowledge_figure)
        end
      end
    end

    # 保存しようとしているknowledgeオブジェクトに絵を関連付ける
    @knowledge.knowledge_figures = knowledge_figures

    # 検索用に、title と textbody と author(creator) と category を keyword_attributes に入れる。
    @knowledge.keyword_attributes.build(:name => "title", :value => params[:knowledge]["title"])
    @knowledge.keyword_attributes.build(:name => "textbody", :value => params[:knowledge]["textbody"])
    @knowledge.keyword_attributes.build(:name => "description", :value => params[:knowledge]["description"])
    @knowledge.keyword_attributes.build(:name => "creator", :value => params[:knowledge]["creator"])
    @knowledge.keyword_attributes.build(:name => "category", :value => params[:knowledge]["category"])

    # 更新時、mtimeを上書き
    @knowledge.mtime = Time.new unless params[:commit] == "Create"
    
    # * 一時保存ならバックアップのみ保存
    # * 上書き保存なら本体とバックアップの両方を保存
    # * そのほかの場合は本体のみ保存
    if params[:commit] == "Temporary Save"
      create_backup
      @type = params[:type]
      @knowledge = Knowledge.find(params[:document_id], :user => @user) if @type == "edit"
      render :partial => "backup"
    else
        print "==== Save a document =========-\n"
        print "@knowledge = "
        pp @knowledge
        print "_________________________________\n"

      # 知見文書の save
      unless @knowledge.save
        if params[:knowledge]["title"] == ""
          flash[:notice] = "Title is empty. Failed to save."
          redirect_to :action => "list"
        else
          flash[:notice] = "Failed to save."
          redirect_to :action => 'list'
        end
      else
        # === 成功の場合。
        # Create, Save, Save As, new_from_analysis, comment

        # temporary backupを消す
        temporary_backups = KnowledgeBackup.find(:all, :conditions => ["backup_on=? AND temporary", @knowledge.path])
        temporary_backups.each do |tb|
          tb.destroy
        end

        # メッセージを出す
        if params[:commit] == add_a_comment_button_message
          flash[:notice] = "A comment is successfully saved."
        else
          flash[:notice] = "A knowledge document is successfully saved."
        end

        # 上書き保存のとき、バックアップを別テーブルに保存しておく
        if params[:commit] == "Save"
          create_backup
        end
        
        # + node_relations table
        # * 画像から数値データへと辿り、node_relationsテーブルに
        #   知見文書 -> 数値データへの関係を格納する
        # * knowledgeのnode_idが必要なので、保存後である必要がある。
        # ++ Save のときのみ、前の node_relations を消す
        if params[:commit] == "Save"
          old_node_relations = NodeRelation.find(:all, :conditions => ["name=? AND referenced_by=?", "based_on", @knowledge.node_id])
          old_node_relations.each do |relation|
            relation.destroy
          end
        end
        # ++ node_relations テーブルに関係を記録する
        begin
          variable_paths = Array.new
          knowledge_figures.each do |figure|
            image = Image.find(figure.image_id, :user => @user)
            vizshot_yaml = image.vizshot
            vizshot = YAML.load(vizshot_yaml)
            analysis = Analysis.from_vizshot(vizshot)

            analysis.attributes["variables"].each do |variable|
              node_of_variable = Node.find(variable.node_id)
              node_relation = NodeRelation.new
              node_relation.attributes = {:reference => node_of_variable, :referenced_by => @knowledge.node, :name => "based_on"}
              variable_paths.push(variable.path)
              node_relation.save
            end
          end
        rescue
          flash[:notice] = "Unknown error is occurred when NodeRelation objects are created."
        end

        if variable_paths.length > 0
          node_relation_hash = {"reference" => []}
          variable_paths.uniq.each do |vpath|
            node_relation_hash["reference"].push({"name" => "based_on", "path" => vpath})
          end
        end
        
        # If "Save", delete original knowledge_figures.
        if params[:commit] == "Save"
          old_knowledge_figures.each do |old_knowledge_figure|
            old_knowledge_figure.destroy
          end
          old_keyword_attributes.each do |old_keyword_attribute|
            old_keyword_attribute.destroy
          end
        end
        
        # == .knlge ファイル作成
        # * knowledge テーブルの要素
        if (comment_on = @knowledge.comment_on && Knowledge.find(@knowledge.comment_on, :user => @user))
          comment_on_path = comment_on.path
        else
          comment_on_path = nil
        end
        
        knowledge_hash = {
          "gfdnavi_knowledge" =>
          {
            "title" => @knowledge.title,
            "creator" => @knowledge.creator,
            "category" => @knowledge.category,
            "textbody" => @knowledge.textbody,
            "description" => @knowledge.description,
            "default_layout" => @knowledge.default_layout,
            "horizontal_figures"=> @knowledge.horizontal_figures,
            "knowledge_figures" => [],
            "owner" => @knowledge.owner.login,
            "figures_size_status" => @knowledge.figures_size_status,
            "figures_size_number" => @knowledge.figures_size_number,
            "comment_on" => comment_on_path,
            "comment_number" => @knowledge.comment_number,
            "rgroups" => @groups,
            "other_mode" => @knowledge.other_mode
          }}
        # * knowledge_figures テーブルの要素
        @knowledge.knowledge_figures.length.times do |i|
          image_id = @knowledge.knowledge_figures[i].image_id
          image_path = Image.find(image_id, :user => @user).path          
          knowledge_hash["gfdnavi_knowledge"]["knowledge_figures"].push({"image_path" => image_path, "caption"  => @knowledge.knowledge_figures[i].caption})
        end
        
        # * node_relation テーブルの要素
        knowledge_hash["gfdnavi_knowledge"].merge!(node_relation_hash) if node_relation_hash
        
        # * .knlgeファイルへの書き込み
        File.open(@knowledge.fname,"w"){|file| file.print knowledge_hash.to_yaml}

        # * コメントなら、元のドキュメントへ redirect
        if params[:commit] == add_a_comment_button_message
          @knowledge, @knowledge_figures, @comments, @image_paths, @image_widths, @image_heights, @caption_widths, @caption_heights = Knowledge.read_parameters_of_knowledge_document(params[:path], @user)
          @num_of_figure = 1 # コメント投稿欄を出現させたときに必要
          @displayed_knowledge = @knowledge
          render :partial => 'comments'
        else
          redirect_to :action => 'show', :path => @knowledge.path
        end
      end
    end
  end

  # == Save backup of knowledge, knowledge figures.
  # params[commit]が "Save" か "Temporary Save" のときに呼ばれる。
  def create_backup
    # === search backups of knowledge.
    if params[:commit] == "Temporary Save"
      saved_backup = @knowledge
      new_version_number = 0
    else
      saved_backup = @old_knowledge
      backups = KnowledgeBackup.find(:all, :conditions => ["backup_on=?", @knowledge.path])
      if backups.length > 0
        backups.collect! {|backup|
          backup = backup.version_number
        }
        new_version_number = backups.max + 1
      else
        new_version_number = 1
      end
    end
    
    # === knowledge_backups Table. 
    knowledge_backup = KnowledgeBackup.new
    knowledge_backup.attributes = {
      "title" => saved_backup.title,
      "creator" => saved_backup.creator,
      "textbody" => saved_backup.textbody,
      "description" => saved_backup.description,      
      "default_layout" => saved_backup.default_layout || 0,
      "horizontal_figures" => saved_backup.horizontal_figures,
      "figures_size_status" => saved_backup.figures_size_status,
      "figures_size_number" => saved_backup.figures_size_number,
      "comment_on" => saved_backup.comment_on,
      "comment_number" => saved_backup.comment_number,
      "mtime" => saved_backup.mtime,
      "backup_on" => saved_backup.path,
      "version_number" => new_version_number,
      "temporary" => (params[:commit]=="Temporary Save"),
      "owner_id" => @user.id,
      "rgroups" => @groups,
      "other_mode" => saved_backup.other_mode
    }
    
    @knowledge.id = params[:original_id] if params[:commit] == "Temporary Save"
    knowledge_backup.temporary = (params[:commit] == "Temporary Save")
    knowledge_backup.backup_on = @knowledge.path || "temporarily_backup"
    
    # === knowledge_figure_backups Table.
    knowledge_figure_backups = Array.new
    if params[:knowledge_figure]
      params[:knowledge_figure].sort {|a, b| a[0].to_i <=> b[0].to_i}.each do |key, value| # 絵の順番を正しくソート        
        if value["figure_path"] && value["figure_path"] != ""
          unless img = Image.find(:first, :conditions => ["path=?", value["figure_path"] + ".png"], :user => @user)
            raise "Image file #{figure_path} is not found."
          end
          knowledge_figure_backup = KnowledgeFigureBackup.new(:caption => value["figure_caption"], :image_id => img.node_id)
          knowledge_figure_backup.knowledge_backup = knowledge_backup
          knowledge_figure_backups.push(knowledge_figure_backup)
        elsif value["diagram_path"] && value["diagram_path"] != ""
          knowledge_figure_backup = KnowledgeFigureBackup.new(:caption => value["figure_caption"])
          knowledge_figure_backup.knowledge_backup = knowledge_backup
          knowledge_figure_backups.push(knowledge_figure_backup)
        end
      end
    end
    knowledge_backup.knowledge_figure_backups = knowledge_figure_backups
    unless knowledge_backup.save
      flash[:notice] = "The backup failed to save."
    end
    
    # create ".knlge" file for backup.
    # * knowledge_backups Table.
    knowledge_backup_hash = {
      "gfdnavi_knowledge" =>
      {
        "title" => saved_backup.title,
        "creator" => saved_backup.creator,
        "category" => saved_backup.category,
        "textbody" => saved_backup.textbody,
        "description" => saved_backup.description,
        "default_layout" => saved_backup.default_layout,
        "horizontal_figures"=> saved_backup.horizontal_figures,
        "knowledge_figures" => [],
        "owner" => saved_backup.owner.login,
        "figures_size_status" => saved_backup.figures_size_status,
        "figures_size_number" => saved_backup.figures_size_number,
        "comment_on" => saved_backup.comment_on,
        "comment_number" => saved_backup.comment_number,
        "backup_on" => saved_backup.path,
        "version_number" => new_version_number,
        "temporary" => (params[:commit]=="Temporary Save"),
        "rgroups" => @groups,
        "other_mode" => saved_backup.other_mode
      }}
    # * knowledge_figure_backups Table
    saved_backup.knowledge_figures.length.times do |i|
      image_id = saved_backup.knowledge_figures[i].image_id
      image_path = Image.find(image_id, :user => @user).path
      knowledge_backup_hash["gfdnavi_knowledge"]["knowledge_figures"].push({"image_path" => image_path, "caption"  => @knowledge.knowledge_figures[i].caption})
    end

    # バージョンつきのバックアップは、.knlgeファイルとして保存する
    unless params[:commit]=="Temporary Save"
      File.open(saved_backup.fname[0..-7] + "." + new_version_number.to_s + ".knlge","w"){|file| file.print knowledge_backup_hash.to_yaml}
    end
  end
  
  # == 知見文書をデータベースとディスクから消去する
  def destroy
    @user = (login=session[:user]) && User.find_by_login(login)
    knowledge = Knowledge.find(:first, :conditions => ["path=?", params[:path]], :user => @user)
    
    # 関連するコメントのデータベースからの消去
    comments = Knowledge.find(:all, :conditions => ["comment_on=?", knowledge.node_id])
    comments.each do |comment|
      comment.destroy
    end
    
    # node_relations テーブルからの関係の消去
    node_relations = NodeRelation.find(:all, :conditions => ["name=? AND referenced_by=?", "based_on", knowledge.node_id])
    node_relations.each do |nr|
      nr.destroy
    end
    
    # ディスクから .knlge ファイルを消去
    File.delete(knowledge. fname)

    # データベースからの消去
    knowledge.destroy

    if knowledge.comment_on
      # コメントを削除する場合
      @knowledge, @knowledge_figures, @comments, @image_paths, @image_widths, @image_heights, @caption_widths, @caption_heights = Knowledge.read_parameters_of_knowledge_document(params[:parent_path], @user)
      @displayed_knowledge = @knowledge
      render :partial => 'comments'
    else
      # コメントでない、普通の知見文書を削除する場合
      redirect_to :action => 'list'
    end
  end
  
  def destroy_backup
    @user = (login=session[:user]) && User.find_by_login(login)
    @type = params[:type]
    @knowledge = Knowledge.find(params[:document_id], :user => @user) if @type == "edit"

    @knowledge_backup = KnowledgeBackup.find(params[:backup_id])
    knowledge_figure_backup = KnowledgeFigureBackup.new

    # .knlgeファイルの消去
    # File.delete(@knowledge.fname)

    # データベースからの消去
    flash[:notice] = "A backup file is failed to delete." unless @knowledge_backup.destroy

    render :partial => "backup"
  end

  
  # == show.rhtmlの下部にコメント作成用のフォームを出現させる
  def appear_comment_input_form
    # 出現するフォームは partial で埋め込まれているので、
    # 非ログイン時、 before_filter :login_required を使わずに
    # ログイン後は一旦 index (list.rhtml) まで戻ってもらう。
    unless @user = (login=session[:user]) && User.find_by_login(login)
      redirect_to :controller => "user", :action => "login"
    else
      # これらの変数は各コメントを表示する際に上書きされてしまっているので
      # ここで、コメントのつけられた、元のドキュメントの値を再び代入しておく。
      @knowledge, @knowledge_figures, @comments, @image_paths, @image_widths, @image_heights, @caption_widths, @caption_heights = Knowledge.read_parameters_of_knowledge_document(params[:path], @user)
      @num_of_figure = 1
      @type = "comment"

      # editと同様、@knowledge の中身がそのままフォームに入る。
      # しかし、コメントの場合はそのまま入っては困るので、ここで加工しておく。
      new_comment_number = @comments.collect{|comment| comment.comment_number}.max || 0 + 1
      @knowledge.title = "Re[#{new_comment_number}]:"+ @knowledge.title
      @knowledge.creator = @user.full_name
      @knowledge.textbody = ""
      @knowledge.description = ""
      render :partial => "comment_input_form"
    end
  end

  # == 知見ドキュメント作成フォーム内の、グループの可視性の入力部分を knowledge テーブルから書き戻す。
  def restore_group_form
    @user = (login=session[:user]) && User.find_by_login(login)
    @groups = @user.belonging_groups
    render :partial => "group_form"
  end

  # == 知見ドキュメント作成フォーム内の、図の入力部分を knowledge_figure_backups テーブルから書き戻す。
  def restore_knowledge_figure_form
    @type = params[:type]
    @user = (login=session[:user]) && User.find_by_login(login)
    @groups = @user.belonging_groups
    
    # list.rhtml -> edit.rhtml (Click "Edit".)
    @knowledge = KnowledgeBackup.find(params[:id])
    @figure_captions = Array.new
    @figure_paths = Array.new

    knowledge_figures = @knowledge.knowledge_figure_backups
    knowledge_figures.each do |kf|
      @figure_captions << kf.caption
      if (img = Image.find(kf.image_id, :user => @user))
        # 一時保存のときは、このimage_idがnullになる。
        @figure_paths << img.node.path
      else
        @figure_paths << kf.temporarily_image_path
      end
    end

    @num_of_figure = @knowledge.knowledge_figure_backups.length
    render :partial => "knowledge_figure_form"
  end
  
  # == 存在するカテゴリーのリストを取り出す
  def category_search
    @categories = Array.new
    Knowledge.find(:all, :group => "category", :conditions => ['category LIKE ?', params[:keyword] + '%'], :order => "category").each do |knowledge|
      @categories << knowledge.category
    end
    
    render :partial => 'category_table'
  end

  # /view/knowledge/_layout_figure.rhtml で使用
  def fig2analysis
    user = (login=session[:user]) && User.find_by_login(login)
    vizshot_yaml = Image.find(params[:image_id], :user => user).vizshot
    vizshot = YAML.load(vizshot_yaml)

    analysis = Analysis.from_vizshot(vizshot)

    session[:analysis] = analysis
    variable = Array.new
    variable = [analysis.attributes["variables"], Node.find(analysis.attributes["variables"][0].attributes["node_id"], :user => user).path]
    session[:variables_list] = variable

    redirect_to :controller => "analysis", :action => "index"
  end

  private
  def make_directories(obj, user, groups, other_mode)
    full_path = ""
    parent = nil

    obj.path.split(File::Separator)[0..-2].each{|dname|
      full_path = File.join(full_path, dname)
      dir = Directory.find(:first, :conditions=>["path=?",full_path], :user=>user)
      unless dir
        dir = Directory.new
        dir.name = dname
        dir.path = full_path
        dir.parent = parent.node
        dir.owner = user
        dir.other_mode = other_mode
        dir.node.set_rgroups(groups) if groups.length > 0
        if full_path == obj.file
          dir.downloadable = obj.downloadable?
          dir.plain_file = true
        end
        dir.save!
      end
      parent = dir
    }
  end
  
  # == 入力されたパスが正しいかどうかを調べる
  # // などが無いか調べる。
  def check_path(path)
    case path
    when /\.\.\//
      flash[:notice] = '"../" cannot be used in path.'
      return "path_error."
    when /^\s*$/
      flash[:notice] = 'Path cannot be empty.'
      return "path_error."
    when /^\s*\//, /\/\s*$/, /\/\s*\//
      flash[:notice] = "Directory that doesn't have name is forbidden."
      return "path_error."
    when /\_comment\_/
      flash[:notice] = "\"_comment_\" is forbidden string."
      return "path_error."
    when /\.\d\.$/
      flash[:notice] = "\".number.knlge\" is forbidden string."
      return "path_error."
    end
  end

end


