require 'wx'
require 'wxconstructor'

require 'gettext'
require 'net/http'
require 'msgpack'
require 'yaml'
require 'ini'
require 'rubyplus'

module DarkHall
	module ErrorReport
		def self.call
			begin
				SE.sonar
			rescue
			end
			
			File.write('darkhall_error.log', dump)
			
			sleep(0.2)
			App.new.main_loop
		end
		
		def self.dump(comment = nil, mail_address = nil)
			data = {}
			data['version'] = DarkHall::VERSION
			data['time'] = Time.now.to_i
			data['exception_class'] = $!.class.to_s
			data['exception_message'] = $!.message
			data['backtrace'] = $!.backtrace
			data['comment'] = comment
			data['mail_address'] = mail_address
			data['phase_class'] = $phase.class.to_s
			data['window_classes'] = $windows.map{|x| x.class.to_s} if $windows
			
			if $section == Section::BATTLE then
				data['last_round_reserved_actions'] = []
				if $battle then
					$battle.last_round_reserved_actions.each do |action|
						data['last_round_reserved_actions'] << action.to_error_report_model
					end
				end
				data['last_action'] = $battle.last_action.to_error_report_model
			end
			
			#data['game_state'] = GS.to_hash
			
			
			
			return data.to_yaml
		end

		class App < Wx::App
			include GetText
			def on_init
				@frame = MainFrame.new(nil, :title => _('DarkHall Error'))
				@frame.show
			end
			
			def on_run
				begin
					super
				rescue StandardError, ScriptError, NoMemoryError
					open('error.log', 'w'){|f|
						f.puts $!.class.to_s
						f.puts $!.to_s
						f.puts $!.backtrace
						f.puts "(from #{caller[0]})"
					}
					Kernel.raise $!
				end
			end
		end
		
		class DetailDialog < Wx::Dialog
			def initialize(parent, comment = nil, mail_address = nil)
				super(parent)
				self.window_style ^= Wx::RESIZE_BORDER
				self.window_style ^= Wx::MAXIMIZE_BOX
				
				@comment = comment
				@mail_address = mail_address
				
				dialog = self
				topsz = nil
				construct_children do
					widget Wx::Panel do
						topsz = vbox_sizer do
							expand
							border 8
							
							widget Wx::StaticText, :label => _("DarkHallのバージョン情報やエラー情報などを送信します。\nゲーム内で入力した名前や、プライバシーにかかわる情報は送信されません。")
							
							widget Wx::TextCtrl, :name => 'display', :style => Wx::TE_MULTILINE | Wx::TE_READONLY, :value => _('Dumping...'), :size => [420, 360]
							button = widget Wx::Button, :label => _('確認')
							button.set_default
							dialog.evt_button(button){ dialog.end_modal(0) }
						end
					end
				end
				
				evt_show(self, :on_show)
				
				topsz.fit(self)
			end
			
			def on_show
				timer = Wx::Timer.every(1) do
					Thread.pass
				end
				
				t = Thread.new{
					yaml = ErrorReport.dump(@comment, @mail_address)
					find_window_by_name('display').value = yaml
				
					timer.stop
				}
				t.abort_on_exception = true
				
			end
		end

		
		class SendingDialog < Wx::Dialog
			def initialize(parent, comment = nil, mail_address = nil)
				super(parent)
				self.window_style ^= Wx::RESIZE_BORDER
				self.window_style ^= Wx::MAXIMIZE_BOX
				
				@comment = comment
				@mail_address = mail_address
				
				dialog = self
				topsz = nil
				construct_children do
					widget Wx::Panel do
						topsz = vbox_sizer do
							expand
							border 16
							
							widget Wx::StaticText, :name => 'status', :label => _("エラーレポートを送信中です...")
							button = widget Wx::Button, :label => _('キャンセル')
							dialog.evt_button(button, :on_cancel)
						end
					end
					
	
				end
				
				topsz.fit(self)
				
				evt_show self, :on_start
			end
			
			def on_cancel
				end_modal(1)
			end
			
			def on_start
				t = Thread.new{
					begin
						Net::HTTP.version_1_2
						Net::HTTP.start('wiz.morphball.net'){|http|
						  res = http.post('/darkhall/error_report.cgi', ErrorReport.dump(@comment, @mail_address))
						}
						end_modal(0)
					rescue Exception
						find_window_by_name('status').label = _("送信に失敗しました。")
					end
				}
				t.abort_on_exception = true
				
				Wx::Timer.every(1) do
					Thread.pass
				end
				
			end
		end
		
		class MainFrame < Wx::Frame
			include GetText
			def initialize(*args)
				super
				self.window_style ^= Wx::RESIZE_BORDER
				self.window_style ^= Wx::MAXIMIZE_BOX
				#self.window_style |= Wx::STAY_ON_TOP
	
				topsz = nil
				frame = self
				construct_children do
					widget Wx::Panel do
						topsz = vbox_sizer do
							expand
							border 8
							
							vbox_sizer do
								border 8
								
								widget Wx::StaticText, :label => _("DarkHall のプログラム実行中にエラーが発生しました。\nご迷惑をおかけして申し訳ありません。")
							
								widget Wx::StaticText, :label => _("よろしければ、エラー原因の迅速な修正のために\nTeam D.H. までエラーレポートをお送りください。")
								
							end
							
							static_vbox_sizer(_('オプション（省略可）')) do
								expand
								border 4
								
								widget Wx::StaticText, :label => _('エラーの発生した状況について教えてください。')
								widget Wx::TextCtrl, :name => 'comment', :style => Wx::TE_MULTILINE, :size => Wx::Size.new(300, 60)
	
								
								hbox_sizer do
									proportion 1
									widget Wx::StaticText, :label => _('メールアドレス:')
									proportion 3
									widget Wx::TextCtrl, :name => 'mail_address', :value => SETTING.error_report_mail_address || ''
								end
							end
							
							hbox_sizer do
								border 8
								stretch_spacer 1
								checkbox = widget Wx::CheckBox, :name => 'reboot_check', :label => _("DarkHall をすぐに再起動する")
								checkbox.value = SETTING.error_report_reboot?
								stretch_spacer 1
							end
							
							widget Wx::StaticLine
	
							
	
							hbox_sizer do
								link = widget Wx::HyperlinkCtrl, :label => _('送信されるデータの詳細'), :style => Wx::NO_BORDER | Wx::HL_CONTEXTMENU | Wx::HL_ALIGN_CENTRE
								frame.evt_hyperlink(link, :on_detail)
	
								stretch_spacer 3
								
								button = widget Wx::Button, :label => _('送信する')
								button.set_default
								frame.evt_button(button, :on_send)
								
								stretch_spacer 1
								
								button = widget Wx::Button, :label => _('送信しない')
								frame.evt_button(button, :on_not_send)
							end
						end
					end
				end
				
				topsz.fit(self)
			end
			
			def on_send
				#Net::HTTP.version_1_2
				#Net::HTTP.start('wiz.morphball.net') {|http|
				#  res = http.post('/darkhall/new/error_report_test.cgi', RUBY_VERSION.to_s)
				#}
				store_setting
				
				ret = SendingDialog.new(self, find_window_by_name('comment').value, find_window_by_name('mail_address').value).show_modal
				if ret == 0 then
					call_reboot_sequence
					exit
				end
			end
			
			def on_not_send
				store_setting
				call_reboot_sequence
				exit
			end
			
			def on_detail
				DetailDialog.new(self, find_window_by_name('comment').value, find_window_by_name('mail_address').value).show_modal
			end
			
			def on_font_select
				dialog = Wx::FontDialog.new
				ret = dialog.show_modal
				@font_text.value = dialog.font_data.chosen_font.face_name
				
			end
			
			def call_reboot_sequence
				checkbox = find_window_by_name('reboot_check')
				if checkbox.checked? then
					Util.reboot_game
				end
			end
			
			def store_setting
				if File.exist?('setting.ini') then
					ini = Ini.parse_file('setting.ini')
				else
					ini = {}
				end
				
				ini['ErrorReport'] ||= {}
				ini['ErrorReport']['MailAddress'] = find_window_by_name('mail_address').value
				ini['ErrorReport']['Reboot'] = find_window_by_name('reboot_check').value.to_s
				
				open('setting.ini', 'w'){|f|
					f.write Ini.dump(ini)
				}

			end
		end
		
	end
end