using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Crosswords.Core;
using Crosswords.Models;
using Crosswords.WebHelper;
using System.Text.RegularExpressions;
using System.Windows.Threading;
using System.Threading;
using System.Collections.Specialized;
namespace Crosswords
{
public class BoardViewModel : INotifyPropertyChanged
{
#region members
string txtUser = "";
string txtClue = "";
bool isBusy = false;
HtmlParser htmlParser;
char[,] boardValues = new char[15, 15];
int size;
Dispatcher dispatcher;
Action<object, NotifyCollectionChangedEventArgs> squaresChangedCallback;
public event EventHandler HtmlLoaded;
#endregion Members
#region ctr
public BoardViewModel(Dispatcher dispatcher, int size, Action<object, NotifyCollectionChangedEventArgs> squaresChangedCallback)
{
this.dispatcher = dispatcher;
this.size = size;
this.squaresChangedCallback = squaresChangedCallback;
this.Clues = new ObservableCollection<Clue>();
squares.CollectionChanged += (s, e) =>
{
squaresChangedCallback(s, e);
};
}
#endregion ctr
#region properties
public string TxtUser
{
get
{
return txtUser;
}
set
{
txtUser = value;
NotifyPropertyChanged("TxtUser");
}
}
public string TxtClue
{
get
{
return txtClue;
}
set
{
txtClue = value;
NotifyPropertyChanged("TxtClue");
}
}
public bool IsBusy
{
get
{
return isBusy;
}
set
{
isBusy = value;
NotifyPropertyChanged("IsBusy");
}
}
ObservableNotifiableCollection<Square> squares = new ObservableNotifiableCollection<Square>();
public ObservableNotifiableCollection<Square> Squares
{
get
{
return squares;
}
set
{
squares = value;
NotifyPropertyChanged("Squares");
}
}
private ObservableCollection<Clue> clues;
public ObservableCollection<Clue> Clues
{
get
{
return clues;
}
set
{
if (value != clues)
{
clues = value;
NotifyPropertyChanged("Clues");
}
}
}
public bool IsDataLoaded
{
get;
private set;
}
#endregion properties
#region methods
public void LoadGrid()
{
TxtClue = "";
Clues.Clear();
foreach (var square in Squares)
{
square.UserLetter = "";
square.Letter = "";
square.IsSelected = false;
squaresChangedCallback(squares,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, square, square.Row * size + square.Column));
}
IsBusy = true;
htmlParser = new HtmlParser(size,
//onSuccess
(html) =>
{
IsBusy = false;
processHtmlResult();
},
//onFailure
() =>
{
IsBusy = false;
},
//onProgressChanged
(percentage) =>
{
}
);
}
private void processHtmlResult()
{
if (HtmlLoaded != null)
HtmlLoaded(this, new EventArgs());
var board = htmlParser.Parse();
SetSquares(board);
var dictWords = new Dictionary<string, string>();
AddHorizontalWordsToDict(dictWords);
AddVerticalWordsToDict(dictWords);
dispatcher.BeginInvoke(delegate
{
LoadClues(dictWords, "");
});
}
public void LoadClues(Dictionary<string, string> dictWords, string note)
{
var dictionaryHelper = new DictionaryHelper(dictWords);
dictionaryHelper.GetDictionaryEntries((key, word, definition) =>
{
var sb = new StringBuilder();
sb.AppendLine(string.Format("{0}: {1}", key, definition));
lock (clues)
{
if (note == "(plural)" && !definition.Contains("(noun)"))
{
definition = "";
}
var clue = new Clue()
{
WordId = key,
Definition = string.Format("{0} {1}", definition, note)
};
if (string.IsNullOrEmpty(definition))
{
if (word.Trim().Length > 3 &&
word.ToLower().Last() == 's' &&
string.IsNullOrEmpty(note))
{
var dictPlural = new Dictionary<string, string>();
dictPlural.Add(key, word.Substring(0, word.Length - 1));
LoadClues(dictPlural, "(plural)");
}
else
{
squares.Where(s => (s.WordId ?? "").Split(',').Contains(key))
.ToList().ForEach(s =>
{
s.UserLetter = s.Letter;
squaresChangedCallback(squares,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, s, s.Row * size + s.Column));
});
}
}
else
{
var indexToInsert = 0;
for (var index = 0; index < clues.Count(); index++)
{
if (clues[index].WordId.CompareTo(clue.WordId) > 0)
{
indexToInsert = index;
break;
}
}
Clue[] cluesAux = new Clue[clues.Count()];
clues.CopyTo(cluesAux, 0);
var sortedClues = cluesAux.ToList().OrderBy(x => x.WordId);
clues.Clear();
sortedClues.ToList().ForEach(c => clues.Add(c));
clues.Insert(indexToInsert, clue);
}
}
NotifyPropertyChanged("Clues");
});
this.IsDataLoaded = true;
}
public void SelectSquaresByPosition(double gridWidth, double gridHeight, Point swipeDownPoint, Point swipeUpPoint)
{
var factor = size / gridWidth;
var col1 = (int)(swipeDownPoint.X * factor);
var row1 = (int)(swipeDownPoint.Y * factor);
var col2 = (int)(swipeUpPoint.X * factor);
var row2 = (int)(swipeUpPoint.Y * factor);
var col = (col2 + col1) / 2;
var row = (row2 + row1) / 2;
if (col >= 0 &&
row >= 0 &&
col < size &&
row < size)
{
var wordId = squares[row * size + col].WordId;
if (wordId != null)
{
var wordId1 = "";
if (col1 == col2 && row1 != row2)
{
if (wordId != null)
{
wordId1 = wordId.Split(',')[1];
}
}
else if (col1 != col2 && row1 == row2)
{
if (wordId != null)
{
wordId1 = wordId.Split(',')[0];
}
}
SelectSquaresByWordId(wordId1);
}
}
}
public void SelectSquaresByWordId(string wordId1)
{
var isSomeSquareUnSelected =
squares
.Where(s => s.WordId.Split(',').Contains(wordId1)
&& !s.IsSelected).Any();
var isSomeEmptySquareUnSelected =
squares
.Where(s => s.WordId.Split(',').Contains(wordId1)
&& (s.UserLetter ?? "").Trim() == ""
&& !s.IsSelected).Any();
if (isSomeEmptySquareUnSelected || !isSomeSquareUnSelected)
{
squares
.ToList()
.ForEach(s =>
{
var split = s.WordId.Split(',');
s.IsSelected = split.Contains(wordId1) && (s.UserLetter ?? "").Trim() == "";
squaresChangedCallback(squares,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, s, s.Row * size + s.Column));
});
}
else
{
squares
.ToList()
.ForEach(s =>
{
var split = s.WordId.Split(',');
s.IsSelected = split.Contains(wordId1);
squaresChangedCallback(squares,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, s, s.Row * size + s.Column));
});
}
var txt = "";
if (clues.Count() > 0)
{
var selectedClue = clues.Where(c => c.WordId == wordId1);
if (selectedClue.Any())
{
var clue = selectedClue.First();
txt = clue.Definition;
}
TxtClue = txt.Trim();
}
}
public void TypeLetter(string letter)
{
var selectedSquares = this.Squares.Where(s => s.IsSelected);
if (selectedSquares.Count() > 0)
{
var square = selectedSquares.First();
if (square != null)
{
square.UserLetter = letter;
square.IsSelected = false;
squaresChangedCallback(squares,
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, square, square.Row * size + square.Column));
var isSomeSquareSelected =
squares.Where(s => s.IsSelected).Any();
if (!isSomeSquareSelected)
{
TxtClue = "";
}
}
}
}
private string AddVerticalWordsToDict(Dictionary<string, string> dictWords)
{
string line;
line = "";
for (var col = 0; col < size; col++)
{
for (var row = 0; row < size; row++)
{
if (col < size && row < size)
{
var val = boardValues[row, col];
line = string.Concat(line, val);
}
}
RegexOptions options = RegexOptions.None;
Regex regex = new Regex(@"[ ]{2,}", options);
line = regex.Replace(line, @" ")
.Trim();
var words = line.Split(' ');
for (var i = 0; i < words.Count(); i++)
{
dictWords.Add(string.Format("V{0}{1}", (char)(65 + col), i + 1), words[i]);
}
line = "";
}
return line;
}
private string AddHorizontalWordsToDict(Dictionary<string, string> dictWords)
{
var line = "";
for (var row = 0; row < size; row++)
{
for (var col = 0; col < size; col++)
{
if (col < size && row < size)
{
var val = boardValues[row, col];
line = string.Concat(line, val);
}
}
RegexOptions options = RegexOptions.None;
Regex regex = new Regex(@"[ ]{2,}", options);
line = regex.Replace(line, @" ")
.Trim();
var words = line.Split(' ');
for (var i = 0; i < words.Count(); i++)
{
dictWords.Add(string.Format("H{0}{1}", (char)(65 + row), i + 1), words[i]);
}
line = "";
}
return line;
}
private void SetSquares(string board)
{
squares.Clear();
for (var row = 0; row < 15; row++)
{
var index = 0;
var lastLetter = ' ';
for (var col = 0; col < 15; col++)
{
if (col < size && row < size)
{
var val = (char)board[row * 15 + col];
boardValues[row, col] = val;
var square = new Square();
square.Row = row;
square.Column = col;
squares.Add(square);
var text = val.ToString();
if (!string.IsNullOrEmpty(text.Trim()) && lastLetter == ' ')
{
index++;
}
lastLetter = val;
if (val != ' ')
{
square.WordId = string.Format("H{0}{1}", (char)(65 + row), index);
}
else
{
square.WordId = "";
}
square.Letter = text;
var fontSize = 28;
switch (size)
{
case 4:
fontSize = 52;
break;
case 7:
fontSize = 40;
break;
case 10:
fontSize = 28;
break;
}
}
}
}
for (var col = 0; col < 15; col++)
{
var index = 0;
var lastLetter = ' ';
for (var row = 0; row < 15; row++)
{
if (col < size && row < size)
{
var val = (char)board[row * 15 + col];
var square = this.squares[row * size + col];
var text = val.ToString();
if (!string.IsNullOrEmpty(text.Trim()) && lastLetter == ' ')
{
index++;
}
lastLetter = val;
if (val != ' ')
{
square.WordId = string.Concat(square.WordId, ",",
string.Format("V{0}{1}", (char)(65 + col), index));
}
else
{
square.WordId = "";
}
}
}
}
}
#endregion methods
#region notification
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion notification
}
}