# Copyright 2014 Google Inc. All rights reserved.
#
# Use of this source code is governed by The MIT License.
# See the LICENSE file for details.

require "autoprefixer-rails"
require "fileutils"
require "find"
require "json"
require "pathname"
require "sass"
require "tmpdir"
require "yaml"


# Define paths here relative to this Rakefile.
BASE = "."
DOC = "../doc"
STAGING = "../../spfjs-gh-pages"
BOWER_COMPONENTS = "../bower_components"
NODE_MODULES = "../node_modules"

# Derived paths.
SITE = "#{BASE}/_site"
SOURCE = "#{BASE}/_source"
ASSETS = "#{SOURCE}/assets"
VENDOR = "#{BOWER_COMPONENTS}"
BUILD_DEST = Pathname(SITE).relative_path_from(Pathname(SOURCE))
STAGE_DEST = Pathname(STAGING).relative_path_from(Pathname(SOURCE))

JEKYLL = "bundle exec jekyll"
begin
  BOWER = Pathname("#{NODE_MODULES}/bower/bin/bower").realpath
  JSDOX = Pathname("#{NODE_MODULES}/jsdox/bin/jsdox").realpath
rescue
  msg = "Required tools not found; please run the following:\n"
  msg += "    cd .. && npm install"
  raise msg
end

BOWER_INFO = JSON.parse(`cd .. && #{BOWER} --offline list --json`)

# Use an official SPF release instead of building from source.
SPF = "#{VENDOR}/spf"
SPF_INFO = BOWER_INFO["dependencies"]["spf"]["pkgMeta"]
SPF_VERSION = SPF_INFO["version"]
LOCAL_SPF = "#{ASSETS}/vendor/spf/#{SPF_VERSION}"

WSK = "#{VENDOR}/web-starter-kit/app"
WSK_INFO = BOWER_INFO["dependencies"]["web-starter-kit"]["pkgMeta"]
WSK_VERSION = WSK_INFO["version"]
LOCAL_WSK = "#{ASSETS}/vendor/wsk/#{WSK_VERSION}"

OCTICONS = "#{VENDOR}/octicons/octicons"
OCTICONS_INFO = BOWER_INFO["dependencies"]["octicons"]["pkgMeta"]
OCTICONS_VERSION = OCTICONS_INFO["version"]
LOCAL_OCTICONS = "#{ASSETS}/vendor/octicons/#{OCTICONS_VERSION}"

AUTOPREFIXER_BROWSERS = [
  "ie >= 10",
  "ie_mob >= 10",
  "ff >= 30",
  "chrome >= 34",
  "safari >= 7",
  "opera >= 23",
  "ios >= 7",
  "android >= 4.4",
  "bb >= 10",
]


jek_to_symlink = {
  "#{SOURCE}/_config.yml" => "#{BASE}/config.yml",
  "#{SOURCE}/_layouts" => "#{BASE}/layouts",
  "#{SOURCE}/_includes" => "#{BASE}/includes",
  "#{SOURCE}/_data" => "#{BASE}/data",
  "#{SOURCE}/_plugins" => "#{BASE}/plugins",
}

doc_to_symlink = {}
Find.find(DOC) do |src|
  unless File.directory?(src)
    dst = src.sub(DOC, SOURCE)
    doc_to_symlink[dst] = src
  end
end

css_to_symlink = {
  "#{LOCAL_OCTICONS}/octicons.css" => "#{OCTICONS}/octicons.css",
}
Find.find("#{BASE}/assets/styles") do |src|
  unless File.directory?(src)
    dst = src.sub("#{BASE}/assets", ASSETS)
    css_to_symlink[dst] = src
  end
end
css_to_build = {
  "#{LOCAL_WSK}/styles/wsk.css" => [
      "#{WSK}/styles/h5bp.css",
      "#{WSK}/styles/components/components.css",
      "#{WSK}/styles/main.css",
    ]
}
# Note: WSK font files are not used and instead fonts are linked directly from
# Google Fonts, but they may be installed locally during development if desired.

