require 'net/ssh'
require 'pathname'
namespace :create_site do
  desc "Create Site Script"
  task :create_site,[:git_template_url,:git_extension_url,:git_url,:ip, :server_port,:user,:password,:site_name,:domain_name,:port,:db_name,:path,:site_construct_id] => :environment do |task,args|
    @password = args.password
    if args.site_construct_id.blank?
      @site_construct = SiteConstruct.new
      @site_construct.server_type = (SiteServer.where(:ip=>args.ip).first.server_name rescue args.ip)
      @site_construct.site_name = args.site_name
      @site_construct.domain_name = args.domain_name
      @site_construct.db_name = args.db_name.gsub(" ","")
      @site_construct.port = args.port
      @site_construct.path = args.path
      @site_construct.school_name = args.site_name.split(/[-_]/)
      @site_construct.user_id = User.first.id.to_s
      @site_construct.save
    else
      @site_construct = SiteConstruct.find(args.site_construct_id)
    end
    begin
      @site_construct.update(:status=>"creating")
      @site_construct.update!(:infos=>[])
      begin 
        Net::SSH.start(args.ip , args.user , { password: args.password, port: args.server_port}) do |ssh|
        end
      rescue Net::SSH::HostKeyMismatch
        system("ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{args.ip}")
      rescue Errno::ENOTTY
        system("ssh-add \"$HOME/.ssh/id_rsa\"")
      end
      Net::SSH.start(args.ip , args.user , { password: args.password, port: args.server_port}) do |ssh|
        update_infos("setting nginx for #{args.site_name}")
        nginx_setting_texts = @site_construct.generate_nginx_text
        exec_ssh_command_by_sudo_for_create(ssh,"touch /etc/nginx/orbit_sites/#{@site_construct.get_site_name}")
        exec_ssh_command_by_sudo_for_create(ssh,"x='#{nginx_setting_texts.gsub(/'{1,3}/,"\"\'\"")}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' >  /etc/nginx/orbit_sites/#{@site_construct.get_site_name}\"")
        update_infos("restarting nginx")
        exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' service nginx restart")
        update_infos("finish restarting nginx")
        exec_ssh_command_by_sudo_for_create(ssh,"mkdir -p #{args.path}")
        update_infos("cloning orbit4-5 from #{args.git_url} to #{args.path}/#{args.site_name}")
        exec_ssh_command_by_sudo_for_create(ssh,"git clone #{args.git_url} #{args.path}/#{@site_construct.get_site_name}")
        exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && git submodule add #{args.git_template_url} app/templates/default-theme'")
        exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && git submodule add #{args.git_extension_url} modules'")
        exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && git submodule update --init --recursive'")
        ssh.exec!("bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && ln -s modules/* .'")
        exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{@site_construct.get_site_name} -R")
        exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{@site_construct.get_site_name.gsub(" ","\\ ")} -R")
        db_setting_text = ssh.exec!("cat #{args.path}/#{@site_construct.get_site_name}/config/mongoid.yml")
        update_infos("setting dbname to #{@site_construct.db_name}")
        exec_ssh_command_by_sudo_for_create(ssh,"sh -c \"echo '#{db_setting_text.gsub("orbit_4_5",@site_construct.db_name)}' > #{args.path}/#{@site_construct.get_site_name}/config/mongoid.yml\"",true)
        rvm_path = ssh.exec!("which rvm").to_s.strip
        if rvm_path.blank?
          rvm_path = "/home/#{args.user}/.rvm/bin/rvm"
        end
        gemdir = ssh.exec!("#{rvm_path} gemdir").to_s
        if gemdir.include?("No such file or directory")
          ls = ssh.exec!("echo `ls /home`").to_s.split
          ls.each do |d|
            rvm_path = "/home/#{d}/.rvm/bin/rvm"
            gemdir = ssh.exec!("#{rvm_path} gemdir").to_s
            break if !gemdir.to_s.include?("No such file or directory")
          end
          if gemdir.include?("No such file or directory")
            rvm_path = "/usr/share/rvm/bin/rvm"
            gemdir = ssh.exec!("#{rvm_path} gemdir").to_s
          end
        end
        if gemdir.include?("No such file or directory")
          update_infos("please connect your admin to install rvm on #{args.ip}")
          @site_construct.update(:status =>"error")
        else
          bundle_dir = gemdir.gsub("\n","") + '/bin/bundle'
          update_infos("execing bundle install...")
          exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nbundle install'",true)
          exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nbundle install'")
          update_infos("finish execing bundle install")
          update_infos("starting #{args.site_name} web server to development")
          outputs = exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nkill -s TERM `fuser tmp/unicorn.sock`\nsudo -p \"sudo password:\" kill -s TERM `sudo -p \"sudo password:\" fuser tmp/unicorn.sock`\nsudo -p \"sudo password:\" rm -f tmp/pids/unicorn.pid\nbundle exec unicorn_rails -c config/unicorn.rb -D -E development\n'")
          if outputs.include? "not writable"
            exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{@site_construct.get_site_name} -R")
            exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{@site_construct.get_site_name} -R")
          end
          update_infos("finish creating #{args.site_name}")
		      exec_ssh_command_by_sudo_for_create(ssh,"chmod 777 #{args.path}/#{@site_construct.get_site_name} -R")
          @site_construct.update(:status =>"finish")
          puts "finish creating #{args.site_name} on #{args.ip}"
        end
      end
    rescue =>e
      @site_construct.update(:status =>"error",:infos=>@site_construct.infos.push("#{e}"))
    end
  end
  def exec_ssh_command_by_sudo(session,command)
    output = session.exec!("echo '#{@password}' | sudo -S #{command}")
    # output = session.exec!("echo '#{@password}' | sudo -S -s #{command}")
    if output.include?("sudo:") && output.include?("command not found")
      output = session.exec!(command)
    end
    return output.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
  end
  def update_thread_infos_for_exec(info,update_last=false)
    if update_last
      @thread.status["infos"][-1] += info
    else
      @thread.status["infos"] = @thread.status["infos"].push(info)
    end
    @thread.save!
    return @thread.status["infos"]
  end
  def exec_ssh_command_for_create(session,command,update=false)
    outputs = []
    session.open_channel do |channel|
      channel.request_pty do |channel, success|
        channel.exec("LANG=en.UTF8 #{command}") do |ch, success|
          abort "could not execute command: #{command}" unless success
          channel.on_data do |ch, data|
            outputs.push(data)
            print "#{data}"
            if update
              if data.include? "\n"
                update_infos_for_exec(data)
              else
                update_infos_for_exec(data,true)
              end
            end
            if data.to_s.include?("sudo password:") || data.to_s.include?("Password:")
              channel.send_data "#{@password}\n"
            end
          end
        end
      end
    end
    session.loop
    return outputs
  end
  def exec_ssh_command_by_sudo_for_create(session,command,update=false)
    outputs = exec_ssh_command_for_create(session,command,update)
    tmp = outputs.join("\n")
    if tmp.include?("Permission denied") || tmp.include?("Operation not permitted")
      outputs = exec_ssh_command_for_create(session,"sudo -p 'sudo password:' #{command}",update)
      tmp = outputs.join("\n")
    end
    return tmp
  end
  def update_infos_for_exec(info,update_last=false,update_array=false)
    return if @site_construct.nil?
    info.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
    if update_last && !@site_construct.infos.empty?
      @site_construct.infos[-1] += info.to_s
    else
      if update_array
        @site_construct.infos += info
      else
        @site_construct.infos.push(info.to_s)
      end
    end
    @site_construct.save!
    return @site_construct.infos
  end
  def update_infos(info)
    puts info
    @site_construct.infos = @site_construct.infos.push(info)
    @site_construct.save!
    return @site_construct.infos
  end
end