# Copyright (C) 2003-2005 Kouichirou Eto, All rights reserved.

require "stringio"
$LOAD_PATH << "../../lib" unless $LOAD_PATH.include?("../../lib")
require "qwik/act-smil"

module Qwik
  class Action
    def act_media_server
      ms = MediaServer.new(@config)

      if 0 < @req.path_args.length # has target file
	filename = @req.path_args.shift
	file = filename.path

	if @req.query["delete"] == "yes"
	  output = ms.output_file(@site, file)
	  return c_nerror("already deleted: #{file.to_s}") unless output.exist?
	  output.unlink
	  return c_notice("delete content: #{file.to_s}"){}
	end

	if filename == "all"
	  each_media_entry {|f|
	    file = f.basename
	    f = @site.attach.path(file)
	    qp f, f.exist?
	    next unless f.exist?
	    ms.publish_file(@site, f)
	  }
	  return c_notice("pulish all")
	end

	f = @site.attach.path(filename)
	return c_notice("File not found.", nil, 404) unless f.exist?
	ms.publish_file(@site, f)
	return c_notice("pulish the content: #{file.to_s}")
      end

      ul = []
      each_media_entry {|f|
	file = f.basename
	ar = []
	ar << [:a, {:href=>c_relative_to_absolute(".media_server/"+file.to_s)},
	  file.to_s]
	output = ms.output_file(@site, file)
	if output.exist?
	  outbase = output.basename.to_s
	  url = "rtsp://"+@config.default_hostname+":554/"+@site.sitename+"/"+outbase
	  ar << " [" << [:a, {:href=>url}, outbase] << "] "
	  url = [:a, {:href=>c_relative_to_absolute(".media_server/"+file.to_s+"?delete=yes")}, "delete"]
	  ar << url
	end
	ul << [:li, ar]
      }

      if 0 < ul.length
	ul << [:li, [:a, {:href=>c_relative_to_absolute(".media_server/all")}, "publish all"]]
      end

      return c_notice("media server"){[:ul, ul]}
    end

    def each_media_entry
      path = @site.attach.path
      path.each_entry {|file|
	base = file.to_s
	next unless /\A(.+)\.rm\z/i =~ base
	yield(path+file)
      }
    end

    def each_movie_entry
      path = @site.attach.path
      path.each_entry {|file|
	base = file.to_s
	next unless /\A(.+)\.avi\z/i =~ base || /\A(.+)\.mp4\z/i =~ base
	yield(path+file)
      }
    end

    def act_encode
      rp = RealProducer.new(@config, @site)
      if 0 < @req.path_args.length # has target file
	filename = @req.path_args.shift

	if filename == "all"
	  t = Thread.new {
	    each_movie_entry {|f|
	      file = f.basename
	      f = @site.attach.path(file)
	      qp f, f.exist?
	      next unless f.exist?
	      output = rp.output_file(file)
	      output.dirname.check_directory
	      qp f, output, output.dirname
	      next if output.exist?
	      msg = StringIO.new
	      rp.encode_file(f, output, msg)
	      puts "done", msg.string
	    }
	  }
	  return c_notice("start encoding all")
	end

	file = filename.path
	f = @site.attach.path(filename)
	return c_nerror("File not found.", nil, 404) unless f.exist?
	output = rp.output_file(file)
	msg = StringIO.new
	t = Thread.new {
	  rp.encode_file(f, output, msg)
	}
	return c_notice("start encoding: #{file.to_s}")
      end

      ul = []
      each_movie_entry {|f|
	file = f.basename
	ar = []
	ar << [:a, {:href=>c_relative_to_absolute(".encode/"+file.to_s)},
	  file.to_s]
	output = rp.output_file(file)
	if output.exist?
	  outbase = output.basename.to_s
#	  url = "rtsp://"+@req.org_host+":554/"+@site.sitename+"/"+outbase
#	  url = "rtsp://"+@config.default_hostname+":554/qwik/"+@site.sitename+"/"+outbase
	  url = "rtsp://"+@config.default_hostname+":554/"+@site.sitename+"/"+outbase
	  ar += [" [", [:a, {:href=>url}, outbase], "]"]
	end
	ul << [:li, ar]
      }

      if 0 < ul.length
	ul << [:li, [:a, {:href=>c_relative_to_absolute(".encode/all")}, "encode all"]]
      end

      return c_notice("movie file list"){[:ul, ul]}
    end
  end

  class MediaServer
    def initialize(config)
      @config = config
    end

    def output_file(site, input)
      path = @config.real_server_content.path+site.sitename
      base = input.basename.to_s
      base = base.sub(%r!\A(.+)\.(\w+)!){|a| $1 }
      outbase = base+".rm"
      output = path+outbase
      output
    end

    def windows?
      r = RUBY_PLATFORM
      (r.index("cygwin") || r.index("mswin32") || r.index("mingw32")) != nil
    end

    def publish_file(site, input)
      output = output_file(site, input)
      output.dirname.check_directory
      if windows?
	FileUtils.cp(input, output)
      else
	FileUtils.ln(input, output)
      end
    end
  end

  class RealProducer
    def initialize(config, site)
      @config = config
      @site = site
