1 /*
2  * Copyright (C) 2007 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.Timers;
20 using System.ComponentModel;
21 
22 using gbrainy.Core.Views;
23 using gbrainy.Core.Services;
24 
25 namespace gbrainy.Core.Main
26 {
27 	public class GameSession : IDrawable, IDrawRequest, IMouseEvent
28 	{
29 		[Flags]
30 		public enum Types
31 		{
32 			None			= 0,
33 			LogicPuzzles		= 2,
34 			Memory			= 4,
35 			Calculation		= 8,
36 			VerbalAnalogies		= 16,
37 			Custom			= 32,
38 			AllGames		= Memory | Calculation | LogicPuzzles | VerbalAnalogies
39 		}
40 
41 		public enum SessionStatus
42 		{
43 			NotPlaying,
44 			Playing,
45 			Answered,
46 			Finished,
47 		}
48 
49 		private TimeSpan game_time;
50 		private Game current_game;
51 		private GameManager game_manager;
52 		private System.Timers.Timer timer;
53 		private bool paused;
54 		private TimeSpan one_sec = TimeSpan.FromSeconds (1);
55 		private SessionStatus status;
56 		private ViewsControler controler;
57 		private ISynchronizeInvoke synchronize;
58 		private PlayerHistory player_history;
59 		private int id;
60 		private GameSessionHistoryExtended history;
61 		private GameSessionPlayList play_list;
62 
63 		public event EventHandler DrawRequest;
64 		public event EventHandler <UpdateUIStateEventArgs> UpdateUIElement;
65 
66 
GameSession(ITranslations translations)67 		public GameSession (ITranslations translations)
68 		{
69 			Translations = translations;
70 			id = 0;
71 			game_manager = new GameManager ();
72 			play_list = new GameSessionPlayList (game_manager);
73 			game_time = TimeSpan.Zero;
74 
75 			timer = new System.Timers.Timer ();
76 			timer.Elapsed += TimerUpdater;
77 			timer.Interval = (1 * 1000); // 1 second
78 
79 			controler = new ViewsControler (translations, this);
80 			Status = SessionStatus.NotPlaying;
81 			player_history = new PlayerHistory ();
82 			history = new GameSessionHistoryExtended ();
83 		}
84 
85 		public int ID {
86 			get {return id;}
87 		}
88 
89 		public GameSessionHistoryExtended History {
90 			get {return history;}
91 		}
92 
93 		public GameTypes AvailableGames {
94 			get { return game_manager.AvailableGameTypes; }
95 		}
96 
97 		public PlayerHistory PlayerHistory {
98 			set { player_history = value; }
99 			get { return player_history; }
100 		}
101 
102 		public ISynchronizeInvoke SynchronizingObject {
103 			set { synchronize = value; }
104 			get { return synchronize; }
105 		}
106 
107 		public Types Type {
108 			get { return play_list.GameType; }
109 			set { play_list.GameType = value; }
110 		}
111 
112 		public GameDifficulty Difficulty {
113 			get { return play_list.Difficulty; }
114 			set { play_list.Difficulty = value; }
115 		}
116 
117 		public string GameTime {
118 			get { return TimeSpanToStr (game_time);}
119 		}
120 
121 		public bool Paused {
122 			get {return paused; }
123 			set {paused = value; }
124 		}
125 
126 		public GameSessionPlayList PlayList {
127 			get { return play_list; }
128 			set { play_list = value; }
129 		}
130 
131 		public Game CurrentGame {
132 			get {return current_game; }
133 			set {
134 				current_game = value;
135 				controler.Game = value;
136 			}
137 		}
138 
139 		public bool EnableTimer {
140 			get {return timer.Enabled; }
141 			set {timer.Enabled = value; }
142 		}
143 
144 		public SessionStatus Status {
145 			get {return status; }
146 			set {
147 				status = value;
148 				controler.Status = value;
149 
150 				if (status == SessionStatus.Answered && CurrentGame != null)
151 					CurrentGame.EnableMouseEvents (false);
152 			}
153 		}
154 
155 		public GameManager GameManager {
156 			get { return game_manager;}
157 			set {
158 				game_manager = value;
159 				play_list.GameManager = value;
160 			}
161 		}
162 
163 		public string TimePerGame {
164 			get {
165 				TimeSpan average;
166 
167 				average = (history.GamesPlayed > 0) ? TimeSpan.FromSeconds (game_time.TotalSeconds / history.GamesPlayed) : game_time;
168 				return TimeSpanToStr (average);
169 			}
170 		}
171 
172 		private ITranslations Translations { get; set; }
173 
174 		public string StatusText {
175 			get {
176 				if (Status == SessionStatus.NotPlaying || Status == SessionStatus.Finished)
177 					return string.Empty;
178 
179 				string played, time, game;
180 
181 				played = String.Format (Translations.GetString ("Games played: {0} (Score: {1})"), history.GamesPlayed, history.TotalScore);
182 				time = String.Format (Translations.GetString ("Time: {0}"),
183 					paused == false ? GameTime : Translations.GetString ("Paused"));
184 
185 				if (CurrentGame != null) {
186 					// Translators: {0} is the name of the game
187 	 				game = String.Format (Translations.GetString ("Game: {0}"), CurrentGame.Name);
188 					// Translators: text in the status bar: games played - time - game name
189 					return String.Format (Translations.GetString ("{0} - {1} - {2}"), played, time, game);
190 				} else {
191 					// Translators: text in the status bar: games played - time
192 					return String.Format (Translations.GetString ("{0} - {1}"), played, time);
193 				}
194 			}
195 		}
196 
New()197 		public void New ()
198 		{
199 			if (Type == Types.None)
200 				throw new InvalidOperationException ("You have to setup the GameSession type");
201 
202 			id++;
203 			if (Status != SessionStatus.NotPlaying)
204 				End ();
205 
206 			history.Clear ();
207 			game_time = TimeSpan.Zero;
208 			timer.SynchronizingObject = SynchronizingObject;
209 			EnableTimer = true;
210 		}
211 
End()212 		public void End ()
213 		{
214 			// Making a deep copy of GameSessionHistory type (base class) for serialization
215 			player_history.SaveGameSession (history.Copy ());
216 
217 			if (CurrentGame != null) {
218 				CurrentGame.DrawRequest -= GameDrawRequest;
219 				CurrentGame.UpdateUIElement -= GameUpdateUIElement;
220 				CurrentGame.Finish ();
221 			}
222 
223 			EnableTimer = false;
224 			timer.SynchronizingObject = null;
225 
226 			paused = false;
227 			CurrentGame = null;
228 			Status = SessionStatus.Finished;
229 		}
230 
NextGame()231 		public void NextGame ()
232 		{
233 			try
234 			{
235 				if (CurrentGame != null) {
236 					CurrentGame.DrawRequest -= GameDrawRequest;
237 					CurrentGame.UpdateUIElement -= GameUpdateUIElement;
238 					CurrentGame.Finish ();
239 				}
240 
241 				history.GamesPlayed++;
242 				CurrentGame = play_list.GetPuzzle ();
243 				CurrentGame.Translations = Translations;
244 				CurrentGame.SynchronizingObject = SynchronizingObject;
245 				CurrentGame.DrawRequest += GameDrawRequest;
246 				CurrentGame.UpdateUIElement += GameUpdateUIElement;
247 
248 				CurrentGame.Begin ();
249 
250 				CurrentGame.GameTime = TimeSpan.Zero;
251 				Status = SessionStatus.Playing;
252 			}
253 			catch (Exception e)
254 			{
255 				Console.WriteLine ("GameSession.NextGame {0}", e);
256 			}
257 		}
258 
Pause()259 		public void Pause ()
260 		{
261 			EnableTimer = false;
262 			paused = true;
263 
264 			if (CurrentGame != null)
265 				CurrentGame.EnableMouseEvents (false);
266 		}
267 
Resume()268 		public void Resume ()
269 		{
270 			EnableTimer = true;
271 			paused = false;
272 
273 			if (CurrentGame != null)
274 				CurrentGame.EnableMouseEvents (true);
275 		}
276 
ScoreGame(string answer)277 		public bool ScoreGame (string answer)
278 		{
279 			int game_score;
280 
281 			if (CurrentGame == null || Status == SessionStatus.Answered)
282 				return false;
283 
284 			game_score = CurrentGame.Score (answer);
285 			history.UpdateScore (CurrentGame.Type, Difficulty, game_score);
286 
287 			Status = SessionStatus.Answered;
288 			return (game_score > 0 ? true : false);
289 		}
290 
TimerUpdater(object source, ElapsedEventArgs e)291 		private void TimerUpdater (object source, ElapsedEventArgs e)
292 		{
293 			lock (this) {
294 				if (CurrentGame == null)
295 					return;
296 
297 				game_time = game_time.Add (one_sec);
298 				CurrentGame.GameTime = CurrentGame.GameTime + one_sec;
299 			}
300 
301 			if (UpdateUIElement == null)
302 				return;
303 
304 			UpdateUIElement (this, new UpdateUIStateEventArgs (UpdateUIStateEventArgs.EventUIType.Time, null));
305 		}
306 
TimeSpanToStr(TimeSpan time)307 		static private string TimeSpanToStr (TimeSpan time)
308 		{
309 			DateTime dtime;
310 
311 			// Convert it to DateTime to be able to use CultureSensitive formatting
312 			dtime = new DateTime (1970, 1, 1, time.Hours, time.Minutes, time.Seconds);
313 
314 			return dtime.Hour > 0 ? dtime.ToString ("hh:mm:ss") : dtime.ToString ("mm:ss");
315 		}
316 
GameUpdateUIElement(object obj, UpdateUIStateEventArgs args)317 		public void GameUpdateUIElement (object obj, UpdateUIStateEventArgs args)
318 		{
319 			if (UpdateUIElement != null)
320 				UpdateUIElement (this, args);
321 		}
322 
323 		// A game has requested a redraw, scale the request to the object
324 		// subscribed to GameSession.GameDrawRequest
GameDrawRequest(object o, EventArgs args)325 		public void GameDrawRequest (object o, EventArgs args)
326 		{
327 			if (DrawRequest != null)
328 				DrawRequest (this, EventArgs.Empty);
329 		}
330 
Draw(CairoContextEx gr, int width, int height, bool rtl)331 		public virtual void Draw (CairoContextEx gr, int width, int height, bool rtl)
332 		{
333 			controler.CurrentView.Draw (gr, width, height, rtl);
334 		}
335 
MouseEvent(object obj, MouseEventArgs args)336 		public void MouseEvent (object obj, MouseEventArgs args)
337 		{
338 			if (controler.CurrentView as IMouseEvent != null)
339 				(controler.CurrentView as IMouseEvent).MouseEvent (this, args);
340 		}
341 	}
342 }
343