1 /*
2  * Copyright (C) 2007-2010 Jordi Mas i Hernàndez <jmas@softcatala.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 using System;
19 using System.Collections.Generic;
20 using System.Reflection;
21 
22 using gbrainy.Core.Services;
23 using gbrainy.Core.Main.Verbal;
24 using gbrainy.Core.Main.Xml;
25 
26 namespace gbrainy.Core.Main
27 {
28 	// Manages all the games available on the system
29 	public class GameManager
30 	{
31 		static Type[] VerbalAnalogiesInternal = new Type[]
32 		{
33 			typeof (AnalogiesQuestionAnswer),
34 			typeof (AnalogiesMultipleOptions),
35 			typeof (AnalogiesPairOfWordsOptions),
36 			typeof (AnalogiesPairOfWordsCompare),
37 		};
38 
39 		List <GameLocator> available_games; 	// List of all available games in the system
40 		int cnt_logic, cnt_memory, cnt_calculation, cnt_verbal;
41 		static bool domain_load;
42 
GameManager()43 		public GameManager ()
44 		{
45 			available_games = new List <GameLocator> ();
46 			cnt_logic = cnt_memory = cnt_calculation = cnt_verbal = 0;
47 		}
48 
49 		public GameTypes AvailableGameTypes {
50 			get {
51 				GameTypes types = GameTypes.None;
52 
53 				if (cnt_logic > 0)
54 					types |= GameTypes.LogicPuzzle;
55 
56 				if (cnt_calculation > 0)
57 					types |= GameTypes.Calculation;
58 
59 				if (cnt_memory > 0)
60 					types |= GameTypes.Memory;
61 
62 				if (cnt_verbal > 0)
63 					types |= GameTypes.VerbalAnalogy;
64 
65 				return types;
66 			}
67 		}
68 
69 		// Returns all the games available for playing
70 		public GameLocator [] AvailableGames {
71 			get { return available_games.ToArray (); }
72 		}
73 
74 		// Gives the Assembly.Load used in GameManager the right path to load the application assemblies
ResolveAssemblyLoad(object sender, ResolveEventArgs args)75 		static Assembly ResolveAssemblyLoad (object sender, ResolveEventArgs args)
76 		{
77 			IConfiguration config = ServiceLocator.Instance.GetService <IConfiguration> ();
78 			string asm_dir = config.Get <string> (ConfigurationKeys.AssembliesDir);
79         		string full_name = System.IO.Path.Combine (asm_dir, args.Name);
80 			return Assembly.LoadFile (full_name);
81    		}
82 
83 		// Dynamic load of the gbrainy.Games.Dll assembly
LoadAssemblyGames(string file)84 		public void LoadAssemblyGames (string file)
85 		{
86 			const string CLASS = "gbrainy.Games.GameList";
87 			const string LOGIC_METHOD = "LogicPuzzles";
88 			const string CALCULATION_METHOD = "Calculation";
89 			const string MEMORY_METHOD = "Memory";
90 
91 			Assembly asem;
92 			Type type = null;
93 			PropertyInfo prop;
94 			object obj;
95 
96 			try
97 			{
98 				if (domain_load == false)
99 				{
100 					AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler (ResolveAssemblyLoad);
101 					domain_load = true;
102 				}
103 
104 				asem = Assembly.Load (file);
105 
106 				foreach (Type t in asem.GetTypes())
107 				{
108 					if (t.FullName == CLASS)
109 					{
110 						type = t;
111 						break;
112 					}
113 				}
114 
115 				obj = Activator.CreateInstance (type);
116 
117 				prop = type.GetProperty (LOGIC_METHOD);
118 				if (prop != null)
119 					cnt_logic += AddGamesAndVariations ((Type []) prop.GetValue (obj, null));
120 
121 				prop = type.GetProperty (MEMORY_METHOD);
122 				if (prop != null)
123 					cnt_memory += AddGamesAndVariations ((Type []) prop.GetValue (obj, null));
124 
125 				prop = type.GetProperty (CALCULATION_METHOD);
126 				if (prop != null)
127 					cnt_calculation += AddGamesAndVariations ((Type []) prop.GetValue (obj, null));
128 			}
129 
130 			catch (Exception e)
131 			{
132 				Console.WriteLine ("GameManager.LoadAssemblyGames. Could not load file {0}. Error {1}", file, e);
133 			}
134 		}
135 
136 		// XML are stored using the Variant as a pointer to the game + the internal variant
LoadGamesFromXml(string file)137 		public void LoadGamesFromXml (string file)
138 		{
139 			// Load defined XML games
140 			GamesXmlFactory xml_games;
141 
142 			xml_games = new GamesXmlFactory ();
143 			xml_games.Read (file);
144 
145 			Type type = typeof (GameXml);
146 			int cnt = 0;
147 
148 			foreach (GameXmlDefinition game in xml_games.Definitions)
149 			{
150 				// If the game has variants the game definition is used as reference
151 				// but only the variants are playable. The first variant is used as game (IsGame = true)
152 				available_games.Add (new GameLocator (type, cnt++, game.Type, true));
153 
154 				switch (game.Type) {
155 				case GameTypes.LogicPuzzle:
156 					cnt_logic++;
157 					break;
158 				case GameTypes.Calculation:
159 					cnt_calculation++;
160 					break;
161 				default:
162 					break;
163 				}
164 
165 				for (int i = 1; i < game.Variants.Count; i++)
166 				{
167 					available_games.Add (new GameLocator (type, cnt++, game.Type, false));
168 				}
169 			}
170 		}
171 
172 		// Load an XML file with analogies
LoadVerbalAnalogies(string file)173 		public void LoadVerbalAnalogies (string file)
174 		{
175 			AnalogiesFactory.Read (file);
176 			cnt_verbal += AddVerbalGamesAndVariations (VerbalAnalogiesInternal);
177 		}
178 
179 		// Unload previous assembly, xml and verbal analogies loaded games
ResetAvailableGames()180 		public void ResetAvailableGames ()
181 		{
182 			available_games.Clear ();
183 		}
184 
AddString(String str)185 		private String AddString(String str)
186 		{
187 			return " - " + str + Environment.NewLine;
188 		}
189 
GetGamesSummary(ITranslations translations)190 		public string GetGamesSummary (ITranslations translations)
191 		{
192 			String s = string.Empty;
193 	#if MONO_ADDINS
194 			s += translations.GetString ("Extensions database:") + " " +
195 					System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "gbrainy");
196 
197 			s += Environment.NewLine;
198 	#endif
199 			// Translators: 'Games registered' is the games know to gbrainy (build-in and load from addins-in and external files)
200             int total = cnt_logic + cnt_memory + cnt_calculation + cnt_verbal;
201             s += String.Format (translations.GetPluralString ("{0} game registered:", "{0} games registered:", total) +  Environment.NewLine, total);
202             s += AddString (String.Format (translations.GetPluralString ("{0} logic puzzle", "{0} logic puzzles", cnt_logic), cnt_logic));
203             s += AddString (String.Format (translations.GetPluralString ("{0} calculation trainer", "{0} calculation trainers", cnt_calculation), cnt_calculation));
204             s += AddString (String.Format (translations.GetPluralString ("{0} memory trainer", "{0} memory trainers", cnt_memory), cnt_memory));
205             s += AddString (String.Format (translations.GetPluralString ("{0} verbal analogy", "{0} verbal analogies", cnt_verbal), cnt_verbal));
206 			return s;
207 		}
208 
209 		// Adds all the games and its variants into the available games list
AddGamesAndVariations(Type [] types)210 		int AddGamesAndVariations (Type [] types)
211 		{
212 			Game game;
213 			int cnt = 0;
214 
215 			foreach (Type type in types)
216 			{
217 				game = (Game) Activator.CreateInstance (type, true);
218 				for (int i = 0; i < game.Variants; i++)
219 				{
220 					available_games.Add (new GameLocator (type, i, game.Type, game.Variants == 1));
221 				}
222 				cnt += game.Variants;
223 			}
224 			return cnt;
225 		}
226 
227 		// Adds all the games and its variants into the available games list
AddVerbalGamesAndVariations(Type [] types)228 		int AddVerbalGamesAndVariations (Type [] types)
229 		{
230 			Game game;
231 			int cnt = 0;
232 
233 			foreach (Type type in types)
234 			{
235 				game = (Game) Activator.CreateInstance (type, true);
236 				for (int i = 0; i < game.Variants; i++)
237 				{
238 					available_games.Add (new GameLocator (type, i, game.Type, true));
239 				}
240 				cnt += game.Variants;
241 			}
242 			return cnt;
243 		}
244 	}
245 }
246