# coding : utf-8
require 'open3'
require 'erb'
require 'pathname'
require 'fileutils'
require 'base64'
require 'yaml'
require 'kconv'


module Consts
  module DIR
    ROOT = Pathname(File.expand_path("..", __FILE__))
    SWAP = ".swp"
    BACKUP = ".vimbackups"
    SCRIPT = ROOT + ".scripts"
    VIMPROC = ROOT + "bundle/vimproc"
  end

  module PATH
    GistVimConfig = Pathname(File.expand_path("~/.gist-vim"))
    GitHubConfig = DIR::ROOT + File.expand_path("github.conf")
  end

  module URL
    VIMPROC = lambda{|arch| "https://github.com/downloads/Shougo/vimproc/vimproc_win#{arch}-ver.7.0.zip"}
  end

  module GCC
    Target = "ターゲット"   # if LANG=ja*
  end

  RCPATH = %(<%= Pathname(ENV["HOME"]) + ("." + rc) %>)
  CLEAN_IGNORE = %w(.gitkeep)
  RICTY_SH = "install_ricty.sh"

  RCSCRIPT =<<-EOS
" Loads x-platform rc
let vimrc_path=expand('$HOME/<%= vimdir %>/<%= rc %>')
if filereadable(vimrc_path)
  exe "source ".vimrc_path
endif
unlet vimrc_path

" vim:set ts=8 sts=2 sw=2 tw=0:
  EOS

end

