@ -4,8 +4,12 @@
 
		
	
		
			
				
 
		
	
		
			
				- export ( [ start_link / 0 ,  init / 1 ,  handle_cast / 2 ,  handle_call / 3 ] ) .  
		
	
		
			
				
 
		
	
		
			
				- export ( [ set_test_config / 0 ] ) .  
		
	
		
			
				
 
		
	
		
			
				- include ( " erlk.hrl " ) .  
		
	
		
			
				
 
		
	
		
			
				- record ( division ,  { teams  =  [ ] ,  practice  =  0 ,  qualification  =  0 } ) .  
		
	
		
			
				- record ( config ,  { divisions  =  [ ] } ) .  
		
	
		
			
				- record ( state ,  { database_file  =  none ,  database  =  none ,  teams  =  [ ] ,  config  =  none } ) .  
		
	
		
			
				
 
		
	
		
			
				start_link ( )  - >  
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -39,49 +43,41 @@ fill_padding_schedule(Matches, Teams) ->
 
		
	
		
			
				  { Schedule ,  _ }  =  lists : mapfoldl ( fun  fill_padding_match / 2 ,  TeamsRandom ,  Matches ) , 
 
		
	
		
			
				  Schedule . 
 
		
	
		
			
				
 
		
	
		
			
				hash_teams_list ( Teams )  - >  
		
	
		
			
				  [  Y  | |  < < X : 4 > >  < =  crypto : hash ( sha ,  Teams ) ,  Y  < -  integer_to_list ( X , 16 ) ] . 
 
		
	
		
			
				
 
		
	
		
			
				init_db ( Database )  - >  
		
	
		
			
				  ok  =  sqlite3 : create_table ( Database ,  teams ,  [ { name ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                              { inspection ,  blob } ] , 
 
		
	
		
			
				                            [ { primary_key ,  [ name ] } ] ) , 
 
		
	
		
			
				  ok  =  sqlite3 : create_table ( Database ,  matches ,  [ { division ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                { round ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                { size ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                { teams ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                { number ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                { seed,  integer  ,  [ not_null ] } , 
 
		
	
		
			
				                                                { genid ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                { red_1 ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                { red_2 ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                { blue_1 ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                { blue_2 ,  text ,  [ not_null ] } ] , 
 
		
	
		
			
				                            [ { primary_key ,  [ division ,  round ,  size ,  teams ,  number ,  see ] } , 
 
		
	
		
			
				                            [ { primary_key ,  [ division ,  round ,  number ,  geni ] } , 
 
		
	
		
			
				                             { check ,  " round IN ('practice', 'qualification', 'elimination') " } , 
 
		
	
		
			
				                             { foreign_key ,  { [ blue_1 ] ,  teams ,  [ name ] ,  " ON DELETE RESTRICT " } } , 
 
		
	
		
			
				                             { foreign_key ,  { [ blue_2 ] ,  teams ,  [ name ] ,  " ON DELETE RESTRICT " } } , 
 
		
	
		
			
				                             { foreign_key ,  { [ red_1 ] ,  teams ,  [ name ] ,  " ON DELETE RESTRICT " } } , 
 
		
	
		
			
				                             { foreign_key ,  { [ red_2 ] ,  teams ,  [ name ] ,  " ON DELETE RESTRICT " } } ] ) , 
 
		
	
		
			
				
 
		
	
		
			
				  ok  =  sqlite3 : create_table ( Database ,  match_scores ,  [ { division ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { round ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { size ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { teams ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { number ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { seed,  integer  ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { genid ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { instance ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { score ,  blob ,  [ not_null ] } ] , 
 
		
	
		
			
				                            [ { primary_key ,  [ division ,  round ,  size ,  teams ,  number ,  see ,  instance ] } , 
 
		
	
		
			
				                             { foreign_key ,  { [ division ,  round ,  size ,  teams ,  number ,  see ] ,  matches ,  [ division ,  round ,  size ,  teams ,  number ,  see ] ,  " ON DELETE CASCADE " } } ] ) , 
 
		
	
		
			
				                            [ { primary_key ,  [ division ,  round ,  number ,  geni ,  instance ] } , 
 
		
	
		
			
				                             { foreign_key ,  { [ division ,  round ,  number ,  geni ] ,  matches ,  [ division ,  round ,  number ,  geni ] ,  " ON DELETE CASCADE " } } ] ) , 
 
		
	
		
			
				  ok  =  sqlite3 : create_table ( Database ,  match_states ,  [ { division ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { round ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { size ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { teams ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { number ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { seed,  integer  ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { genid ,  text ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { time ,  integer ,  [ not_null ] } , 
 
		
	
		
			
				                                                     { state ,  blob ,  [ not_null ] } ] , 
 
		
	
		
			
				                            [ { primary_key ,  [ division ,  round ,  size ,  teams ,  number ,  see ,  time ] } , 
 
		
	
		
			
				                             { foreign_key ,  { [ division ,  round ,  size ,  teams ,  number ,  see ] ,  matches ,  [ division ,  round ,  size ,  teams ,  number ,  see ] ,  " ON DELETE CASCADE " } } ] ) , 
 
		
	
		
			
				                            [ { primary_key ,  [ division ,  round ,  number ,  geni ,  time ] } , 
 
		
	
		
			
				                             { foreign_key ,  { [ division ,  round ,  number ,  geni ] ,  matches ,  [ division ,  round ,  number ,  geni ] ,  " ON DELETE CASCADE " } } ] ) , 
 
		
	
		
			
				
 
		
	
		
			
				  %  TODO :  finals 
 
		
	
		
			
				  %  ok  =  sqlite3 : create_table ( Database ,  finals ,  [ ] ,  [ { primary_key ,  [ ] } ] ) , 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -111,21 +107,19 @@ first_error([]) -> ok;
 
		
	
		
			
				first_error ( [ ok  |  Rest ] )  - >  first_error ( Rest ) ;  
		
	
		
			
				first_error ( [ Error  |  _ ] )  - >  Error .  
		
	
		
			
				
 
		
	
		
			
				delete_matches ( Database ,  Division ,  Size,  Seed ,  TeamsHash ,  Round  )  - >  
		
	
		
			
				  SQL  =  io_lib : format ( " DELETE FROM matches WHERE division =  ~p  AND  size = ~p  AND seed =  ~p  AND teams = ' ~s ' AND round = ' ~p ' " ,  [ Division ,  Size ,  Seed ,  TeamsHash  ,  Round ] ) , 
 
		
	
		
			
				delete_matches ( Database ,  Division ,  Round,  GenID  )  - >  
		
	
		
			
				  SQL  =  io_lib : format ( " DELETE FROM matches WHERE division =  ~p  AND  genid = ~p  AND round = ' ~p ' " ,  [ Division ,  GenID  ,  Round ] ) , 
 
		
	
		
			
				  sqlite3 : sql_exec_script ( Database ,  SQL ) . 
 
		
	
		
			
				
 
		
	
		
			
				write_matches ( Database ,  Division ,  Size,  Seed ,  TeamsHash ,  Round ,  MatchTeam  s)  - >  
		
	
		
			
				write_matches ( Database ,  Division ,  Round,  GenID ,  Matche  s)  - >  
		
	
		
			
				  Schedule  =  [ [ { division ,  Division } , 
 
		
	
		
			
				               { round ,  atom_to_list ( Round ) } , 
 
		
	
		
			
				               { size ,  Size } , 
 
		
	
		
			
				               { teams ,  TeamsHash } , 
 
		
	
		
			
				               { number ,  N } , 
 
		
	
		
			
				               { seed,  Seed  } , 
 
		
	
		
			
				               { genid ,  GenID } , 
 
		
	
		
			
				               { blue_1 ,  B1 } , 
 
		
	
		
			
				               { blue_2 ,  B2 } , 
 
		
	
		
			
				               { red_1 ,  R1 } , 
 
		
	
		
			
				               { red_2 ,  R2 } ]  | |  { N ,  [ B1 ,  B2 ,  R1 ,  R2 ] }  < -  lists : enumerate ( Match T eam s) ] , 
 
		
	
		
			
				               { red_2 ,  R2 } ]  | |  { N ,  [ B1 ,  B2 ,  R1 ,  R2 ] }  < -  lists : enumerate ( Match es) ] , 
 
		
	
		
			
				  [ ok  |  Resp ]  =  sqlite3 : write_many ( Database ,  matches ,  Schedule ) , 
 
		
	
		
			
				  lists : last ( Resp ) . 
 
		
	
		
			
				
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -152,6 +146,28 @@ pick_matches(Teams, Matches) ->
 
		
	
		
			
				
 
		
	
		
			
				pick_matches ( Teams )  - >  pick_matches ( Teams ,  [ ] ) .  
		
	
		
			
				
 
		
	
		
			
				% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %  
		
	
		
			
				- define ( TEST_CONFIG ,  #config { divisions  =  [ #division { teams  =  [ " A " ,  " B " ,  " C " ,  " D " ] ,  practice  =  1 } ] } ) .  
		
	
		
			
				set_test_config ( )  - >  
		
	
		
			
				  gen_server : call ( ? MODULE ,  { set_config ,  ? TEST_CONFIG } ) . 
 
		
	
		
			
				% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %  
		
	
		
			
				
 
		
	
		
			
				handle_call ( { set_config ,  Config } ,  _ ,  State )  when  is_record ( Config ,  config )  - >  
		
	
		
			
				  { reply ,  ok ,  State #state { config  =  Config } } ; 
 
		
	
		
			
				handle_call ( { new_schedule ,  Division ,  Round ,  Seed } ,  _ ,  State )  - >  
		
	
		
			
				  DivInfo  =  lists : nth ( Division ,  State #state.config #config.divisions ) , 
 
		
	
		
			
				  Teams  =  DivInfo #division.teams , 
 
		
	
		
			
				  Matches  =  case  Round  of 
 
		
	
		
			
				      practice  when  DivInfo #division.practice  =/=  0  - > 
 
		
	
		
			
				        DivInfo #division.practice ; 
 
		
	
		
			
				      qualification  when  DivInfo #division.qualification  =/=  0 - > 
 
		
	
		
			
				        DivInfo #division.qualification 
 
		
	
		
			
				  end , 
 
		
	
		
			
				  MatchTeams  =  create_schedule ( Seed ,  Matches ,  Teams ) , 
 
		
	
		
			
				  GenID  =  lists : sublist ( [  Y  | |  < < X : 4 > >  < =  crypto : hash ( sha ,  Teams  ++  [ Seed ,  Matches ] ) , 
 
		
	
		
			
				                               Y  < -  integer_to_list ( X ,  16 ) ] ,  4 ) , 
 
		
	
		
			
				  ok  =  write_matches ( State #state.database ,  Division ,  Round ,  GenID ,  MatchTeams ) , 
 
		
	
		
			
				  { reply ,  GenID ,  State } ; 
 
		
	
		
			
				handle_call ( { new_db ,  DatabaseFile } ,  _ ,  State )  - >  
		
	
		
			
				  ok  =  if  State #state.database  =:=  none  - >  ok ; 
 
		
	
		
			
				          true  - >  sqlite3 : close ( State #state.database ) 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -183,61 +199,6 @@ handle_cast({delete_teams, Removed}, State) ->
 
		
	
		
			
				handle_cast ( { add_teams ,  Teams } ,  State )  - >  
		
	
		
			
				  ok  =  first_error ( add_teams ( State #state.database ,  Teams ) ) , 
 
		
	
		
			
				  { noreply ,  State #state { teams  =  Teams } } ; 
 
		
	
		
			
				handle_cast ( { new_schedule ,  Division ,  Size ,  Seed ,  Teams ,  Round } ,  State )  - >  
		
	
		
			
				  MatchTeams  =  create_schedule ( Seed ,  Size ,  Teams ) , 
 
		
	
		
			
				  ok  =  write_matches ( State #state.database ,  Division ,  Size ,  Seed ,  hash_teams_list ( Teams ) ,  Round ,  MatchTeams ) , 
 
		
	
		
			
				  { noreply ,  State } ; 
 
		
	
		
			
				handle_cast ( { delete_schedule ,  Division ,  Size ,  Seed ,  TeamsHash ,  Round } ,  State )  - >  
		
	
		
			
				  ok  =  first_error ( delete_matches ( State #state.database ,  Division ,  Size ,  Seed ,  TeamsHash ,  Round ) ) , 
 
		
	
		
			
				handle_cast ( { delete_schedule ,  Division ,  Round ,  GenID } ,  State )  - >  
		
	
		
			
				  ok  =  first_error ( delete_matches ( State #state.database ,  Division ,  Round ,  GenID ) ) , 
 
		
	
		
			
				  { noreply ,  State } . 
 
		
	
		
			
				
 
		
	
		
			
				get_matches_from_db ( Database ,  Division ,  Round ,  Seed ,  Size ,  TeamsHash )  - >  
		
	
		
			
				  if  Size  ==  0  - >  [ ] ; 
 
		
	
		
			
				     Size  >  0  - >  SQL  =  io_lib : format ( " SELECT number, blue_1, blue_2, red_1, red_2 FROM 
 
		
	
		
			
				                                     matches  WHERE 
 
		
	
		
			
				                                     division  =  '~p'  AND 
 
		
	
		
			
				                                     round  =  '~p'  AND 
 
		
	
		
			
				                                     size  =  '~p'  AND 
 
		
	
		
			
				                                     seed  =  '~p'  AND 
 
		
	
		
			
				                                     teams  =  '~s' ; " , 
 
		
	
		
			
				                                     [ Division ,  Round ,  Size ,  Seed ,  TeamsHash ] ) , 
 
		
	
		
			
				                 [ { columns ,  Columns } ,  { rows ,  Rows } ]  =  sqlite3 : sql_exec ( Database ,  SQL ) , 
 
		
	
		
			
				                 [ ] 
 
		
	
		
			
				  end . 
 
		
	
		
			
				
 
		
	
		
			
				parse_division ( Division )  - >  
		
	
		
			
				  TeamsBinary  =  maps : get ( < < " teams " > > ,  Division ) , 
 
		
	
		
			
				  TeamsList  =  [ binary_to_list ( X )  | |  X  < -  TeamsBinary ] , 
 
		
	
		
			
				  TeamsHash  =  schedule : hash_teams_list ( TeamsList ) , 
 
		
	
		
			
				
 
		
	
		
			
				  PracticeRounds  =  maps : get ( < < " practice_rounds " > > ,  Division ) , 
 
		
	
		
			
				  PracticeSeed  =  maps : get ( < < " practice_seed " > > ,  Division ) , 
 
		
	
		
			
				
 
		
	
		
			
				  QualificationRounds  =  maps : get ( < < " qualification_rounds " > > ,  Division ) , 
 
		
	
		
			
				  QualificationSeed  =  maps : get ( < < " qualification_seed " > > ,  Division ) , 
 
		
	
		
			
				
 
		
	
		
			
				  #division_config { 
 
		
	
		
			
				     fields  =  [ binary_to_list ( X )  | |  X  < -  maps : get ( < < " fields " > > ,  Division ) ] , 
 
		
	
		
			
				     elimination_alliances  =  maps : get ( < < " elimination_alliances " > > ,  Division ) , 
 
		
	
		
			
				     practice_rounds  =  PracticeRounds , 
 
		
	
		
			
				     practice_seed  =  PracticeSeed , 
 
		
	
		
			
				     qualification_rounds  =  QualificationRounds , 
 
		
	
		
			
				     qualification_seed  =  QualificationSeed , 
 
		
	
		
			
				     teams  =  TeamsList , 
 
		
	
		
			
				     teams_hash  =  TeamsHash 
 
		
	
		
			
				    } . 
 
		
	
		
			
				
 
		
	
		
			
				parse_event_config ( ConfigJSON )  - >  
		
	
		
			
				  Config  =  jsone : decode ( list_to_binary ( ConfigJSON ) ) , 
 
		
	
		
			
				  Divisions  =  lists : map ( fun  parse_division / 1 ,  maps : get ( < < " divisions " > > ,  Config ) ) , 
 
		
	
		
			
				  TestingFields  =  [ binary_to_list ( X )  | |  X  < -  maps : get ( < < " testing_fields " > > ,  Config ) ] , 
 
		
	
		
			
				  SkillsFields  =  [ binary_to_list ( X )  | |  X  < -  maps : get ( < < " skills_fields " > > ,  Config ) ] , 
 
		
	
		
			
				  FinalsFields  =  [ binary_to_list ( X )  | |  X  < -  maps : get ( < < " finals_fields " > > ,  Config ) ] , 
 
		
	
		
			
				
 
		
	
		
			
				  #event_config { 
 
		
	
		
			
				     database_file  =  binary_to_list ( maps : get ( < < " database " > > ,  Config ) ) , 
 
		
	
		
			
				     finals_fields  =  FinalsFields , 
 
		
	
		
			
				     skills_fields  =  SkillsFields , 
 
		
	
		
			
				     testing_fields  =  TestingFields , 
 
		
	
		
			
				     divisions  =  Divisions 
 
		
	
		
			
				    } .