// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net;
using ClassicalSharp.Audio;
using ClassicalSharp.Commands;
using ClassicalSharp.Entities;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Gui;
using ClassicalSharp.Map;
using ClassicalSharp.Model;
using ClassicalSharp.Network;
using ClassicalSharp.Particles;
using ClassicalSharp.Renderers;
using ClassicalSharp.Selections;
using ClassicalSharp.TexturePack;
using OpenTK;
using OpenTK.Input;
namespace ClassicalSharp {
		
	///  Represents a game component. 
	public interface IGameComponent : IDisposable {
		
		///  Called when the game is being loaded. 
		void Init( Game game );
		
		///  Called when the texture pack has been loaded and all components have been initalised. 
		void Ready( Game game );
		
		///  Called to reset the component's state when the user is reconnecting to a server. 
		void Reset( Game game );
		
		///  Called to update the component's state when the user begins loading a new map. 
		void OnNewMap( Game game );
		
		///  Called to update the component's state when the user has finished loading a new map. 
		void OnNewMapLoaded( Game game );
	}
	
	///  Represents a task that runs on the main thread every certain interval. 
	public class ScheduledTask {
		public double Accumulator, Interval;
		public Action Callback;
	}
	
	public partial class Game {
		
		///  Abstracts the underlying 3D graphics rendering API. 
		public IGraphicsApi Graphics;
		
		///  Contains the block data and metadata/properties for the player's current world. 
		public World World;
		
		///  Represents a connection to a multiplayer or a singleplayer server. 
		public IServerConnection Server;
		
		///  List of all entities in the current map, including the player. 
		public EntityList Entities;
		
		///  Entity representing the player. 
		public LocalPlayer LocalPlayer;
		
		///  Contains information for each player in the current world 
		/// (or for whole server if supported). 
		public TabList TabList;
		
		///  Current camera the player is using to view the world with. 
		///  e.g. first person, thid person, forward third person, etc. 
		public Camera Camera;
		Camera firstPersonCam, thirdPersonCam, forwardThirdPersonCam;
		
		///  Contains the metadata about each currently defined block. 
		///  e.g. blocks light, height, texture IDs, etc. 
		public BlockInfo BlockInfo;
		
		///  Total rendering time(in seconds) elapsed since the client was started. 
		public double accumulator;
		public TerrainAtlas2D TerrainAtlas;
		public TerrainAtlas1D TerrainAtlas1D;
		public SkinType DefaultPlayerSkinType;
		
		///  Accumulator for the number of chunk updates performed. Reset every second. 
		public int ChunkUpdates;
		
		///  Whether the third person camera should have their camera position clipped so as to not intersect blocks. 
		public bool CameraClipping = true;
		
		public bool ShowClock = false;
		
		public bool SkipClear = false;
		
		public MapRenderer MapRenderer;
		public MapBordersRenderer MapBordersRenderer;
		public EnvRenderer EnvRenderer;
		public WeatherRenderer WeatherRenderer;
		public Inventory Inventory;
		public IDrawer2D Drawer2D;
		public GuiInterface Gui;
		
		public CommandList CommandList;
		public SelectionManager SelectionManager;
		public ParticleManager ParticleManager;
		public PickedPosRenderer Picking;
		public PickedPos SelectedPos = new PickedPos(), CameraClipPos = new PickedPos();
		public ModelCache ModelCache;
		internal string skinServer, chatInInputBuffer = null;
		internal int defaultIb;
		public OtherEvents Events = new OtherEvents();
		public EntityEvents EntityEvents = new EntityEvents();
		public WorldEvents WorldEvents = new WorldEvents();
		public UserEvents UserEvents = new UserEvents();
		public InputHandler InputHandler;
		public Chat Chat;
		public HeldBlockRenderer HeldBlockRenderer;
		public AudioPlayer AudioPlayer;
		public AxisLinesRenderer AxisLinesRenderer;
		public SkyboxRenderer SkyboxRenderer;
		
		public List Components = new List();
		public List Tasks = new List();
		///  Whether x to stone brick tiles should be used. 
		public bool UseCPEBlocks = false;
		
		///  Account username of the player. 
		public string Username;
		
		///  Verification key used for multiplayer, unique for the username and individual server. 
		public string Mppass;
		
		///  IP address of multiplayer server connected to, null if singleplayer. 
		public IPAddress IPAddress;
		
		///  Port of multiplayer server connected to, 0 if singleplayer. 
		public int Port;
		
		///  Radius of the sphere the player can see around the position of the current camera. 
		public float ViewDistance = 512;
		internal float MaxViewDistance = 32768, UserViewDistance = 512;
		