img_to_symlink = {
  "#{LOCAL_WSK}/images/icons/icons-hinted.ttf" => "#{WSK}/images/icons/icons-hinted.ttf",
  "#{LOCAL_WSK}/images/icons/icons.eot" => "#{WSK}/images/icons/icons.eot",
  "#{LOCAL_WSK}/images/icons/icons.svg" => "#{WSK}/images/icons/icons.svg",
  "#{LOCAL_WSK}/images/icons/icons.ttf" => "#{WSK}/images/icons/icons.ttf",
  "#{LOCAL_WSK}/images/icons/icons.woff" => "#{WSK}/images/icons/icons.woff",
  "#{LOCAL_WSK}/images/icons/icons.woff2" => "#{WSK}/images/icons/icons.woff2",
  "#{LOCAL_OCTICONS}/octicons.eot" => "#{OCTICONS}/octicons.eot",
  "#{LOCAL_OCTICONS}/octicons.svg" => "#{OCTICONS}/octicons.svg",
  "#{LOCAL_OCTICONS}/octicons.ttf" => "#{OCTICONS}/octicons.ttf",
  "#{LOCAL_OCTICONS}/octicons.woff" => "#{OCTICONS}/octicons.woff",
}
Find.find("#{BASE}/assets/images") do |src|
  unless File.directory?(src)
    dst = src.sub("#{BASE}/assets", ASSETS)
    img_to_symlink[dst] = src
  end
end

js_to_symlink = {
  "#{LOCAL_SPF}/spf.js" => "#{SPF}/dist/spf.js",
}
Find.find("#{BASE}/assets/scripts") do |src|
  unless File.directory?(src)
    dst = src.sub("#{BASE}/assets", ASSETS)
    js_to_symlink[dst] = src
  end
end


all_to_symlink = {}.merge(jek_to_symlink)
                   .merge(doc_to_symlink)
                   .merge(css_to_symlink)
                   .merge(img_to_symlink)
                   .merge(js_to_symlink)
jek_files = jek_to_symlink.keys
doc_files = doc_to_symlink.keys
css_files = css_to_symlink.merge(css_to_build).keys
img_files = img_to_symlink.keys
js_files = js_to_symlink.keys


all_to_symlink.each do |dst, src|
  file dst => src do
    dstdir = File.dirname(dst)
    FileUtils.mkdir_p(dstdir) unless File.directory?(dstdir)
    sym = Pathname(src).relative_path_from(Pathname(dstdir)).to_s
    puts("sym #{dst} -> #{sym}") if verbose == true
    FileUtils.ln_s(sym, dst)
  end
end

css_to_build.each do |dst, srcs|
  file dst => srcs do
    css = ""
    # Concatenate WSK files.
    srcs.each do |src|
      css += File.read(src)
    end
    # Fix WSK paths.
    css = css.gsub('url("../../images', 'url("../images')
    # Prefix rules.
    prefixed = AutoprefixerRails.process(css, browsers: AUTOPREFIXER_BROWSERS)
    # Compress.
    sass_engine = Sass::Engine.new(prefixed.css, {
      :style => :compressed,
      :cache => false,
      :syntax => :scss,
    })
    compressed = sass_engine.render
    # Output.
    dstdir = File.dirname(dst)
    FileUtils.mkdir_p(dstdir) unless File.directory?(dstdir)
    puts("scss #{srcs} > #{dst}") if verbose == true
    File.write(dst, compressed)
  end
end


# Tasks.
task :jek => jek_files
task :doc => doc_files
task :css => css_files
task :img => img_files
task :js => js_files
task :source => [:jek, :doc, :css, :img, :js]

JEKYLL_BUILD = "cd #{SOURCE} && #{JEKYLL} build --trace"
JEKYLL_SERVE = "cd #{SOURCE} && #{JEKYLL} serve --trace --watch"

task :build => [:source] do
  cmd = "#{JEKYLL_BUILD} --destination #{BUILD_DEST}"
  puts(cmd) if verbose == true
  system(cmd)
end


task :serve => [:source] do
  cmd = "#{JEKYLL_SERVE} --destination #{BUILD_DEST}"
  puts(cmd) if verbose == true
  system(cmd)
end


task :stage => [:clean, :source] do
  cmd = "#{JEKYLL_BUILD} --destination #{STAGE_DEST}"
  puts(cmd) if verbose == true
  system(cmd)
end


task :clean do
  clean_paths = [SITE, SOURCE]
  puts("rm #{clean_paths}") if verbose == true
  FileUtils.rm_rf(clean_paths)
end


task :default => [:build]
