using System.Collections.Generic;
using Microsoft.Xna.Framework;
using System;

namespace XELF.Sphynx {

	enum BodyKind {
		None,
		Actor,
		Puff,
		ButtonInner,
		ButtonOuter,
		Key,
		Lock,
		StartWay,
		CheckWay,
		GoalWay,
		Emitter,
		Slider,

		Wall,

		Head,
		Neck,
		Chest,
		Waist,
		Hip,
		UArmL,
		UArmR,
		LArmL,
		LArmR,
		HandL,
		HandR,
		ULegL,
		ULegR,
		LLegL,
		LLegR,
		FootL,
		FootR,
	}

	class GimmickBody : Body {
		public GimmickBody(World world, ClosedShape shape,
			float r0, float r1, float r2, Vector2 position, float rotation, Vector2 scale)
			: base(world, shape, 1) {
			Position = position;
			Rotation = rotation;
		}
		protected GimmickBody()
			: base() {
		}
		public new GimmickBody Clone() {
			var value = new GimmickBody();
			//var value = new GimmickBody(World, Shape.Clone(), 1, 1, 1, Vector2.Zero, 0, Vector2.One);
			CopyTo(value);
			return value;
		}
		bool enabled;
		public virtual bool Registered {
			get { return enabled; }
			set {
				enabled = value;
				if (enabled) {
					World.AddBody(this);
					World._.Add(Geometry._);
				} else {
					World.RemoveBody(this);
					World._.Remove(Geometry._);
				}
			}
		}
		public override string ToString() {
			return string.Format("GimmickBody{{{0}}}", Tag);
		}
		/*
		public GimmickBody(World w, ClosedShape s, float massPerPoint,
			float edgeSpringK, float edgeSpringDamp, Vector2 pos, float angle, Vector2 scale)
			: base(w, s, massPerPoint, 1, 400, 10, edgeSpringK, edgeSpringDamp, pos, angle, scale, false) {
			Shape = s;
		}
		*/

		/*
		public override void accumulateExternalForces() {
			base.accumulateExternalForces();

			// gravity!
			for (int i = 0; i < mPointMasses.Count; i++) {
				mPointMasses[i].Force += new Vector2(0f, -9.8f * mPointMasses[i].Mass);

			}
			if (dragging) {
				this.IsKinematic = false;
				for (int i = 0; i < mPointMasses.Count; i++) {
					mPointMasses[i].Velocity = Vector2.Zero;
					mPointMasses[i].Force = dragVelocity * mPointMasses[i].Mass;
				}
				dragging = false;
			}
		}
		 * */
	}

	partial class BodyFactory {
		public readonly World World;

		public BodyFactory(Factories factories, World world) {
			World = world;
		}
		public GimmickBody Create(BodyKind Kind, Vector2 position, object tag) {
			GimmickBody body = null;
			switch (Kind) {
			case BodyKind.Actor:
				body = CreateActor(World, position);
				break;
			case BodyKind.Puff: body = CreatePuff(World, position); break;
			case BodyKind.StartWay:
				body = CreateWay(World, position);
				break;
			case BodyKind.CheckWay:
				body = CreateWay(World, position);
				break;
			case BodyKind.GoalWay:
				body = CreateWay(World, position);
				break;
			case BodyKind.Lock:
				body = CreateLock(World, position);
				break;
			case BodyKind.Key:
				body = CreateKey(World, position);
				break;
			case BodyKind.ButtonInner:
				body = CreateButtonInner(World, position);
				break;
			case BodyKind.ButtonOuter:
				body = CreateButtonOuter(World, position);
				break;
			case BodyKind.Emitter:
				body = CreateKey(World, position);
				break;
			case BodyKind.Slider:
				body = CreateSlider(World, position);
				break;
			case BodyKind.Wall: body = CreateWall(World, position); break;
			case BodyKind.Head:
			case BodyKind.Neck:
			case BodyKind.Chest:
			case BodyKind.Waist:
			case BodyKind.Hip:
			case BodyKind.UArmL:
			case BodyKind.UArmR:
			case BodyKind.LArmL:
			case BodyKind.LArmR:
			case BodyKind.HandL:
			case BodyKind.HandR:
			case BodyKind.ULegL:
			case BodyKind.ULegR:
			case BodyKind.LLegL:
			case BodyKind.LLegR:
			case BodyKind.FootL:
			case BodyKind.FootR:
				body = CreateDollPart(World, position, Kind);
				break;
			}
			body.Tag = tag;
			return body;
		}
	}

