using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class LetterBoard : FunObject {
	
	List<Letter> _letters = new List<Letter>();
	List<Letter> _oldLetters = new List<Letter>();
	List<Letter> _sortedLetters = new List<Letter>();
	
	GameObject _letterPrefab;
	Sinus _noiser;
	float _gainer = 0.0f;
	
	List<Word> _words = new List<Word>();
	
	void Awake () {
		_letterPrefab = Resources.Load("Prefabs/Letter") as GameObject;
		
		InitializeBoard();
		//CheckSpelling();
		_noiser = Camera.main.GetComponent<Sinus>();
		_noiser.gain = 0.0f;
		
		HSController.shared.ScoreDelegate = this;
	}
	
	public void Restart()
	{
		Globals.Submitting = false;
		Globals.Menu = true;
		Globals.Score = 0;
		Globals.LastCombo = 0;
		Globals.AcceptMode = false;
		Globals.Clicks = 0;
		Globals.FallenIn = false;
	
		HSController.shared.GetScores();
		foreach(Letter l in _letters)
		{
			Destroy (l.gameObject);
		}
		_letters.Clear();
		InitializeBoard();
	}
	
	public void DonePostingScore()
	{
		Restart ();
	}
	
	void Start() {
		HSController.shared.GetScores();	
	}
	
	void InitializeBoard()
	{
		int numLerped = 0;
		int idx = 0;
		for(int ypos = Globals.BoardHeight - 1; ypos >= 0; ypos--)
		{
			for(int xpos = 0; xpos < Globals.BoardWidth; xpos++)
			{
				Vector3 start = new Vector3(x + (xpos * Globals.TileSize), y + (ypos * Globals.TileSize), 0);
				GameObject letterObj = Instantiate(_letterPrefab, start + new Vector3((Globals.BoardWidth * Globals.TileSize), 0.0f, 0.0f) ,Quaternion.identity) as GameObject;
				Letter l = letterObj.GetComponent<Letter>();
				_letters.Add(l);
				letterObj.transform.parent = transform;
				l.GenerateCloneLetter();
				
				if(Globals.Menu)
				{
					l.SetCharacter(' ');
					if(idx == 62)
						l.SetCharacter('S');
					if(idx == 63)
						l.SetCharacter('P');
					if(idx == 64)
						l.SetCharacter('E');				
					if(idx == 65)
						l.SetCharacter('L');
					if(idx == 66)
						l.SetCharacter('L');	
					if(idx == 67)
						l.SetCharacter('B');
					if(idx == 68)
						l.SetCharacter('O');
					if(idx == 69)
						l.SetCharacter('X');
				}
				
				l.DoLerp = true;
				l.LerpDest = new Vector3((xpos * Globals.TileSize), (ypos * Globals.TileSize), 0);
				l.Delay = (float)numLerped;
				numLerped += 1;
				idx += 1;
			}
			numLerped = 0;
		}	
		_animating = true;
	}
	
	void IntersectWords( Word word, List<Word> words )
	{
		words.Add(word);
		Vector2 pos = GetPosition(word.letter);
		for(int i = 0; i < word.length; i++)
		{
			Letter l = GetLetter((int)(word.vertical ? pos.x : pos.x + i), (int)(word.vertical ? pos.y - i : pos.y));
			if(l != null)
			{
				if(l.Words.Count > 1)
				{
					foreach(Word w in l.Words)
					{
						if(w != word && words.Contains(w) == false)
						{
							IntersectWords(w, words);	
						}
					}
				}
			}
		}
	}
	
	void ClearSpelling()
	{
		for(int i = 0; i < Globals.BoardWidth * Globals.BoardHeight; i++)
		{
			_letters[i].MakesWord = false;
			_letters[i].InHorizontalWord = false;
			_letters[i].InVerticalWord = false;
			_letters[i].Words.Clear();
		}
	}
	
	Color GetColor(Letter l, bool vert)
	{
		foreach(Word w in _words)
		{
			if(w.letter == l && w.vertical == vert)
				return w.color;
		}

		return Color.black;
	}
	
	Word GetWord(Letter l, bool vert)
	{
		foreach(Word w in _words)
		{
			if(w.letter == l && w.vertical == vert)
				return w;
		}

		return null;
	}
	
	void CheckSpelling()
	{
		ClearSpelling();
		_sortedLetters.Clear();
		
		for(int ypos = 0; ypos < Globals.BoardHeight; ypos++)
		{
			for(int xpos = 0; xpos < Globals.BoardWidth; xpos++)
			{
				_sortedLetters.Add(GetLetterSlow(xpos, ypos));
			}
		}
		
		Letter l;
		for(int ypos = Globals.BoardHeight - 1; ypos >= 0; ypos--)
		{
			for(int xpos = 0; xpos < Globals.BoardWidth; xpos++)
			{
				l = GetLetter(xpos, ypos);
				bool marked = false;
				int length = Globals.BoardWidth - xpos;
				for(int i = 0; i < length; i++)
				{
					if(length - i <= 3)
						break;
				
					string word = GetLetterWord(xpos, ypos, length - i, false);
					if(WordListManager.shared.ContainsWord(word))
					{
						Word w = GetWord (l, false);
						if(w == null)
						{
							w = new Word();
							w.letter = l;
							w.color = new Color((0.6f + (Random.value * 0.4f)) - 0.2f, (0.6f + (Random.value * 0.4f)) - 0.2f, (0.6f + (Random.value * 0.4f)) - 0.2f, 1.0f);;
							w.vertical = false;
							_words.Add(w);
						}
						w.length = word.Length;
						MarkWord (xpos, ypos, length - i, w);
						marked = true;
						break;	
					}						
				}			
				length = ypos + 1;
				for(int i = 0; i < length; i++)
				{
					if(length - i <= 3)
						break;
					
					string word = GetLetterWord(xpos, ypos, length - i, true);
					if(WordListManager.shared.ContainsWord(word))
					{
						Word w = GetWord (l, true);
						if(w == null)
						{
							w = new Word();
							w.letter = l;		
							w.color = new Color((0.6f + (Random.value * 0.4f)) - 0.2f, (0.6f + (Random.value * 0.4f)) - 0.2f, (0.6f + (Random.value * 0.4f)) - 0.2f, 1.0f);;
							w.vertical = true;
							_words.Add(w);
						}
						w.length = word.Length;
						MarkWord (xpos, ypos, length - i, w);
						marked = true;
						break;	
					}						
				}
				
				if(!marked)
				{
					_words.RemoveAll( item => item.letter == l );
				}
			}
		}
	}
	
	string GetLetterWord(int xpos, int ypos, int length, bool vertical)
	{
		if(length <= 0)
			return "";
		
		string word = "";
		Letter l = GetLetter(xpos, ypos);
		
		if(!vertical && l.InHorizontalWord)
			return "";
		if(vertical && l.InVerticalWord)
			return "";
		
		word += l.Character;
		if(vertical == false)
		{
			if(xpos < Globals.BoardWidth - 1)
				return word + GetLetterWord(xpos + 1, ypos, length - 1, vertical);
		}
		else
		{
			if(ypos > 0)
				return word + GetLetterWord(xpos, ypos - 1, length - 1, vertical);
		}
		return word;
	}

	void MarkWord(int xpos, int ypos, int length, Word w)
	{
		if(length <= 0)
			return;
		
		Letter l = GetLetter(xpos, ypos);
		l.MakesWord = true;
		if(w.vertical)
			l.InVerticalWord = true;
		else
			l.InHorizontalWord = true;
		
		l.Words.Add(w);
		
		if(w.vertical == false)
		{
			if(xpos < Globals.BoardWidth - 1)
				MarkWord(xpos + 1, ypos, length - 1, w);
		}
		else
		{
			if(ypos > 0)
				MarkWord(xpos, ypos - 1, length - 1, w);
		}
	}
	
	Vector2 GetPosition(Letter l)
	{
		Letter letr;
		for(int ypos = Globals.BoardHeight - 1; ypos >= 0; ypos--)
		{
			for(int xpos = 0; xpos < Globals.BoardWidth; xpos++)
			{
				letr = GetLetter(xpos, ypos);
				if(letr == l)
					return new Vector2(xpos, ypos);
			}
		}
		return Vector2.zero;
	}

	Letter GetLetterSlow(int xpos, int ypos)
	{
		for(int i = 0; i < _letters.Count; i++)
		{
			int xer = (int)Mathf.Round(_letters[i].lx / Globals.TileSize);
			int yer = (int)Mathf.Round(_letters[i].ly / Globals.TileSize);	
			if(xer == xpos && yer == ypos)
				return _letters[i];
		}
		return null;	
	}
	
	Letter GetLetter(int xpos, int ypos)
	{
		return _sortedLetters[xpos + (ypos * Globals.BoardWidth)];
	}
	
	List<Letter> GetAdjacentLetters(Letter l, bool vertical)
	{
		Vector2 pos = GetPosition (l);
		List<Letter> list = new List<Letter>();
		if(vertical == false)
		{
			for(int xpos = 0; xpos < Globals.BoardWidth; xpos++)
			{
				Letter letr = GetLetter(xpos, (int)pos.y);
				if(letr != l)
					list.Add (letr);
			}
		}
		else
		{
			for(int ypos = 0; ypos < Globals.BoardHeight; ypos++)
			{
				Letter letr = GetLetter((int)pos.x, ypos);
				if(letr != l)
					list.Add (letr);
			}	
		}
		return list;
	}
	
	void HoverLetters(Word word)
	{
		Vector2 pos = GetPosition(word.letter);
		for(int i = 0; i < word.length; i++)
		{
			Letter l = GetLetter((int)(word.vertical ? pos.x : pos.x + i), (int)(word.vertical ? pos.y - i : pos.y));
			if(l != null)
				l.Hover = 1.0f;
		}		
	}
	
	List<Letter> GetWordLetters(Word word)
	{
		List<Letter> letters = new List<Letter>();
		Vector2 pos = GetPosition(word.letter);
		for(int i = 0; i < word.length; i++)
		{
			Letter l = GetLetter((int)(word.vertical ? pos.x : pos.x + i), (int)(word.vertical ? pos.y - i : pos.y));
			if(l != null)
				letters.Add(l);
		}		
		return letters;
	}
	
	int _wordCombo = 0;
	void KillWord(Word w)
	{
		List<Letter> letters = GetWordLetters(w);
		int num = letters.Count;
		foreach(Letter l in letters)
		{
			if(l.Character == 'Q' || l.Character == 'X' || l.Character == 'Z')
				num += 1;
			
			l.Words.Remove(w);
			if(l.Words.Count == 0)
			{
				_letters.Remove(l);
				int index = _sortedLetters.IndexOf(l);
				_sortedLetters[index] = null;
				Destroy (l.gameObject);	
			}
		}
				
		int val = ((int)(Mathf.Pow(2.0f, num) * _wordCombo)) * 2;
		Globals.LastCombo += val;
		Globals.Score += val;
	
		_words.Remove(w);
	}
	
	Letter NextLetterLeft(int xpos, int ypos)
	{
		Letter l = null;
		do
		{
			if(xpos <= 0)
				return null;
			
			xpos -= 1;
			l = _sortedLetters[xpos + (ypos * Globals.BoardWidth)];
		}while(l == null);
		return l;
	}
	
	void DropWords()
	{
		for(int ypos = 0; ypos < Globals.BoardHeight; ypos++)
		{
			for(int xpos = 0; xpos < Globals.BoardWidth; xpos++)
			{
				int needed = 0;
				int numLerped = 0;
				int leftX = xpos;
				Letter l = _sortedLetters[xpos + (ypos * Globals.BoardWidth)];
				if(l == null)
				{
					needed += 1;
					while(true)
					{
						xpos += 1;
						if(xpos == Globals.BoardWidth)
							break;
						
						l = _sortedLetters[xpos + (ypos * Globals.BoardWidth)];
						if(l == null)
							needed += 1;
						else
						{
							l.DoLerp = true;
							l.LerpDest = l.lposition;
							l.LerpDest.x = leftX * Globals.TileSize;
							l.Delay = (float)numLerped;
							numLerped += 1;
							leftX += 1;
						}
					}
					for(int i = 0; i < needed; i++)
					{
						GameObject letterObj = Instantiate(_letterPrefab, new Vector3(x + ((Globals.BoardWidth * Globals.TileSize) + (i * Globals.TileSize)), y + (ypos * Globals.TileSize), 0), Quaternion.identity) as GameObject;
						Letter n = letterObj.GetComponent<Letter>();
						_letters.Add(n);
						letterObj.transform.parent = transform;	
						n.GenerateCloneLetter();
						n.DoLerp = true;
						n.LerpDest = n.lposition;
						n.LerpDest.x = leftX * Globals.TileSize;
						n.Delay = (float)numLerped;
						numLerped += 1;
						leftX += 1;
					}
					break;
				}
			}	
		}
	}

	
	Letter _dragLetter;
	bool _dragLock = false;
	bool _dragVert = false;
	bool _dragging = false;
	bool _killDrag = false;
	bool _animating = false;
	Vector2 _startMouse = Vector2.zero;
	Vector2 _dragOff = new Vector2(0.0f, 0.0f);
	List<Letter> _adjacent = new List<Letter>();
	void Update () 
	{
		if(Globals.Submitting)
			return;
		
		_wordCombo = 0;
		Vector3 prev = Vector3.zero;
		if(_dragLetter != null)
			prev = _dragLetter.position;
		
		Vector3 mouse = Camera.main.ScreenToWorldPoint(Input.mousePosition);
		bool hadLerp = false;
		for(int i = 0; i < _letters.Count; i++)
		{
			if(_letters[i].DoLerp)
				hadLerp = true;
			
			if(mouse.x > _letters[i].x - (Globals.TileSize / 2.0f) &&
			   mouse.x < _letters[i].x + (Globals.TileSize / 2.0f) &&
			   mouse.y > _letters[i].y - (Globals.TileSize / 2.0f) &&
			   mouse.y < _letters[i].y + (Globals.TileSize / 2.0f) && _animating == false)
			{
				if(_dragging == false && _letters[i].Words.Count > 0 && _dragLock == false)
				{
					List<Word> words = new List<Word>();
					IntersectWords( _letters[i].Words[0], words );
					foreach(Word w in words)
					{
						HoverLetters(w);
					}
				}
				
				if(Input.GetMouseButton(0) && _dragLetter == null)
				{
					_dragLetter = _letters[i];
					_startMouse = new Vector2(mouse.x, mouse.y);
				}
				if(Input.GetMouseButton(0) == false)
				{		
					if(_dragging)
						_killDrag = true;
					else
					{
						if(_dragLetter)
						{
							bool skip = false;
							if(_dragLetter.Words.Count > 0)
							{
								if(Globals.Menu)
								{
									foreach(Letter l in _letters)
									{
										l.Fade = true;	
										_oldLetters.Add(l);
									}
									Globals.Menu = false;
									_dragging = false;
									_letters.Clear();
									_sortedLetters.Clear();
									InitializeBoard();
									Globals.FallenIn = false;
									skip = true;
									_dragLetter = null;
									return;
								}
								else
								{					
									List<Word> words = new List<Word>();
									IntersectWords(_dragLetter.Words[0], words);
									_wordCombo = words.Count;
									
									Globals.Clicks += 1;
									
									Vector3 average = new Vector3(0.0f, 0.0f, 0.0f);
									int letters = 0;
									foreach(Word w in words)
									{
										List<Letter> lettars = GetWordLetters(w);
										foreach(Letter l in lettars)
										{
											letters += 1;
											average += l.position;
										}
										KillWord(w);
									}
									Globals.ComboPos = average / letters;
									_wordCombo = 0;
									DropWords();
								}
							}
							if(skip == false)
							{
								_dragLetter = null;
								_animating = true;
								hadLerp = true;
							}
							break;
						}
					}
				}
			}
		}
	
		if(_oldLetters.Count > 0)
		{
			if(_oldLetters[0].Faded)
			{
				foreach(Letter l in _oldLetters)
				{
					Destroy (l.gameObject);
				}
				_oldLetters.Clear();	
			}
		}
		
		if(_animating && hadLerp == false)
		{
			if(Globals.Menu)
				Globals.FallenIn = true;
			
			_animating = false;
			CheckSpelling();	
		}
		
		/*if(Globals.Menu)
		{
			if(_letters[0].Faded == true)
			{
				Globals.Menu = false;
				foreach(Letter l in _oldLetters)
				{
					Destroy (l.gameObject);
				}
				_letters.Clear();
				InitializeBoard();
			}
		}*/
		
		if(_gainer > 0.0f)
			_gainer = 0.0f;
		
		if(_killDrag)
		{
			Vector3 reqPos = new Vector3( Mathf.Round(_dragLetter.lx / Globals.TileSize) * Globals.TileSize,
										  Mathf.Round(_dragLetter.ly / Globals.TileSize) * Globals.TileSize,
										  _dragLetter.lz);
			_dragLetter.lposition = Vector3.Lerp(_dragLetter.lposition, reqPos, Time.deltaTime * 10.0f);
			Vector3 dif = _dragLetter.lposition - reqPos;
			if(dif.magnitude < 1)
			{
				_dragLetter.lposition = reqPos;	
				foreach(Letter l in _adjacent)
				{
					l.UpdateDrag();
					l.FinishDrag(this);
					l.MovingLocked = false;
				}
				_adjacent.Clear();
				_dragLetter.MovingLocked = false;
				_dragLetter = null;
				_dragging = false;	
				_killDrag = false;
				_dragLock = false;
				CheckSpelling();
			}
		}
		else if(_dragLetter != null)
		{
			if(_dragging == false && Globals.Menu == false)
			{
				if(Mathf.Abs(_startMouse.x - mouse.x) > 3)
				{
					_dragVert = false;
					_dragging = true;
					Globals.DragVertical = false;
					_dragOff = _startMouse - new Vector2(mouse.x, mouse.y);
				}
				if(Mathf.Abs(_startMouse.y - mouse.y) > 3)
				{
					_dragVert = true;
					_dragging = true;
					Globals.DragVertical = true;
					_dragOff =  _startMouse - new Vector2(mouse.x, mouse.y);
				}
				if(_dragging == true)
				{
					_adjacent = GetAdjacentLetters(_dragLetter, _dragVert);
					foreach(Letter l in _adjacent)
					{
						l.transform.parent = _dragLetter.transform;	
						l.Dragging = true;
					}
					
					
					bool locked = _dragLetter.Locked;
					if(locked == false)
					{
						foreach(Letter l in _adjacent)
						{
							if(l.Locked)
							{
								locked = true;
								break;
							}
						}
					}
					
					foreach(Letter l in _adjacent)
					{
						l.MovingLocked = locked;
					}
					_dragLetter.MovingLocked = locked;
					_dragLock = locked;
					
					if(!locked)
						ClearSpelling();
				}
			}
			else
			{				
				if(_dragLock == false && Globals.Menu == false)
				{
					if(_dragVert)
					{
						_dragLetter.y = mouse.y + _dragOff.y;
						if(_dragLetter.ly < 0)
							_dragLetter.ly = 0;
						if(_dragLetter.ly > (Globals.BoardHeight - 1) * Globals.TileSize)
							_dragLetter.ly = (Globals.BoardHeight - 1) * Globals.TileSize;
					}
					else
					{
						_dragLetter.x = mouse.x + _dragOff.x;
						if(_dragLetter.lx < 0)
							_dragLetter.lx = 0;
						if(_dragLetter.lx > (Globals.BoardWidth - 1) * Globals.TileSize)
							_dragLetter.lx = (Globals.BoardWidth - 1) * Globals.TileSize;
					}
				}
			}
		}
		
		if(_dragLetter)
		{
			float dif = Mathf.Abs(_dragLetter.x - prev.x) + Mathf.Abs(_dragLetter.y - prev.y);
			_gainer += dif;
		}
			
		if(_gainer > 1.0f)
			_gainer = 1.0f;	
		_noiser.gain = (double)Mathf.Lerp((float)_noiser.gain, _gainer * 0.003f, Time.deltaTime * 30.0f);
			
		
		/*_letter.transform.position = new Vector3(mouseWorldPosition.x, mouseWorldPosition.y, _letter.transform.position.z);
		
		if(Input.GetMouseButtonDown(0))
		{
			_letter.transform.localScale *= 1.1f;	
		}*/
	}
	
	void OnDestroy() {
		/*foreach(Letter l in _letters)
		{
			Destroy (l.gameObject);	
		}*/
	}
}
