using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _9_ElSpirale {
	public class Spiral {

		public char[,] Visualization;

		public Spiral(int count, char primeChar, char nonPrimeChar, char emptyChar) {
			var primeCount = 0;

			var direction = 0;
			var directions = new (int x, int y)[] {
				(1, 0), (0, 1), (-1, 0), (0, -1)
			};

			var value = 1;
			var numbers = new List<Position>();
			var x = 0;
			var y = 0;

			numbers.Add(
					new Position(x++, y, value++)
				);

			var highestX = 0;
			var lowestX = 0;
			var highestY = 0;
			var lowestY = 0;

			while (primeCount < count) {
				var newPos = new Position(x, y, value++);

				numbers.Add(newPos);
				var newDirection = (direction + 1) % 4;

				var nextPosition = NewPosition((newPos.X, newPos.Y), directions[newDirection]);

				var first = numbers.OrderByDescending(x => x.Value).FirstOrDefault(x => (x.X == nextPosition.x) && (x.Y == nextPosition.y));

				if (first == null)
					direction = newDirection;

				if (x > highestX)
					highestX = x;
				if (x < lowestX)
					lowestX = x;

				if (y > highestY)
					highestY = y;
				if (y < lowestY)
					lowestY = y;


				x += directions[direction].x;
				y += directions[direction].y;

				if (newPos.IsPrime)
					primeCount++;
			}

			var width = highestX - lowestX + 1;
			var height = highestY - lowestY + 1;

			Visualization = new char[width, height];

			for (y = 0; y < height; y++) {
				var yPos = highestY - y;
				for (x = 0; x < width; x++) {
					var xPos = x + lowestX;

					var first = numbers.FirstOrDefault(x => x.X == xPos && x.Y == yPos);

					if (first == null) Visualization[x, y] = emptyChar;
					else if (first.IsPrime) Visualization[x, y] = primeChar;
					else Visualization[x, y] = nonPrimeChar;
				}
			}

		}

		(int x, int y) NewPosition((int x, int y) current, (int x, int y) move) {
			return (current.x + move.x, current.y + move.y);
		}

		public override string ToString() {
			var ret = "";

			for (var y = 0; y < Visualization.GetLength(1); y++) {
				for (var x = 0; x < Visualization.GetLength(0); x++) {
					ret += Visualization[x, y];
				}
				ret += '\n';
			}

			return ret;
		}
	}

	internal class Position {
		public readonly int X;
		public readonly int Y;
		public readonly int Value;
		public readonly bool IsPrime;

		public Position(int x, int y, int value) {
			X = x;
			Y = y;
			Value = value;

			IsPrime = true;

			if (Value == 1) {
				IsPrime = false;
			} else if (Value > 2) {
				var half = (int)(value * 0.5);

				for (var i = 2; i <= half; i++) {
					if (Value % i == 0) {
						IsPrime = false;
						break;
					}
				}
			}
		}
	}
}
