|  |  |  | @ -2,19 +2,27 @@ | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | -behaviour(gen_server). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | -export([start_link/0, init/1, handle_cast/2, handle_call/3, add_teams/1]). | 
		
	
		
			
				|  |  |  |  | -export([start_link/1, init/1, handle_cast/2, handle_call/3, add_teams/1]). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | -export([set_test_config/0, new/1, load/1]). | 
		
	
		
			
				|  |  |  |  | -export([set_test_config/0, new/1, close/0]). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | -record(division, {teams = [], practice = 0, qualification = 0}). | 
		
	
		
			
				|  |  |  |  | -record(config, {divisions = []}). | 
		
	
		
			
				|  |  |  |  | -record(state, {database_file = none, database = none, teams = [], config = none}). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | start_link() -> | 
		
	
		
			
				|  |  |  |  |   gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). | 
		
	
		
			
				|  |  |  |  | start_link(DatabaseFile) -> | 
		
	
		
			
				|  |  |  |  |   gen_server:start_link({local, ?MODULE}, ?MODULE, [DatabaseFile], []). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | init([]) -> | 
		
	
		
			
				|  |  |  |  |   {ok, #state{}}. | 
		
	
		
			
				|  |  |  |  | init([DatabaseFile]) -> | 
		
	
		
			
				|  |  |  |  |   Exists = filelib:is_regular(DatabaseFile), | 
		
	
		
			
				|  |  |  |  |   if Exists =:= true -> | 
		
	
		
			
				|  |  |  |  |        {ok, DB} = sqlite3:open(schedule_db, [{file, DatabaseFile}]), | 
		
	
		
			
				|  |  |  |  |        ok = sqlite3:sql_exec(DB, "PRAGMA foreign_keys = ON;"), | 
		
	
		
			
				|  |  |  |  |        {ok, #state{database_file = DatabaseFile, database = DB}}; | 
		
	
		
			
				|  |  |  |  |      true -> | 
		
	
		
			
				|  |  |  |  |        io:format("Failed to load database ~s~n", [DatabaseFile]), | 
		
	
		
			
				|  |  |  |  |        {ok, #state{database_file = none, database = none}} | 
		
	
		
			
				|  |  |  |  |   end. | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | init_db(Database) -> | 
		
	
		
			
				|  |  |  |  |   ok = sqlite3:create_table(Database, genids, [{genid, text, [not_null]}, | 
		
	
	
		
			
				
					|  |  |  | @ -66,16 +74,16 @@ init_db(Database) -> | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | delete_teams(Database, Teams) -> | 
		
	
		
			
				|  |  |  |  |   SQL = lists:append(["BEGIN; ", | 
		
	
		
			
				|  |  |  |  |          lists:append([io_lib:format("DELETE FROM teams WHERE name = ~p; ", | 
		
	
		
			
				|  |  |  |  |                                      [Team]) || Team <- Teams]), | 
		
	
		
			
				|  |  |  |  |          "COMMIT;"]), | 
		
	
		
			
				|  |  |  |  |                       lists:append([io_lib:format("DELETE FROM teams WHERE name = ~p; ", | 
		
	
		
			
				|  |  |  |  |                                                   [Team]) || Team <- Teams]), | 
		
	
		
			
				|  |  |  |  |                       "COMMIT;"]), | 
		
	
		
			
				|  |  |  |  |   first_error(sqlite3:sql_exec_script(Database, SQL)). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | add_teams(Database, Teams) -> | 
		
	
		
			
				|  |  |  |  |   SQL = lists:append(["BEGIN; ", | 
		
	
		
			
				|  |  |  |  |          lists:append([io_lib:format("INSERT INTO teams(name) VALUES('~s') ON CONFLICT(name) DO NOTHING; ", | 
		
	
		
			
				|  |  |  |  |                                      [Team]) || Team <- Teams]), | 
		
	
		
			
				|  |  |  |  |          "COMMIT;"]), | 
		
	
		
			
				|  |  |  |  |                       lists:append([io_lib:format("INSERT INTO teams(name) VALUES('~s') ON CONFLICT(name) DO NOTHING; ", | 
		
	
		
			
				|  |  |  |  |                                                   [Team]) || Team <- Teams]), | 
		
	
		
			
				|  |  |  |  |                       "COMMIT;"]), | 
		
	
		
			
				|  |  |  |  |   first_error(sqlite3:sql_exec_script(Database, SQL)). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | first_error([]) -> ok; | 
		
	
	
		
			
				
					|  |  |  | @ -93,7 +101,7 @@ write_matches(Database, Type, Teams, Seed, Size, Round, Matches) -> | 
		
	
		
			
				|  |  |  |  |                                     [GenID, atom_to_list(Type), Size, Seed]), | 
		
	
		
			
				|  |  |  |  |                       lists:append([io_lib:format( | 
		
	
		
			
				|  |  |  |  |                                       "INSERT INTO matches(genid, round, number, blue_1, blue_2, red_1, red_2) | 
		
	
		
			
				|  |  |  |  |                                        VALUES ('~s', '~s', ~p, '~s', '~s', '~s', '~s'); ", | 
		
	
		
			
				|  |  |  |  |                                       VALUES ('~s', '~s', ~p, '~s', '~s', '~s', '~s'); ", | 
		
	
		
			
				|  |  |  |  |                                        [GenID, atom_to_list(Round), N, B1, B2, R1, R2]) | 
		
	
		
			
				|  |  |  |  |                                         || {N, [B1, B2, R1, R2]} <- lists:enumerate(Matches)]), | 
		
	
		
			
				|  |  |  |  |                       "COMMIT;"]), | 
		
	
	
		
			
				
					|  |  |  | @ -111,11 +119,17 @@ add_teams(Teams) -> | 
		
	
		
			
				|  |  |  |  | new(DatabaseFile) -> | 
		
	
		
			
				|  |  |  |  |   gen_server:call(?MODULE, {new_db, DatabaseFile}). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | load(DatabaseFile) -> | 
		
	
		
			
				|  |  |  |  |   gen_server:call(?MODULE, {load_db, DatabaseFile}). | 
		
	
		
			
				|  |  |  |  | close() -> | 
		
	
		
			
				|  |  |  |  |   gen_server:call(?MODULE, close_db). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | handle_call({set_config, Config}, _, State) when is_record(Config, config) -> | 
		
	
		
			
				|  |  |  |  |   {reply, ok, State#state{config = Config}}; | 
		
	
		
			
				|  |  |  |  | handle_call(close_db, _, State) -> | 
		
	
		
			
				|  |  |  |  |   if State#state.database =:= none -> {reply, ok, State}; | 
		
	
		
			
				|  |  |  |  |      true -> | 
		
	
		
			
				|  |  |  |  |        ok = sqlite3:close(State#state.database), | 
		
	
		
			
				|  |  |  |  |        {reply, ok, State#state{database = none, database_file = none}} | 
		
	
		
			
				|  |  |  |  |   end; | 
		
	
		
			
				|  |  |  |  | handle_call({new_db, DatabaseFile}, _, State) -> | 
		
	
		
			
				|  |  |  |  |   ok = if State#state.database =:= none -> ok; | 
		
	
		
			
				|  |  |  |  |           true -> sqlite3:close(State#state.database) | 
		
	
	
		
			
				
					|  |  |  | @ -150,11 +164,11 @@ handle_call({new_schedule, Division, Round, Seed}, _, State) -> | 
		
	
		
			
				|  |  |  |  |   DivInfo = lists:nth(Division, State#state.config#config.divisions), | 
		
	
		
			
				|  |  |  |  |   Teams = DivInfo#division.teams, | 
		
	
		
			
				|  |  |  |  |   Size = case Round of | 
		
	
		
			
				|  |  |  |  |       practice when DivInfo#division.practice =/= 0 -> | 
		
	
		
			
				|  |  |  |  |         DivInfo#division.practice; | 
		
	
		
			
				|  |  |  |  |       qualification when DivInfo#division.qualification =/= 0-> | 
		
	
		
			
				|  |  |  |  |         DivInfo#division.qualification | 
		
	
		
			
				|  |  |  |  |   end, | 
		
	
		
			
				|  |  |  |  |            practice when DivInfo#division.practice =/= 0 -> | 
		
	
		
			
				|  |  |  |  |              DivInfo#division.practice; | 
		
	
		
			
				|  |  |  |  |            qualification when DivInfo#division.qualification =/= 0-> | 
		
	
		
			
				|  |  |  |  |              DivInfo#division.qualification | 
		
	
		
			
				|  |  |  |  |          end, | 
		
	
		
			
				|  |  |  |  |   Matches = schedule:create(Seed, Size, Teams), | 
		
	
		
			
				|  |  |  |  |   {ok, GenID} = write_matches(State#state.database, division, Teams, Seed, Size, Round, Matches), | 
		
	
		
			
				|  |  |  |  |   {reply, GenID, State}; | 
		
	
	
		
			
				
					|  |  |  | 
 |