// Decompiled with JetBrains decompiler
// Type: ZuneUI.Search
// Assembly: ZuneShell, Version=4.7.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: FC8028F3-A47B-4FB4-B35B-11D1752D8264
// Assembly location: C:\Program Files\Zune\ZuneShell.dll

using Microsoft.Iris;
using Microsoft.Zune.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Security;
using System.Text;

namespace ZuneUI
{
    public class Search : ModelItem
    {
        private string _keywords = "";
        private string[] _processedKeywords;
        private static Search _singletonInstance;
        private bool _ignoreAccented;
        private Dictionary<char, char> _accentTable;
        private Command _executeCommand;
        private Hashtable _keywordLinkTable;
        private Command _searchFocusHotkey;
        private Choice _filterList;
        private SearchResultFilterType _selectedFilter;
        private SearchResultContextType _usersContextType = SearchResultContextType.Undefined;
        private SearchHintHelper _hintHelper;
        private static List<SearchResultFilterCommand> _searchResultFilterCommandTypes;

        public static Search Instance
        {
            get
            {
                if (_singletonInstance == null)
                    _singletonInstance = new Search();
                return _singletonInstance;
            }
        }

        internal static bool HasInstance => _singletonInstance != null;

        private Search()
        {
            this._executeCommand = new Command();
            this._ignoreAccented = string.Compare(CultureInfo.CurrentCulture.TwoLetterISOLanguageName, "en", true) == 0;
            this._accentTable = new Dictionary<char, char>();
            this._accentTable.Add('À', 'A');
            this._accentTable.Add('Á', 'A');
            this._accentTable.Add('Â', 'A');
            this._accentTable.Add('Ã', 'A');
            this._accentTable.Add('Ä', 'A');
            this._accentTable.Add('Å', 'A');
            this._accentTable.Add('à', 'a');
            this._accentTable.Add('á', 'a');
            this._accentTable.Add('â', 'a');
            this._accentTable.Add('ã', 'a');
            this._accentTable.Add('ä', 'a');
            this._accentTable.Add('å', 'a');
            this._accentTable.Add('È', 'E');
            this._accentTable.Add('É', 'E');
            this._accentTable.Add('Ê', 'E');
            this._accentTable.Add('Ë', 'E');
            this._accentTable.Add('è', 'e');
            this._accentTable.Add('é', 'e');
            this._accentTable.Add('ê', 'e');
            this._accentTable.Add('ë', 'e');
            this._accentTable.Add('Ì', 'I');
            this._accentTable.Add('Í', 'I');
            this._accentTable.Add('Î', 'I');
            this._accentTable.Add('Ï', 'I');
            this._accentTable.Add('ì', 'i');
            this._accentTable.Add('í', 'i');
            this._accentTable.Add('î', 'i');
            this._accentTable.Add('ï', 'i');
            this._accentTable.Add('Ò', 'O');
            this._accentTable.Add('Ó', 'O');
            this._accentTable.Add('Ô', 'O');
            this._accentTable.Add('Õ', 'O');
            this._accentTable.Add('Ö', 'O');
            this._accentTable.Add('ò', 'o');
            this._accentTable.Add('ó', 'o');
            this._accentTable.Add('ô', 'o');
            this._accentTable.Add('õ', 'o');
            this._accentTable.Add('ö', 'o');
            this._accentTable.Add('Ù', 'U');
            this._accentTable.Add('Ú', 'U');
            this._accentTable.Add('Û', 'U');
            this._accentTable.Add('Ü', 'U');
            this._accentTable.Add('ù', 'u');
            this._accentTable.Add('ú', 'u');
            this._accentTable.Add('û', 'u');
            this._accentTable.Add('ü', 'u');
        }

        protected override void OnDispose(bool disposing)
        {
            if (disposing && this._filterList != null)
                this._filterList.ChosenChanged -= new EventHandler(this.FilterListChosenChanged);
            base.OnDispose(disposing);
        }

