desc "Setup all"
task :setup => :environment do
  if exist_tables.include?("nodes") && Node.count > 0
    print "This will clear all the database tables.\n"
    print "If you want just to update database tables, use \"rake update\" instead.\n"
    print "Are you sure to continue? (no/yes, default:no) "
    res = $stdin.gets.chomp!
    unless res == "yes"
      abort "execution was canceled"
    end
  end
  Rake::Task["setup:tables"].invoke
  Rake::Task["setup:tree"].invoke
  Rake::Task["setup:functions"].invoke
  Rake::Task["setup:draw_methods"].invoke
end

namespace :setup do
  desc "Setup database tables"
  task :tables => :environment do
    command = 'ruby "' + File.join(File.expand_path(RAILS_ROOT), 'db', 'dump_db.rb') + '"'
    unless system( command )
      raise "failed to execute '#{command}'"
    end
    pw = nil
    if User.table_exists? && (root = User.find_by_login('root'))
      print "Do you want to keep root's password? (yes/no, default:yes): "
      res = $stdin.gets.chomp!
      unless res == "no"
        pw = root.password
      end
    end

        pw2 = "temporary_password"
    if !pw
      if /mswin(?!ce)|mingw|bccwin/ =~ RUBY_PLATFORM
      else
        system("stty -echo > /dev/null 2>&1") #for unix-like systems
      end
      while true
        while true
          print "Input password for root (number of characters must be 5 to 40): "
          pw2 = $stdin.gets.chomp!
          if pw2.length < 5
            print "The password which you input is too short.\n"
          elsif pw2.length > 40
            pinnt "The password which you input is too long.\n"
          else
            break
          end
        end
        print "\nRepeat password: "
        tmp = $stdin.gets.chomp!
        break if tmp == pw2
        print "\nNot correct!\n"
      end
      if /mswin(?!ce)|mingw|bccwin/ =~ RUBY_PLATFORM
      else
        system("stty echo > /dev/null 2>&1") #for unix-like systems
      end
      print("\n")
    end

    connection = ActiveRecord::Base.connection
    connection.drop_table("schema_info") if connection.tables.include?("schema_info")
    Rake::Task["db:migrate"].invoke
    root = User.new( :login => "root",
		     :full_name => "default super user",
		     :email_address => GFDNAVI_ADMIN_EMAIL,
		     :affiliation => "GFDNAVI",
                     :password => pw2,
                     :password_confirmation => pw2 )
    root.super_user = true
    root.save!
    if pw
      root.password = pw
      root.save!
    end

  end

  desc "Set root password"
  task :root_password => :environment do
    if root = User.find_by_login("root")
      if /mswin(?!ce)|mingw|bccwin/ =~ RUBY_PLATFORM
      else
        system("stty -echo > /dev/null 2>&1") #for unix-like systems
      end
      while true
        while true
          print "Input password for root (number of characters must be 5 to 40): "
          pw2 = $stdin.gets.chomp!
          if pw2.length < 5
            print "The password which you input is too short.\n"
          elsif pw2.length > 40
            pinnt "The password which you input is too long.\n"
          else
            break
          end
        end
        print "\nRepeat password: "
        tmp = $stdin.gets.chomp!
        break if tmp == pw2
        print "\nNot correct!\n"
      end
      if /mswin(?!ce)|mingw|bccwin/ =~ RUBY_PLATFORM
      else
        system("stty echo > /dev/null 2>&1") #for unix-like systems
      end
      print("\n")
      if root.change_password(pw2,tmp)
        print "changing was succeded\n"
      else
        print "changing was not succeded\n"
      end
    end
  end

  desc "Setup tree of directories and variables"
  task :tree => :environment do
    Rake::Task["clean:diagram_cache"].invoke
    %w( draw_parameters
      keyword_attributes spatial_and_time_attributes
      node_relations
      knowledge_figures knowledges
      actual_files images variables directories
      nodes).each{|table_name|
      if exist_tables.include?(table_name)
        model = ActiveRecord.class_eval(table_name.classify)
	model.delete_all
      end
    }
    command = 'ruby "' + File.join(File.expand_path(RAILS_ROOT), 'db', 'register_directory_tree.rb') + '"'
    unless system( command )
      raise "failed to execute '#{command}'"
    end
  end

  desc "Setup default functions database"
  task :functions => :environment do
    print "registeration functions\n"
    create_value_type_table
    unless Function.table_exists?
      raise "functions table does not exist"
    end
    unless FunctionOutput.table_exists?
      raise "function_outputs table does not exist"
    end
    unless FunctionArgument.table_exists?
      raise "function_arguments table does not exist"
    end
    FunctionArgument.delete_all
    FunctionOutput.delete_all if FunctionOutput.table_exists?
    Function.delete_all if Function.table_exists?
    Node.delete_all(['node_type = ?',Node::FUNCTION])
    dir = File.join(File.expand_path(RAILS_ROOT), 'db', 'functions')
    root = User.find_by_login("root")
    regist_functions(dir, root, true)
    Dir.foreach(GFDNAVI_USER_PATH){|dname|
      user = User.find_by_login(dname)
      dir = File.join(GFDNAVI_USER_PATH, dname, "functions")
      if user && File.exist?(dir)
        regist_functions(dir, user)
      end
    }
  end

  desc "Setup default draw methods database"
  task :draw_methods => :environment do
    print "registeration draw methods\n"
    create_value_type_table
    unless DrawMethod.table_exists?
      raise "draw_methods table does not exist"
    end
    unless DrawMethodAttribute.table_exists?
      raise "draw_method_attributes table does not exist"
    end
    DrawMethodAttribute.delete_all
    DrawMethod.delete_all 
    Node.delete_all(['node_type = ?',Node::DRAW_METHOD])
    dir = File.join(File.expand_path(RAILS_ROOT), 'db', 'draw_methods')
    root = User.find_by_login("root")
    regist_draw_methods(dir, root, true)
    Dir.foreach(GFDNAVI_USER_PATH){|dname|
      user = User.find_by_login(dname)
      dir = File.join(GFDNAVI_USER_PATH, dname, "draw_methods")
      if user && File.exist?(dir)
        regist_draw_methods(dir, user)
      end
    }
  end    