		///  Field of view for the current camera in degrees. 
		public int Fov = 70;
		internal int DefaultFov, ZoomFov = 0;
		
		///  Strategy used to limit how many frames should be displayed at most each second. 
		public FpsLimitMethod FpsLimit;
		
		///  Whether lines should be rendered for each axis. 
		public bool ShowAxisLines;
		
		///  Whether players should animate using simple swinging parallel to their bodies. 
		public bool SimpleArmsAnim;
		
		///  Whether mouse rotation on the y axis should be inverted. 
		public bool InvertMouse;
		
		public long Vertices;
		public FrustumCulling Culling;
		public AsyncDownloader AsyncDownloader;
		public Matrix4 View, Projection;
		
		///  How sensitive the client is to changes in the player's mouse position. 
		public int MouseSensitivity = 30;
		
		public bool TabAutocomplete;
		
		public bool UseClassicGui, UseClassicTabList, UseClassicOptions, ClassicMode, ClassicHacks;
		
		public bool PureClassic { get { return ClassicMode && !ClassicHacks; } }
		
		public bool AllowCustomBlocks, UseCPE, AllowServerTextures;
		
		public bool SmoothLighting;
		
		public string FontName = "Arial";
		
		public int ChatLines = 12;
		public bool ClickableChat = false, HideGui = false, ShowFPS = true;
		internal float HotbarScale = 1, ChatScale = 1, InventoryScale = 1;
		public bool ViewBobbing, ShowBlockInHand;
		public bool UseSound, UseMusic, ModifiableLiquids;
		
		public Vector3 CurrentCameraPos;
		
		public Animations Animations;
		internal int CloudsTex;
		internal bool screenshotRequested;
		internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" ); 
		internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" );
		internal EntryList ETags = new EntryList( "etags.txt" );
		internal EntryList LastModified = new EntryList( "lastmodified.txt" );
		
		
		///  Calculates the amount that the hotbar widget should be scaled by when rendered. 
		///  Affected by both the current resolution of the window, as well as the
		/// scaling specified by the user (field HotbarScale). 
		public float GuiHotbarScale { get { return Scale( MinWindowScale  * HotbarScale ); } }
		
		///  Calculates the amount that the block inventory menu should be scaled by when rendered. 
		///  Affected by both the current resolution of the window, as well as the
		/// scaling specified by the user (field InventoryScale). 
		public float GuiInventoryScale { get { return Scale( MinWindowScale  * InventoryScale ); } }
		
		///  Calculates the amount that 2D chat widgets should be scaled by when rendered. 
		///  Affected by both the current resolution of the window, as well as the
		/// scaling specified by the user (field ChatScale). 
		public float GuiChatScale { get { return Scale( (Height / 480f) * ChatScale ); } }
		
		float MinWindowScale { get { return Math.Min( Width / 640f, Height / 480f ); } }
		
		public float Scale( float value ) { 
			return (float)Math.Round( value * 10, MidpointRounding.AwayFromZero ) / 10; 
		}
		
		string defTexturePack = "default.zip";
		///  Gets or sets the path of the default texture pack that should be used by the client. 
		///  If the custom default texture pack specified by the user could not be found,
		/// this method returns "default.zip". 
		public string DefaultTexturePack {
			get {
				string path = Path.Combine( Program.AppDirectory, TexturePackExtractor.Dir );
				path = Path.Combine( path, defTexturePack );
				return File.Exists( path ) && !ClassicMode ? defTexturePack : "default.zip"; 
			}
			set {
				defTexturePack = value;
				Options.Set( OptionsKey.DefaultTexturePack, value );
			}
		}
		
		internal IPlatformWindow window;
		public MouseDevice Mouse;
		public KeyboardDevice Keyboard;
		
		public int Width, Height;
		
		public bool Focused { get { return window.Focused; } }
		
		public bool Exists { get { return window.Exists; } }
		
		public Point PointToScreen( Point coords ) {
			return window.PointToScreen( coords );
		}
		
		public bool VSync {
			get { return window.VSync; }
			set { window.VSync = value; }
		}
		
		bool visible = true;
		internal bool realVisible = true;
		public bool CursorVisible { 
			get { return visible; }
			set {
				// Defer mouse visibility changes.
				realVisible = value;
				if( Gui.overlays.Count > 0 ) return;
				   
				// Only set the value when it has changes.
				if( visible == value ) return;
				window.CursorVisible = value;
				visible = value;
			}
		}
		
		public Point DesktopCursorPos {
			get { return window.DesktopCursorPos; }
			set { window.DesktopCursorPos = value; }
		}
	}
}