        public Choice FilterList
        {
            get
            {
                if (this._filterList == null)
                {
                    this._filterList = new Choice(this);
                    this._filterList.Options = new ArrayListDataSet();
                    this._filterList.ChosenChanged += new EventHandler(this.FilterListChosenChanged);
                    this.UpdateFiltersList();
                }
                this._filterList.ChosenIndex = 0;
                return this._filterList;
            }
        }

        private void FilterListChosenChanged(object sender, EventArgs args)
        {
            if (this._filterList == null)
                return;
            SearchResultFilterCommand chosenValue = (SearchResultFilterCommand)this._filterList.ChosenValue;
            if (chosenValue == null)
                return;
            this.SelectedFilterType = chosenValue.Type;
        }

        public void UpdateFiltersList()
        {
            if (this._filterList == null)
                return;
            if (_searchResultFilterCommandTypes == null)
            {
                _searchResultFilterCommandTypes = new List<SearchResultFilterCommand>();
                _searchResultFilterCommandTypes.Add(SearchResultFilter.All);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Artists);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Albums);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Tracks);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.MusicVideos);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.TVShows);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Movies);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.OtherVideo);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Podcasts);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Playlists);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Channels);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.WindowsPhoneApps);
                _searchResultFilterCommandTypes.Add(SearchResultFilter.Profile);
            }
            this._filterList.Options.Clear();
            for (int index = 0; index < _searchResultFilterCommandTypes.Count; ++index)
            {
                SearchResultFilterCommand filterCommandType = _searchResultFilterCommandTypes[index];
                if (filterCommandType.HasResults)
                    this._filterList.Options.Add(filterCommandType);
            }
        }

        public void Navigate(string command, IDictionary commandArguments)
        {
            if (string.IsNullOrEmpty(command))
                return;
            if (command.Contains("Marketplace\\"))
                SQMLog.Log(SQMDataId.SearchMarketplaceResultsCount, 1);
            else if (command.Contains("Collection\\"))
                SQMLog.Log(SQMDataId.SearchCollectionResultsCount, 1);
            ZuneShell.DefaultInstance.Execute(command, commandArguments);
        }

        public void RecordContextMenuType(SearchResultContextMenuType type) => SQMLog.LogToStream(SQMDataId.SearchContextMenuAction, (uint)type);

        public SearchResultFilterType SelectedFilterType
        {
            get => this._selectedFilter;
            set
            {
                if (this._selectedFilter == value)
                    return;
                this._selectedFilter = value;
                this.FirePropertyChanged(nameof(SelectedFilterType));
                SQMLog.Log(SQMDataId.SearchFiltersCount, 1);
                SQMLog.LogToStream(SQMDataId.SearchFiltersSelection, (uint)this._selectedFilter);
            }
        }

        public SearchResultContextType UsersContextType
        {
            get => this._usersContextType;
            set
            {
                if (this._usersContextType == value)
                    return;
                this._usersContextType = value;
                this.FirePropertyChanged(nameof(UsersContextType));
            }
        }

        public SearchHintHelper HintHelper
        {
            get
            {
                if (this._hintHelper == null)
                    this._hintHelper = new SearchHintHelper();
                return this._hintHelper;
            }
        }

        public Command SearchFocusHotkey
        {
            get
            {
                if (this._searchFocusHotkey == null)
                    this._searchFocusHotkey = new Command(this);
                return this._searchFocusHotkey;
            }
        }

        public string Keywords
        {
            get => this._keywords.Trim();
            private set
            {
                if (!(this._keywords != value) || string.IsNullOrEmpty(value))
                    return;
                this._keywords = value;
                this._processedKeywords = null;
                this.FirePropertyChanged(nameof(Keywords));
            }
        }

        public void Execute(string keywords)
        {
            this.Keywords = keywords;
            if (this._executeCommand == null)
                return;
            this._executeCommand.Invoke();
        }

        public Command Executed => this._executeCommand;

        public SearchKeywordLink KeywordLink => (SearchKeywordLink)this.KeywordLinkTable[this.Keywords.ToLower()];

        private Hashtable KeywordLinkTable
        {
            get
            {
                if (this._keywordLinkTable == null)
                {
                    this._keywordLinkTable = new Hashtable();
                    foreach (SearchKeywordLink searchKeywordLink in new SearchKeywordLink[1]
                    {
            new SearchKeywordLink(StringId.IDS_APPLICATIONS, StringId.IDS_SEARCH_MARKETPLACE_GAMES_LINK, StringId.IDS_SEARCH_MARKETPLACE_GAMES_KEYWORDS, "Marketplace\\Apps\\Home")
                    })
                    {
                        for (int index = 0; index < searchKeywordLink.Keywords.Length; ++index)
                            this._keywordLinkTable[searchKeywordLink.Keywords[index].ToLower().Trim()] = searchKeywordLink;
                    }
                }
                return this._keywordLinkTable;
            }
        }

        public bool IsValidKeyword(string keywords)
        {
            if (string.IsNullOrEmpty(keywords))
                return false;
            string str = keywords.Trim();
            return !string.IsNullOrEmpty(str) && (str.Length > 1 || this.IsValidCjkCharacter(str[0]));
        }

        private bool IsValidCjkCharacter(char c)
        {
            ushort num = c;
            return num >= 12352 && (num > 12351 && num < 12544 || num > 13311 && num < 19904 || (num > 19967 && num < 40960 || num > 44031 && num < 55216));
        }

        public string FormatResult(string keywordStyle, string item0, string item1)
        {
            List<string> list = new List<string>();
            this.AddResult(keywordStyle, list, item0);
            this.AddResult(keywordStyle, list, item1);
            return this.FormatResult(list);
        }

        public string FormatResult(string keywordStyle, string item0, string item1, string item2)
        {
            List<string> list = new List<string>();
            this.AddResult(keywordStyle, list, item0);
            this.AddResult(keywordStyle, list, item1);
            this.AddResult(keywordStyle, list, item2);
            return this.FormatResult(list);
        }

        private void AddResult(string keywordStyle, List<string> list, string item)
        {
            if (string.IsNullOrEmpty(item))
                return;
            if (keywordStyle != null)
                list.Add(this.HighlightKeywords(item, keywordStyle));
            else
                list.Add(item);
        }

        private string FormatResult(List<string> list)
        {
            switch (list.Count)
            {
                case 1:
                    return list[0];
                case 2:
                    return string.Format(Shell.LoadString(StringId.IDS_FOUND_ITEM_BUTTON1), list[0], list[1]);
                case 3:
                    return string.Format(Shell.LoadString(StringId.IDS_FOUND_ITEM_BUTTON2), list[0], list[1], list[2]);
                default:
                    return "";
            }
        }

        public string HighlightKeywords(string target, string styleName)
        {
            int startIndex = 0;
            if (target == null)
                return "";
            StringBuilder stringBuilder = new StringBuilder(target.Length + styleName.Length * 4 + 10);
            List<IndexRange> keywords = this.FindKeywords(this.ProcessKeywords(), target);
            for (int index = 0; index < keywords.Count; ++index)
            {
                IndexRange indexRange = keywords[index];
                if (indexRange.indexStart > startIndex)
                {
                    string str = target.Substring(startIndex, indexRange.indexStart - startIndex);
                    stringBuilder.Append(SecurityElement.Escape(str));
                }
                string str1 = target.Substring(indexRange.indexStart, indexRange.indexEnd - indexRange.indexStart);
                stringBuilder.Append(string.Format("<{0}>{1}</{0}>", styleName, SecurityElement.Escape(str1)));
                startIndex = indexRange.indexEnd;
            }
            if (startIndex < target.Length)
            {
                string str = target.Substring(startIndex);
                stringBuilder.Append(SecurityElement.Escape(str));
            }
            return stringBuilder.ToString();
        }

        private List<IndexRange> FindKeywords(string[] keywords, string text)
        {
            StringBuilder stringBuilder = new StringBuilder(text.Length);
            for (int index = 0; index < text.Length; ++index)
                stringBuilder.Append(this.MapAccentedChar(text[index]));
            string str = stringBuilder.ToString();
            List<IndexRange> rangeList = new List<IndexRange>();
            foreach (string keyword in keywords)
            {
                int startIndex = 0;
                while (true)
                {
                    int num = str.IndexOf(keyword, startIndex, StringComparison.OrdinalIgnoreCase);
                    if (num >= 0)
                    {
                        char c1 = num > 0 ? str[num - 1] : ' ';
                        char c2 = num + keyword.Length < str.Length ? str[num + keyword.Length] : ' ';
                        if (!char.IsLetterOrDigit(c1) && (keyword.Length >= 2 || !char.IsLetterOrDigit(c2)))
                        {
                            IndexRange keyRange;
                            keyRange.indexStart = num;
                            keyRange.indexEnd = num + keyword.Length;
                            this.AddRange(keyRange, rangeList);
                        }
                        startIndex = num + keyword.Length;
                    }
                    else
                        break;
                }
            }
            this.CollapseRanges(rangeList);
            return rangeList;
        }

        private void CollapseRanges(List<IndexRange> rangeList)
        {
            for (int index1 = 0; index1 < rangeList.Count; ++index1)
            {
                int index2 = index1 + 1;
                while (index2 < rangeList.Count)
                {
                    IndexRange range1 = rangeList[index1];
                    IndexRange range2 = rangeList[index2];
                    if (range1.indexEnd > range2.indexStart)
                    {
                        if (range1.indexEnd >= range2.indexEnd)
                        {
                            rangeList.RemoveAt(index2);
                        }
                        else
                        {
                            range1.indexEnd = range2.indexEnd;
                            rangeList[index1] = range1;
                            rangeList.RemoveAt(index2);
                        }
                    }
                    else
                        break;
                }
            }
        }

        private void AddRange(IndexRange keyRange, List<IndexRange> rangeList)
        {
            int index;
            for (index = 0; index < rangeList.Count; ++index)
            {
                IndexRange range = rangeList[index];
                if (keyRange.indexStart <= range.indexStart)
                    break;
            }
            rangeList.Insert(index, keyRange);
        }

        private string[] ProcessKeywords()
        {
            if (this._processedKeywords == null)
            {
                StringBuilder stringBuilder = new StringBuilder(this._keywords.Length);
                bool flag = false;
                for (int index = 0; index < this._keywords.Length; ++index)
                {
                    char keyword = this._keywords[index];
                    switch (keyword)
                    {
                        case '\t':
                        case '\n':
                        case '\r':
                        case '!':
                        case '"':
                        case '%':
                        case '&':
                        case '(':
                        case ')':
                        case '+':
                        case '-':
                        case ';':
                        case '<':
                        case '>':
                        case '{':
                        case '}':
                            stringBuilder.Append(' ');
                            flag = true;
                            break;
                        case '\'':
                            char c1 = index > 0 ? this._keywords[index - 1] : ' ';
                            char c2 = index + 1 < this._keywords.Length ? this._keywords[index + 1] : ' ';
                            if (char.IsLetterOrDigit(c1) && char.IsLetterOrDigit(c2))
                            {
                                stringBuilder.Append(keyword);
                                break;
                            }
                            stringBuilder.Append(' ');
                            flag = true;
                            break;
                        default:
                            stringBuilder.Append(this.MapAccentedChar(keyword));
                            break;
                    }
                }
                this._processedKeywords = stringBuilder.ToString().Split(new char[1]
                {
          ' '
                }, StringSplitOptions.RemoveEmptyEntries);
                if (flag)
                {
                    Array.Resize(ref this._processedKeywords, this._processedKeywords.Length + 1);
                    this._processedKeywords[this._processedKeywords.Length - 1] = this._keywords;
                }
            }
            return this._processedKeywords;
        }

        private char MapAccentedChar(char original)
        {
            char key = original;
            char ch;
            if (this._ignoreAccented && this._accentTable.TryGetValue(key, out ch))
                key = ch;
            return key;
        }

        private struct IndexRange
        {
            public int indexStart;
            public int indexEnd;
        }
    }
}