	partial class BodyFactory {
		private static GimmickBody CreateWay(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
					new Vector2(-1, +1), new Vector2(+1, +1), new Vector2(+1, -1), new Vector2(-1, -1),
				});
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}

	partial class BodyFactory {
		private static GimmickBody CreateLock(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
					new Vector2(-2, 2), new Vector2(2, 2), new Vector2(2, -2), new Vector2(-2, -2),
				});
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}
	partial class BodyFactory {
		private static GimmickBody CreateActor(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
					new Vector2(-2, 2), new Vector2(2, 2), new Vector2(2, -2), new Vector2(-2, -2),
				});
			shape.Subdivide(1);
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}
	partial class BodyFactory {
		private static GimmickBody CreatePuff(World world, Vector2 position) {

			int corners = 8;
			float radius = 1;
			List<Vector2> points = new List<Vector2>(corners);

			for (int i = 0; i < corners; i++) {
				Vector2 point = new Vector2();
				double a = i * ((Math.PI * 2) / corners);
				point.X = (float)Math.Sin(a) * radius;
				point.Y = (float)Math.Cos(a) * radius;
				points.Add(point);
			}

			ClosedShape shape = new ClosedShape(points);

			//shape.SubDivideEdges(1);
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}
	partial class BodyFactory {
		private static GimmickBody CreateKey(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
					new Vector2(-2, 2), new Vector2(2, 2), new Vector2(2, -2), new Vector2(-2, -2),
				});
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}
	partial class BodyFactory {
		private static GimmickBody CreateButtonInner(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
					new Vector2(-1, 0.5f), new Vector2(1, 0.5f), new Vector2(1, 0), new Vector2(-1, 0),
				});
			shape.SubDivideEdges(0.25f);
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}
	partial class BodyFactory {
		private static GimmickBody CreateButtonOuter(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
				new Vector2(-2, -1), new Vector2(-1,-1),
				new Vector2(-1, -1.5f), new Vector2(1, -1.5f),
				new Vector2(1,-1), new Vector2(2, -1),
				new Vector2(2, -2), new Vector2(-2, -2),
			});
			shape.SubDivideEdges(0.5f);
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}

	partial class BodyFactory {
		private static GimmickBody CreateSlider(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
				new Vector2(-0.5f, +0.5f), new Vector2(+0.5f, +0.5f),
				new Vector2(+0.5f, -0.5f), new Vector2(-0.5f, -0.5f),
			});
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}

	partial class BodyFactory {
		private static GimmickBody CreateWall(World world, Vector2 position) {
			ClosedShape shape = new ClosedShape(new List<Vector2>() {
				new Vector2(-1.0f, +1.0f), new Vector2(+1.0f, +1.0f),
				new Vector2(+1.0f, -1.0f), new Vector2(-1.0f, -1.0f),
			});
			shape.SubDivideEdges(1.0f);
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			return body;
		}
	}

	partial class BodyFactory {
		private static GimmickBody CreateDollPart(World world, Vector2 position, BodyKind kind) {
			var part = DollSettings.Parts[(int)(kind - BodyKind.Head)];
			ClosedShape shape = new ClosedShape(new List<Vector2>(part.Shape));
			var body = new GimmickBody(world, shape, 1, 1, 1, position, 0, Vector2.One);
			body.Mass = part.Mass;
			return body;
		}
	}

}
