#!/usr/bin/ruby
#
# Copyright (c) 2010-2014 Minero Aoki, Kenshi Muto
#               1999-2007 Minero Aoki
#
# This program is free software.
# You can distribute or modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.1.
# For details of the GNU LGPL, see the file "COPYING".
#

require 'pathname'

bindir = Pathname.new(__FILE__).realpath.dirname
$LOAD_PATH.unshift((bindir + '../lib').realpath)

require 'review/preprocessor'
require 'review/unfold'
require 'review/version'
require 'review/extentions'
require 'review/logger'
require 'lineinput'
require 'stringio'
require 'fileutils'
require 'optparse'

def sigmain
  Signal.trap(:INT) { exit 1 }
  if RUBY_PLATFORM !~ /mswin(?!ce)|mingw|cygwin|bccwin/
    Signal.trap(:PIPE, 'IGNORE')
  end
  main
rescue Errno::EPIPE
  exit 0
end

def main
  @logger = ReVIEW.logger
  if File.file?('review-preproc-ext.rb')
    if ENV['REVIEW_SAFE_MODE'].to_i & 2 > 0
      @logger.warn 'review-preproc-ext.rb is prohibited in safe mode. ignored.'
    else
      Kernel.load File.expand_path('review-preproc-ext.rb')
    end
  end

  param = {}

  mode = :output
  opts = OptionParser.new
  opts.version = ReVIEW::VERSION
  opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [-c|-d|-s|--replace] [<file>...]"
  opts.on('-c', '--check', 'Check if preprocess is needed.') { mode = :check }
  opts.on('-d', '--diff', 'Show diff from current file.') { mode = :diff }
  opts.on('--replace', 'Replace file by preprocessed one.') { mode = :replace }
  opts.on('-s', '--strip', 'Strip preprocessor tags.') { mode = :strip }
  opts.on('--final', 'Unfold text and strip preprocessor tags. (deprecated)') { mode = :final }
  opts.on('--tabwidth=WIDTH', "Replace tabs with space characters. (0: don't replace)") { |width| param['tabwidth'] = width.to_i }
  opts.on('--help', 'Print this message and quit.') do
    puts opts.help
    exit 0
  end
  begin
    opts.parse!
  rescue OptionParser::ParseError => err
    @logger.error err.message
    $stderr.puts opts.help
    exit 1
  end

  pp = ReVIEW::Preprocessor.new(ReVIEW::Repository.new(param), param)
  current_file = nil
  ARGV.each do |path|
    current_file = path
    case mode
    when :output
      File.open(path) { |f| pp.process f, $stdout }
    when :replace
      File.write "#{path}.pptmp", preproc(pp, path)
      File.rename "#{path}.pptmp", path
    when :diff, :check
      tmp = '/tmp/review.pptmp'
      begin
        File.write tmp, preproc(pp, path)
        if mode == :check
          system "diff -qu #{path} #{tmp} >/dev/null || echo #{path}"
        else
          system "diff -u #{path} #{tmp}"
        end
      ensure
        FileUtils.rm_f tmp
      end
    when :strip
      File.open(path) do |f|
        ReVIEW::Preprocessor::Strip.new(f).each { |line| puts line }
      end
    when :final
      u = ReVIEW::Unfold.new
      File.open(path) { |f| u.unfold ReVIEW::Preprocessor::Strip.new(f), $stdout }
    else
      raise "must not happen: #{mode}"
    end
  end
rescue ReVIEW::Error => err
  raise if $DEBUG
  @logger.error err.message
  exit 1
end

def preproc(pp, path)
  buf = StringIO.new
  File.open(path) { |f| pp.process f, buf }
  buf.string
end

def File.write(path, str)
  File.open(path, 'w') { |f| f.write str }
end

sigmain
