# encoding: utf-8
require 'fileutils'

module Shelr
  class Recorder

    attr_accessor :meta, :user_rows, :user_columns

    def self.record!(options = {})
      new.record!(options)
    end

    def initialize
      @meta = {}
    end

    def record!(options = {})
      ensure_terminal_has_good_size
      check_record_dir
      with_lock_file do
        init_terminal
        request_metadata
        Shelr.terminal.puts_line
        STDOUT.puts "=> Your session started"
        STDOUT.puts "=> Please, do not resize your terminal while recording"
        STDOUT.puts "=> Press Ctrl+D or 'exit' to finish recording"
        Shelr.terminal.puts_line
        start_sound_recording if options[:sound]
        system(recorder_cmd)
        stop_sound_recording if options[:sound]
        save_as_typescript if Shelr.backend == 'ttyrec'
        Shelr.terminal.puts_line
        STDOUT.puts "=> Session finished"
        STDOUT.puts
        STDOUT.puts "Replay  : #{Shelr::APP_NAME} play last"
        STDOUT.puts "Publish : #{Shelr::APP_NAME} push last"
      end
    end

    def request_metadata
      STDOUT.print "Provide some title for your record: "
      @meta["title"] = STDIN.gets.strip
      @meta["recorded_at"] = record_id
      @meta["columns"] = @user_columns
      @meta["rows"] = @user_rows
      @meta["uname"] = `uname -a`
      @meta["shell"] = ENV['SHELL']
      @meta["term"] = ENV['TERM']
      @meta["xdg_current_desktop"] = ENV['XDG_CURRENT_DESKTOP']
      STDOUT.puts record_file('meta')
      File.open(record_file('meta'), 'w+') do |meta|
        meta.puts @meta.to_json
      end
    end

    private

    def ensure_terminal_has_good_size
      if (Shelr.terminal.size[:height] > 43) or (Shelr.terminal.size[:width] > 132)
        Shelr.terminal.puts_line
        puts "=> Please, resize your terminal!"
        puts "=> Sizes bigger than 132x43 are slow and will not be available to all users."
        puts "=> We care about this."
        puts "=> Also, do not resize your terminal while recording. It will break the record."
        Shelr.terminal.puts_line
        exit(0)
      end
    end

    def with_lock_file
      lock_path = record_file('lock')
      File.open(lock_path, 'w') do |f|
        f.puts Time.now.to_s
      end
      yield
      FileUtils.rm(lock_path)
    end

    def save_as_typescript
      puts '=> Converting ttyrec -> typescript'

      ttyrecord  = File.open(record_file('ttyrecord'), 'r')
      converter  = Shelr::TTYRec.new(ttyrecord)
      typescript = converter.parse.to_typescript

      [:typescript, :timing].each do |part|
        File.open(record_file(part.to_s), 'w') do |f|
          f.write(typescript[part])
        end
      end
    end

    def check_record_dir
      FileUtils.mkdir_p(record_dir) unless File.exists?(record_dir)
    end

    def init_terminal
      @user_rows, @user_columns =
        Shelr.terminal.size[:height], Shelr.terminal.size[:width]
    end

    def record_dir
      @record_dir ||= Shelr.data_dir(record_id)
    end

    def record_id
      @record_id ||= Time.now.to_i.to_s
    end

    def record_file(name)
      File.join(Shelr.data_dir(record_id), name)
    end

    def start_sound_recording
      STDOUT.puts "Sound file stored in #{record_file('sound.ogg')}"
      @sox_pid = fork do
        Signal.trap("INT") { puts "=> Sound recording finished!"; exit }
        `rec -C 1 --channels 1 --rate 16k --comment 'Recorded for http://shelr.tv/' #{record_file('sound.ogg')} 2>&1`
      end
    end

    def stop_sound_recording
      STDOUT.puts "=> Stopping sound recorder"
      sleep 2 # otherwise record will be cropped for some reason
      Process.kill("INT", @sox_pid)
      Process.waitpid(@sox_pid)
    end

    def recorder_cmd
      case Shelr.backend
      when 'script'
        "script #{record_file('typescript')} -t 2> #{record_file('timing')}"
      when 'ttyrec'
        "ttyrec #{record_file('ttyrecord')}"
      end
    end
  end
end
