#! /usr/bin/ruby
# -*- mode:Ruby; tab-width:4; coding:UTF-8; -*-
# vi:set ft=ruby ts=4 fenc=UTF-8 :
#----------------------------------------------------------------
# ショートカットを作成する
#
# 2009/06/17 opa
#----------------------------------------------------------------

require 'optparse'
require 'win32ole'

ProgName = 'MakeShortcut'
Version = '1.02'

class String
	def enc()
		encode('UTF-8').force_encoding('ASCII-8BIT')
	end

	def dec()
		force_encoding('UTF-8').encode('locale')
	end

	def expand_path()
		File.expand_path(self).force_encoding('locale').gsub(File::SEPARATOR, File::ALT_SEPARATOR)
	end
end

def File.delete_if_exist(filename)
	begin
		File.delete(filename)
	rescue Errno::ENOENT
		# NOP(ignore)
	end
end

def var_init()
	$shell = WIN32OLE.new('WScript.Shell')
	$stdin.set_encoding('locale:UTF-8') # EXT:INT
	$stdout.set_encoding('locale:UTF-8')
	$stderr.set_encoding('locale:UTF-8')

	$Arguments = nil
	$Description = nil
	$HotKey = nil
	$IconLocation = nil
	$TargetPath = nil
	$Update = false
	$WindowStyle = nil
	$WorkingDirectory = nil
	$Type = nil
end

def make_shortcut(filename)
	if $TargetPath == nil
		printf($stderr, "%s: error: TargetPath not presented\n", ProgName)
		return
	end

	case $Type
	  when nil
		if !(File.extname(filename) == '.lnk' || File.extname(filename) == '.url')
			printf($stderr, "%s: error: filename must be .lnk or .url: %s\n", ProgName, filename)
			return
		end
	  else
		if File.extname(filename) != $Type
			filename += $Type
		end
	end

	if !$Update
		File.delete_if_exist(filename)
	end

	shortcut = $shell.CreateShortcut(filename)
	modified = false
	error = false

	if $Arguments != nil
		if shortcut.Arguments != $Arguments
			begin
				shortcut.Arguments = $Arguments
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: Argument=%s\n", ProgName, $Arguments)
				error = true
			end
		end
	end

	if $Description != nil
		if shortcut.Description != $Description
			begin
				shortcut.Description = $Description
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: Description=%s\n", ProgName, $Description)
				error = true
			end
		end
	end

	if $HotKey != nil
		if $HotKey.casecmp(shortcut.HotKey) != 0
			begin
				shortcut.HotKey = $HotKey
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: HotKey=%s\n", ProgName, $HotKey)
				error = true
			end
		end
	end

	if $IconLocation != nil
		iconLocation = $IconLocation.expand_path()

		if !File.exist?(iconLocation.gsub(/,\d+$/,''))
			printf($stderr, "%s: warning: IconLocation not exist: %s\n", ProgName, iconLocation)
		end

		if iconLocation.casecmp(shortcut.IconLocation) != 0
			begin
				shortcut.IconLocation = iconLocation
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: IconLocation=%s\n", ProgName, iconLocation)
				error = true
			end
		end
	end

	if $TargetPath != nil
		targetPath = $TargetPath.expand_path()

		if !File.exist?(targetPath) && !File.exist?(targetPath + '.exe')
			printf($stderr, "%s: warning: TargetPath not exist: %s\n", ProgName, targetPath)
		end

		if targetPath.casecmp(shortcut.TargetPath) != 0
			begin
				shortcut.TargetPath = targetPath
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: TargetPath=%s\n", ProgName, targetPath)
				error = true
			end
		end
	end

	if $WindowStyle != nil
		if shortcut.WindowStyle != $WindowStyle
			begin
				shortcut.WindowStyle = $WindowStyle
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: WindowStyle=%s\n", ProgName, $WindowStyle)
				error = true
			end
		end
	end

	if $WorkingDirectory != nil
		if $WorkingDirectory == '@'
			if File.directory?($TargetPath)
				workingDirectory = ""
			else
				workingDirectory = File.dirname($TargetPath.expand_path())
			end
		else
			workingDirectory = $WorkingDirectory
		end

		if workingDirectory.length > 0 && !File.exist?(workingDirectory)
			printf($stderr, "%s: warning: WorkingDirectory not exist: %s\n", ProgName, workingDirectory)
		end

		if workingDirectory.casecmp(shortcut.WorkingDirectory) != 0
			begin
				shortcut.WorkingDirectory = workingDirectory
				modified = true
			rescue
				printf($stderr, "%s: error: cannot set property: WorkingDirectory=%s\n", ProgName, workingDirectory)
				error = true
			end
		end
	end

	if error
		File.delete_if_exist(filename)
	elsif modified
		shortcut.save
	end
end

def main()
	var_init()

	ARGV.size.times { |i|
		ARGV[i] = ARGV[i].enc()
	}

	ARGV.options { |opt|
		opt.banner = "Usage: #{ProgName} [options] file..."

		opt.on('-a', '--Arguments=arg', String,
			'パラメータ') { |v|
			$Arguments = v.dec()
		}
		opt.on('-d', '--Description=text', String,
			'コメント') { |v|
			$Description = v.dec()
		}
		opt.on('-h', '--HotKey=key', String, /(\w|\+)+/,
			'ショートカットキー') { |v|
			$HotKey = v[0].dec()
		}
		opt.on('-i', '--IconLocation=filename', String,
			'アイコン') { |v|
			$IconLocation = v.dec()
		}
		opt.on('-t', '--TargetPath=filename', String,
			'リンク先') { |v|
			$TargetPath = v.dec()
		}
		opt.on('-u', '--Update', TrueClass,
			'新規作成ではなく更新を行う') { |v|
			$Update = v
		}
		opt.on('-s', '--WindowStyle=style', String, /Normal|Maximize|Minimize/i,
			'実行時の大きさ(Normal|Maximize|Minimize)') { |v|
			case v
			  when /Normal/i
				$WindowStyle = 1
			  when /Maximize/i
				$WindowStyle = 3
			  when /Minimize/i
				$WindowStyle = 7
			end
		}
		opt.on('-w', '--WorkingDirectory=dir', String,
			'作業フォルダ') { |v|
			$WorkingDirectory = v.dec()
		}
		opt.on('-y', '--Type=type', String, /\.?(lnk|url)/i,
			'ショートカットの種類(.lnk|.url)') { |v|
			case v[0]
			  when /\.?lnk/i
				$Type = '.lnk'
			  when /\.?url/i
				$Type = '.url'
			end
		}

		opt.parse!
		opt.parse('--help') if ARGV.size == 0
	}

	ARGV.each { |a| make_shortcut(a.dec()) }

	return 0
end

exit main()
