using System;
using System.IO;
using System.Runtime.Serialization;
using System.Windows.Forms;
using nft.framework;
using nft.framework.plugin;
using nft.core.schedule;
using nft.util;
using nft.impl.game;
using nft.framework.drawing;
using System.Drawing;
using nft.impl.view;
using nft.core.view;
using nft.core.geometry;
using nft.ui.mainframe;

namespace nft.core.game
{
	/// <summary>
	/// GameManager manages current game, game options, and save/load games.
	/// </summary>
	public class GameManager
	{		
		static private GameManager theManager;
		static public GameManager theInstance { get{ return theManager; } }

        static GameManager()
		{
			theManager = new GameManager( Main.mainFrame );
		}

		protected IMainFrame theFrame;
		protected IGameMode _curMode;
		protected IGame _curGame;
        protected ToolCollection tools;
		/// <summary>
		/// Fired after a new world is loaded/created.
		/// </summary>
		public event GameEventHandler OnGameStart;
        public event GameEventHandler OnGameClose;

        protected GameManager(IMainFrame mainFrame)
		{
			this.theFrame = mainFrame;
            this.tools = new ToolCollection(this);
            theFrame.ActiveViewChanged += new EventHandler<EventArgs>(theFrame_ActiveViewChanged);
		}

		public IGameMode CurrentMode { get{ return _curMode; } }
		public IGame CurrentGame { get{ return _curGame; } }

        public ToolCollection Tools { get { return tools; } }

        [Obsolete]
        public void SetGame(IGame newgame, IGameMode mode, bool prompt){}

        public void NewGameFromMap(ITerrainMap map, IGameMode mode, bool prompt) {
            NewGameFromMap(null, map, Calendar.ActiveCalendar, mode, prompt);
        }

        public virtual void NewGameFromMap(string name, ITerrainMap map, Calendar cal, IGameMode mode, bool prompt)
		{
			if(_curGame != null)
			{
                if (prompt) {
                    if (!ConfirmCloseGame()) return;
                } else {
                    DetachCurrentGame();
                }

			}
            IGame newgame = CreateGame(name, map, cal);
            AttachCurrentGame(newgame);
            _curMode = mode;
		}

        protected virtual IGame CreateGame(string name, ITerrainMap map, Calendar cal) {
            if(name==null || name.Length == 0) name = I18n.T("GameManager", "NewGame");
            return new GameImpl(name, map, cal);
        }

        protected virtual void AttachCurrentGame(IGame gm) {
            _curGame = gm;
            _curGame.Closing += Game_Closing;
            _curGame.Start();
            if (OnGameStart != null) {
                OnGameStart(new GameEventArgs(_curGame));
            }
            _curGame.Views.OpenNew();
        }

        void Game_Closing(object sender, EventArgs e) {
            if (_curGame == sender) {
                DetachCurrentGame();
            }
        }
        protected virtual void DetachCurrentGame() {
            if (!_curGame.Closed) {
                _curGame.Closing -= Game_Closing;
                _curGame.Close();
            }
            if (OnGameClose != null) {
                OnGameClose(new GameEventArgs(_curGame));
            }
            _curGame = null;
        }

        public event EventHandler ActiveViewChanged;

        public ViewController ActiveView {
            get {
                if (CurrentGame != null) {
                    return CurrentGame.Views.ActiveView;
                } else {
                    return null;
                }
            }
        }

        /// <summary>
		/// Starts a new game
		/// </summary>
		protected void newGame() 
		{
			if(!ConfirmCloseGame()) return;

//			NewWorldDialog dialog = new NewWorldDialog();
//
//			if(dialog.ShowDialog(this)==DialogResult.OK) 
//			{
//				IGame game;
//				try
//				{
//					IGame game = dialog.createGame();
//				}
//				catch(Exception e)
//				{
//					string text = Main.resources["game.game_create_error"].stringValue;
//					UIUtil.ShowException(text,e,UIInformLevel.severe );
//				}
//				SetGame(game, false );
//			}
		}