module Helper
  include Consts

  class << self
    include Consts

    def repo_root
      DIR::ROOT
    end

    def encode64(s)
      if RUBY_VERSION < "1.9"
        Base64.b64encode(s)
      else
        Base64.encode64(s)
      end
    end

    def git_installed?
      stderr_exists?("git version")
    end

    def stderr_exists?(cmd)
      Open3.popen3(cmd) do |_in, _out, _err|
        err = _err.read
        return err.nil? || err.empty?
      end
    end

    def write_rc(base)
      path = Pathname(send(:"#{base}_path"))
      raise "File #{path} has already exists. Abort task." if path.exist?

      File.open(path.to_s, "w") do |f|
        f.write send(:"#{base}_script")
      end
    end

    def method_missing(name, *args)
      if name.to_s =~ /^([g]?vimrc)_(script|path)$/
        rc = $1
        s = const_get("RC#{$2.upcase}")
        vimdir = is_win? ? "vimfiles" : ".vim"
        return ERB.new(s).result(binding)
      end

      super(name, *args)
    end

    def clean!(path)
      _p = path.is_a?(Pathname) ? path : Pathname(path)

      faileds = _p.children.map do |c|
        begin
          c.delete if c.file? && !CLEAN_IGNORE.include?(c.basename.to_s)
          nil
        rescue
          c.to_s
        end
      end

      unless faileds.compact.empty?
        puts "#{faileds.combact.size} files have still exists: #{failed.join(",")}"
      end
    end

    def is_win?
      RUBY_PLATFORM =~ /mswin(?!ce)|mingw|cygwin|bccwin/
    end

    def backslashize!(s)
      # change from unix type path string (using /) to win type(using \)
      s.gsub(/\//, '\\')
    end
  end

  module GCC
    class << self
      # avalable returns: "mingw32"/"mingw64"/"cygwin"
      def target
        `gcc -v 2>&1`.split("\n").map{|l| l.split(":").map(&:strip).map(&:toutf8)}.select{|f| f.first == Consts::GCC::Target}.first.last rescue ""
      end

      def compile_vimproc(target)
        puts "** Move to #{Consts::DIR::VIMPROC}"
        Dir.chdir(Consts::DIR::VIMPROC.to_s)

        make = "make -f make_#{target}.mak"
        clean = make + " clean"

        [clean, make].each do |command|
          puts "#{command} :"
          print `#{command}`
        end
      end
    end
  end
end

# -------------------------

namespace :install do
  desc "Install vundle plugin"
  task :vundle => "test:all" do
    `git clone http://github.com/gmarik/vundle.git ./bundle/vundle`
  end

  # (g)vimrc installing tasks ---
  rcs = %w[vimrc gvimrc]
  rcs_desc = lambda {|f| "Creates .#{f} which loading .vim/#{f}"}

  rcs.each do |tname|
    desc rcs_desc.call(tname)
    task tname do
      Helper.write_rc(tname)
    end
  end

  desc rcs_desc.call(rcs.join(", "))
  task :rcs => rcs
  # /(g)vimrc installing tasks ---


  desc "Install Ricty font(for ubuntu only) : TODO"
  task :Ricty do
    print <<-EOS
    Sorry!
    Installing Ricty through rake is not work correctly so far,
    please execute .scripts/install_ricty.sh on shell manually.
    (FIXME: how to communicate with shell asynchronously in rake task?)
    EOS
    #if Consts::DIR::SCRIPT.exist?
    #  sh_path = Consts::DIR::SCRIPT + Consts::RICTY_SH
    #  puts `bash #{sh_path.to_s}`
    #end
  end

  namespace :test do
    task :git do
      unless Helper.git_installed?
        puts "Please install git at first."
        exit 0
      end
    end

    task :all => %w[git]
  end
end

namespace :compile do
  desc "compiles vimproc binary (work on only linux)"
  task :vimproc do
    unless Consts::DIR::VIMPROC.exist?
      puts "Abort because vimproc repo not found at #{Consts::DIR::VIMPROC}."
      exit
    end

    if Helper.is_win?
      # compile on Windows
      Rake::Task["compile:vimproc:win"].invoke
    else
      # compile on *nix environments
      Rake::Task["compile:vimproc:unix"].invoke
    end
  end

  namespace :vimproc do
    task :unix do
      Helper::GCC.compile_vimproc("unix")
    end

    task :win do
      target = Helper::GCC.target
      if target =~ /^(mingw\d{2}|cygwin)$/
        Helper::GCC.compile_vimproc(target)
      else
        sh "make_vimproc.bat"
      end
    end
  end
end

namespace :clean do
  clean_targets = %w(backup swap)
  clean_targets.each do |tname|
    desc "Cleans files in #{tname} directory"
    task tname do
      Helper.clean! Helper.repo_root + Consts::DIR.const_get("#{tname.upcase}")
    end
  end

  desc "Cleans files in #{clean_targets.join(" and ")}"
  task :all => clean_targets
end

namespace :download do
  desc "download dll file of vimproc(for windows only). This takes arch num(default 32)"
  task :vimproc, [:arch] do |t, args|
    arch = args[:arch] || 32

    require 'tmpdir'
    tmp_fname = "vimproc"
    Dir.mktmpdir do |tmpdir|
      tmpfpath = File.join(tmpdir, tmp_fname)

      sh %(curl -L -o "#{tmpfpath}.zip" "#{Consts::URL::VIMPROC.call(arch)}")
      sh %(unzip "#{tmpfpath}.zip")

      FileUtils.mv(Dir[File.join(tmpdir, "*.dll")], File.join(Consts::DIR::VIMPROC, "autoload"), {:verbose => true})
    end
  end
end

namespace :setup do
  desc "makes configuration file for gist-vim"
  task :gist do
    $stdout.sync = true
    include Consts::PATH

    raise "#{GitHubConfig}(github config file) was not found" unless GitHubConfig.exist?
    if GistVimConfig.exist?
      print <<-EOP
#{GistVimConfig} is already exists.
Do you want to remove this?[Y/n]
      EOP

      if STDIN.gets =~ /^[n|N]/
        puts <<-EOP
Task halted.
#{GistVimConfig} is still remined.
        EOP
        exit 0
      end
    end

    github_conf = YAML.load_file(GitHubConfig)
    open(GistVimConfig, "w") do |gist_conf|
      gist_conf.puts "basic #{Helper.encode64(github_conf.map{|k,v| "#{k}:#{v}"}.join("\n"))}"
    end
    puts "#{GistVimConfig} was created."
  end
end

