#!/usr/bin/env ruby

require 'ciphr'
require 'readline'
require 'slop'

Slop.parse do
  banner "Usage: #{File.basename $0} [options] [spec]"
  on :h, :help
  on :v, :verbose
  on :n, :'no-newline'
  on :r, :'repl'
  on :N, :'newline'
  on :x, :'xargs-mode'
  on :'0', :null

  run do |opts, args|
    Ciphr::FunctionRegistry.global.setup
    if opts[:help] || args.size == 0 && opts.to_hash.reject{|k,v| v.nil?}.size == 0
        puts opts
        if opts[:verbose]
            puts "Available Functions: aliases ([args])"
            Ciphr::FunctionRegistry.global.functions.flat_map{|c,vs| vs.map{|v| [c,v] }}.each{|a|
                c,v = a
                puts "  #{v[0].map{|v|v.to_s}.join(", ")} (#{c.params.map{|p| p.to_s}.join(", ")})"
            }
        end
    elsif opts[:repl] # REPL mode
      begin
        while input = Readline.readline("ciphr> ", true)
	  input = input && input.strip
	  if input && !input.empty?
            break if input == "exit"
            parsed = Ciphr::Parser.new.parse(input)
            transformed = Ciphr::Transformer.new($stdin).apply(parsed)
            while (chunk = transformed.read(256)) && ! $stdout.closed?
                $stdout.print(chunk)
            end
	    puts
	  end
        end
      rescue Errno::EPIPE, Interrupt
      end
      puts
    else
      newline = opts[:newline] || opts[:'xargs-mode'] || STDOUT.tty? && ! opts[:'no-newline']
      spec = args.join(" ")
      begin
        parsed = Ciphr::Parser.new.parse(spec)
        if opts[:'xargs-mode']
          delim = opts['null'] ? "\x00" : "\n"
          $stdin.each_line(delim) do |line|
            io = StringIO.new(line.tr(delim,''))
	    io.bindmode
            transformed = Ciphr::Transformer.new(io).apply(parsed)
            $stdout.print transformed.read
            puts if newline
          end
        else 
          transformed = Ciphr::Transformer.new($stdin).apply(parsed)
          while (chunk = transformed.read(256)) && ! $stdout.closed?
            begin
              $stdout.print(chunk)
            rescue Errno::EPIPE 
              break
            end
          end
          puts if newline 
        end
      rescue Parslet::ParseFailed => e
        $stderr.puts e.cause
        $stderr.puts spec
        $stderr.puts " " * (e.cause.pos) + "^"
      rescue Ciphr::FunctionRegistry::InvalidFunctionError => e
        $stderr.puts "invalid function '#{e.name}'"
      end
    end
  end
end