#      @cmd = "c:/usr/RealProducer/producer.exe"
#      @cmd = "/usr/local/bin/producer"
      @cmd = @config.real_producer
      @audience = "768k"
#      @real_server_content_dir = "c:/usr/HelixServer/Content"
#      @real_server_content_dir = "/usr/local/HelixServer/Content/qwik"
#      @real_server_content_dir = "/usr/local/HelixServer/Content"
      @real_server_content_dir = @config.real_server_content
      @o = ($VERBOSE) ? $stdout : StringIO.new
    end
    attr_reader :real_server_content_dir

    def output_file(input)
      path = @real_server_content_dir.path+@site.sitename
      base = input.basename.to_s
      base = base.sub(%r!\A(.+)\.(\w+)!){|a| $1 }
      outbase = base+".rm"
      output = path+outbase
      output
    end

    def encode_all
      path = @site.attach.path
      path.each_entry {|file|
	base = file.basename.to_s
	next unless /\A(.+)\.avi\z/i =~ base || /\A(.+)\.mp4\z/i =~ base
	output_base = $1+".rm"
	output = path+output_base
	if output.exist?
	  puts "already exist: #{output.to_s}"
	  next
	end
	encode_file(path+file)
      }
    end

    def encode_file(input, output, msg=nil)
      m = msg ? msg : @o
      inf  =  input.to_win_dir
      outf = output.to_win_dir
      m.puts "start encode #{inf}"
#      qp inf, outf
      open("|#{@cmd} -i #{inf} -o #{outf} -ad #{@audience}"){|f|
	while line = f.gets
	  m.print line.normalize_eol
	end
      }
      m.puts
    end

    def show_version
      @o.puts(open("|#{@cmd} -pa"){|f| f.read })
    end

    def show_help
      @o.puts(open("|#{@cmd} -h"){|f| f.read })
    end

    def show_more_help
      @o.puts(open("|#{@cmd} -m"){|f| f.read })
    end

    def show_audience_list
      @o.puts(open("|#{@cmd} -pa"){|f| f.read })
    end
  end
end

if $0 == __FILE__
  require "t/test"
  $debug = true
end

if $debug
  class TC_ActMedia < Test::Unit::TestCase
    include TestSession

    def test_act_media_server
      t_add_user
      session("/test/.media_server")
      assert_text("media server", "title")
    end

    def copy_sample_file
      path = @org_data_dir.path+"eto/.attach"
      f = path+"sample.avi"
      FileUtils.cp(f.to_s, @site.attach.path)
    end

    def nutest_act_encode
      copy_sample_file

      t_add_user
      session("/test/.encode")
      assert_text("movie file list", "title")

      session("/test/.encode/nosuchfile.avi")
      assert_text("File not found.", "title")

      session("/test/.encode/sample.avi")
      #    px
      #    px("//div[@class='msg']", 0)
      #    assert_text("encode file: sample.avi", "title")
      assert_text("start encoding: sample.avi", "title")
    end

    def nutest_encode
      copy_sample_file
      rp = Qwik::RealProducer.new(@site)
      rp.encode_all
    end
  end
end
