summaryrefslogtreecommitdiff
path: root/app/models/tournament.rb
blob: 854b8c98213618dd0dc6794f35e9c91e95d4df27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
class Tournament < ActiveRecord::Base
	belongs_to :game

	has_many :tournament_stages
	# Don't validate presence of stages; sadly, it seems to break things
	#validates_presence_of :tournament_stages
	alias_attribute :stages, :tournament_stages

	has_many :brackets

	has_many :tournament_settings

	has_and_belongs_to_many :players, class_name: "User", association_foreign_key: "player_id", join_table: "players_tournaments"

	has_and_belongs_to_many :hosts,   class_name: "User", association_foreign_key: "host_id",   join_table: "hosts_tournaments"
	validates_presence_of :hosts

	validates_presence_of :game

	before_save { self.status ||= 0 }

	validates(:name,
		presence: true,
		length: {minimum: 5},
		uniqueness: {case_sensitive: true})

	validates(:min_players_per_team,
		presence: true,
		numericality: {
			only_integer: true,
			less_than_or_equal_to: :max_players_per_team,
		})
	validates(:max_players_per_team,
		presence: true,
		numericality: {
			only_integer: true,
			greater_than_or_equal_to: :min_players_per_team,
		})

	validates(:min_teams_per_match,
		presence: true,
		numericality: {
			only_integer: true,
			less_than_or_equal_to: :max_teams_per_match,
		})
	validates(:max_teams_per_match,
		presence: true,
		numericality: {
			only_integer: true,
			greater_than_or_equal_to: :min_teams_per_match,
		})

	validate :validate_scoring_method
	def validate_scoring_method
		(not self.scoring_method.try(:empty?)) and (scoring_methods.include? scoring_method)
	end

	def owned_by?(user)
		self.hosts.include?(user)
	end

	# Settings #################################################################

	def settings
		@settings ||= Settings.new(self)
	end

	def settings=(setting)
		setting.each do |key, value|
			value = false if value == "0"
			settings[key] = value
		end
	end

	class Settings
		def initialize(tournament)
			@tournament = tournament
		end

		def [](setting_name)
			tournament_setting = @tournament.tournament_settings.find{|s|s.name==setting_name}
			if tournament_setting.nil?
				return nil
			else
				return tournament_setting.value
			end
		end

		def []=(setting_name, val)
			tournament_setting = @tournament.tournament_settings.find{|s|s.name==setting_name}
			if tournament_setting.nil?
				game_setting = @tournament.game.settings.find_by_name(setting_name)
				@tournament.tournament_settings.build(name: setting_name, value: val,
					vartype:       game_setting.vartype,
					type_opt:      game_setting.type_opt,
					description:   game_setting.description,
					display_order: game_setting.display_order)
			else
				tournament_setting.value = val
			end
		end

		def keys
			@tournament.tournament_settings.all.collect { |x| x.name }
		end

		def empty?() keys.empty? end
		def count() keys.count end
		def length() count end
		def size() count end

		def method_missing(name, *args)
			if name.to_s.ends_with?('=')
				self[name.to_s.sub(/=$/, '').to_s] = args.first
			else
				return self[name.to_s]
			end
		end
	end

	# Joining/Leaving ##########################################################

	def joinable_by?(user)
		return (status==0 and user.can?(:join_tournament) and !players.include?(user))
	end

	def join(user)
		unless joinable_by?(user)
			return false
		end
		players.push(user)
	end

	def leave(user)
		if players.include?(user) && status == 0
			players.delete(user)
		end
	end

	# Configured methods #######################################################

	def scoring
		@scoring ||= "Scoring::#{self.scoring_method.camelcase}".constantize
	end

	# Options for configured methods/modules ###################################
	# We're conflicted about whether these should be `self.` or not. ###########

	def self.scoring_methods
		make_methods "scoring"
	end
	def scoring_methods
		self.class.scoring_methods
	end

	def sampling_methods
		self.class.make_methods("sampling").select do |name|
			"Sampling::#{name.camelcase}".constantize.works_with?(self.game)
		end
	end

	def self.scheduling_methods
		make_methods "scheduling"
	end
	def scheduling_methods
		self.class.scheduling_methods
	end

	def self.seeding_methods
		make_methods "seeding"
	end
	def seeding_methods
		self.class.seeding_methods
	end

	private
	def self.make_methods(dir)
		@methods ||= {}
		if @methods[dir].nil? or Rails.env.development?
			@methods[dir] = Dir.glob("#{Rails.root}/lib/#{dir}/*.rb").map{|filename| File.basename(filename, ".rb") }
		end
		return @methods[dir]
	end
end