end



def create_value_type_table
  if ValueType.table_exists?
    %w(int float string array_int array_float array_string boolean).each{|typ|
      ValueType.new(:name => typ).save! unless ValueType.find_by_name(typ)
    }
  end
end


def regist_functions(dir, user, default=false)
  path = "/usr/#{user.login}/functions"
  Node.make_user_directory(path, user, default ? 4 : 0)
  Dir.foreach(dir){|yml|
    next unless /\.yml$/=~yml
    fname = File.join(dir,yml)
    fixture = YAML.load( File.read(fname) )
    arguments = fixture.delete(:arguments)
    outputs = fixture.delete(:outputs)
    func = Function.new
    fixture.each{|k,v|
      func.send(k.to_s+"=",v)
    }
    func.path = File.join(path, func.name)
    func.owner = user
    func.default = default
    func.other_mode = default ? 4 : 0
    Function.transaction{
      FunctionOutput.transaction{
        FunctionArgument.transaction{
          func.save!
          func.function_outputs.create(outputs)
          if arguments
            arguments.each{|arg|
              typ = arg.delete(:value_type)
              fa = FunctionArgument.new(arg)
              fa.value_type = ValueType.find_by_name(typ)
              fa.function = func
              fa.save!
            }
          end
        }
      }
    }
  }
end



def exist_tables
  ActiveRecord::Base.connection.tables
end


def regist_draw_methods(dir, user, default=false)
  path = "/usr/#{user.login}/draw_methods"
  Node.make_user_directory(path, user, default ? 4 : 0)
  Dir.foreach(dir){|yml|
    next unless /\.yml$/=~yml
    fname = File.join(dir,yml)
    fixture = YAML.load( File.read(fname) )
    attrs = fixture.delete(:attributes)
    dm = DrawMethod.new
    fixture.each{|k,v|
      dm.send(k.to_s+"=",v)
    }
    dm.path = File.join(path, dm.name)
    dm.owner = user
    dm.default = default
    dm.other_mode = default ? 4 : 0
    DrawMethod.transaction{
      DrawMethodAttribute.transaction{
        dm.save!
        if attrs
          attrs.each{|attr|
            typ = attr.delete(:type)
            unless typ
              raise "type must be set for attributes"
            end
            dma = DrawMethodAttribute.new(attr)
            dma.value_type = ValueType.find_by_name(typ)
            dma.draw_method = dm
            dma.save!
          }
        end
      }
    }
  }
end
