using System;
using DxLibDLL;

namespace Nlgp1 {

	public sealed class Controller {

		public readonly int Frames;

		public readonly Key Left;

		public readonly Key Up;

		public readonly Key Right;

		public readonly Key Down;

		public readonly Key Ok;

		public readonly Key Cancel;

		public readonly Key Jump;

		public readonly Key Dash;

		public readonly Key Attack;

		public readonly Key Start;

		public readonly Key Select;

		public struct Key {

			public bool IsDown {
				get {
					return this.IsHit && this.Frames == 0;
				}
			}

			public bool IsUp {
				get {
					return !this.IsHit && this.Frames == 0;
				}
			}

			public readonly bool IsHit;

			public readonly int Frames;

			public Key( bool isHit , int frames ) {
				this.IsHit = isHit;
				this.Frames = frames;
			}
		}

		public static Controller Update() {

			bool left = false;
			bool up = false;
			bool right = false;
			bool down = false;
			bool ok = false;
			bool cancel = false;
			bool jump = false;
			bool dash = false;
			bool attack = false;
			bool start = false;
			bool select = false;

			DX.HitKeyStateAll hitKeyStateAll;
			DX.GetHitKeyStateAll( out hitKeyStateAll );
			left |= hitKeyStateAll[ DX.KEY_INPUT.LEFT ];
			up |= hitKeyStateAll[ DX.KEY_INPUT.UP ];
			right |= hitKeyStateAll[ DX.KEY_INPUT.RIGHT ];
			down |= hitKeyStateAll[ DX.KEY_INPUT.DOWN ];
			ok |= hitKeyStateAll[ DX.KEY_INPUT.Z ];
			cancel |= hitKeyStateAll[ DX.KEY_INPUT.X ];
			jump |= hitKeyStateAll[ DX.KEY_INPUT.Z ];
			dash |= hitKeyStateAll[ DX.KEY_INPUT.X ];
			attack |= hitKeyStateAll[ DX.KEY_INPUT.C ];
			start |= hitKeyStateAll[ DX.KEY_INPUT.RETURN ];
			select |= hitKeyStateAll[ DX.KEY_INPUT.ESCAPE ];

			int joypadNum = DX.GetJoypadNum();
			for( int joypadIndex = 0; joypadIndex < joypadNum; ++joypadIndex ) {
				DX.PAD_INPUT padInput = DX.GetJoypadInputState( DX.DX_INPUT.PAD1 + joypadIndex );
				left |= ( padInput & DX.PAD_INPUT.LEFT ) != 0;
				up |= ( padInput & DX.PAD_INPUT.UP ) != 0;
				right |= ( padInput & DX.PAD_INPUT.RIGHT ) != 0;
				down |= ( padInput & DX.PAD_INPUT.DOWN ) != 0;
				ok |= ( padInput & DX.PAD_INPUT.BUTTON1 ) != 0;
				cancel |= ( padInput & DX.PAD_INPUT.BUTTON2 ) != 0;
				jump |= ( padInput & DX.PAD_INPUT.BUTTON1 ) != 0;
				dash |= ( padInput & DX.PAD_INPUT.BUTTON2 ) != 0;
				attack |= ( padInput & DX.PAD_INPUT.BUTTON3 ) != 0;
			}

			ok |= start;
			cancel |= select;

			current = new Controller(
				current.Frames + 1,
				new Key( left , left == current.Left.IsHit ? current.Left.Frames + 1 : 0 ),
				new Key( up , up == current.Up.IsHit ? current.Up.Frames + 1 : 0 ),
				new Key( right , right == current.Right.IsHit ? current.Right.Frames + 1 : 0 ),
				new Key( down , down == current.Down.IsHit ? current.Down.Frames + 1 : 0 ),
				new Key( ok , ok == current.Ok.IsHit ? current.Ok.Frames + 1 : 0 ),
				new Key( cancel , cancel == current.Cancel.IsHit ? current.Cancel.Frames + 1 : 0 ),
				new Key( jump , jump == current.Jump.IsHit ? current.Jump.Frames + 1 : 0 ),
				new Key( dash , dash == current.Dash.IsHit ? current.Dash.Frames + 1 : 0 ),
				new Key( attack , attack == current.Attack.IsHit ? current.Attack.Frames + 1 : 0 ),
				new Key( start , start == current.Start.IsHit ? current.Start.Frames + 1 : 0 ),
				new Key( select , select == current.Select.IsHit ? current.Select.Frames + 1 : 0 ));
			return current;
		}

		private Controller( int frames , Key left , Key up , Key right , Key down , Key ok , Key cancel , Key jump , Key dash , Key attack , Key start , Key select ) {
			this.Frames = frames;
			this.Left = left;
			this.Up = up;
			this.Right = right;
			this.Down = down;
			this.Ok = ok;
			this.Cancel = cancel;
			this.Jump = jump;
			this.Dash = dash;
			this.Attack = attack;
			this.Start = start;
			this.Select = select;
		}

		private Controller() {
		}

		private static Controller current = new Controller();
	}
}