		/// <summary>
		/// prompt before close current game.
		/// if user allows, current game is closed.
		/// </summary>
		/// <returns>true if the current world can be safely destroyed.</returns>
		public bool ConfirmCloseGame() 
		{
			bool b = true;
			if(_curGame!=null && _curGame.Modified) 
			{
                b = _curGame.ConfirmClose();
			}
			return b;
		}

        private readonly string filterString = I18n.T("Game data (*.ftgd)|*.ftgd|Game data[full packaged] (*.ftgt)|*.ftgt");
		/// <summary>
		/// Saves the current game.
		/// </summary>
		/// <returns>DialogResult.OK if the game was in fact saved.</returns>
		private bool saveGame() 
		{
			using(SaveFileDialog sd = new SaveFileDialog()) 
			{
//				sd.FileName = World.world.name;
//				sd.Filter = filterString;
//				sd.RestoreDirectory = true;
//
//				DialogResult r=0 = sd.ShowDialog(this);
//
//				if(r==DialogResult.OK) 
//				{
//					Cursor.Current = Cursors.WaitCursor;
//
//					// use the file name to update the name of the world
//					World.world.name = Path.GetFileNameWithoutExtension(sd.FileName);
//					updateCaption();
//
//					// save the game
//					saveGame( new FileInfo(sd.FileName) );
//				}
//				return r;
				return false;
			}
		}

		private void saveGame( FileInfo file ) 
		{
//			Stream stream = file.OpenWrite();
//			stream.WriteByte((byte)'U');
//			stream.WriteByte((byte)'C');
//			//			stream.WriteByte((byte)'B');
//			//			stream.WriteByte((byte)'Z');
//			//			stream = new BZip2OutputStream(stream);
//			//			stream = new GZipOutputStream( stream );
//			World.world.save( getFormatter(file), stream );
//			stream.Close();
//			mruMenu.addFile(file);
		}


		private void loadGame() 
		{
			if(!ConfirmCloseGame()) return;

			using(OpenFileDialog ofd = new OpenFileDialog()) 
			{
//				ofd.Filter = filterString;
//				ofd.RestoreDirectory = true;
//
//				if(ofd.ShowDialog(this)==DialogResult.OK)
//					loadGame( new FileInfo(ofd.FileName) );
			}
		}

		/// <summary>
		/// Loads a game from a file.
		/// </summary>
		internal void loadGame( FileInfo file ) 
		{
//			try
//			{
//				loadGame(file, file.OpenRead() );
//				mruMenu.addFile(file);
//			}
//			catch( Exception e )
//			{
//				string templ = Main.resources["game.game_load_error"].stringValue;
//				UIUtil.ShowException(string.Format(templ,file.Name),e,UIInformLevel.severe );
//			}
		}
		
		private IFormatter getFormatter( char formatByte ) 
		{
//			if( formatByte=='X' )
//				return new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
//			else
				return new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
		}

		/// <summary> Load a game from a stream. </summary>
		private void loadGame( Stream stream ) 
		{
//			IFormatter f;
//			try 
//			{
//				// read the header
//				int b1 = stream.ReadByte();
//				int b2 = stream.ReadByte();
//
//				f = getFormatter(b1); // first byte specifies formatter.
//
//				if( b2=='Z' ) // second byte specifies compress mode.
//				{
//					stream = new BZip2InputStream(stream);
//				} 
//				else 
//				{
//					// uncompressed
//				}
//
//				f.Binder = new PluginSerializationBinder();
//				//Main.bgmManager.currentBGM = ((BGMContribution[])f.Deserialize(stream))[0];
//				_curGame = (IGame)f.Deserialize(stream);
//			} 
//			catch( Exception e ) 
//			{
//				throw e;
//			}
//			finally
//			{
//				stream.Close();
//			}
		}

        void theFrame_ActiveViewChanged(object sender, EventArgs e) {
            if (ActiveViewChanged != null) {
                ActiveViewChanged(this, e);
            }
        }

    }
}
