// Decompiled with JetBrains decompiler
// Type: ZuneXml.XmlDataProviderQuery
// 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.Configuration;
using Microsoft.Zune.PerfTrace;
using Microsoft.Zune.Service;
using Microsoft.Zune.Shell;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Xml;

namespace ZuneXml
{
    public class XmlDataProviderQuery : DataProviderQuery
    {
        protected EPassportPolicyId _passportTicketType;
        protected HttpRequestCachePolicy _cachePolicy;
        private string _lastUri;
        internal int _requestGeneration;
        protected bool _keepAlive;
        protected bool _ignoreNamespacePrefix;
        protected bool _ignoreDuplicateGenerationRequests;
        protected bool _acceptGZipEncoding;
        private object _errorCode;
        private bool _refreshOnCacheExpire;
        private Microsoft.Iris.Timer _autoRefreshTimer;

        protected XmlDataProviderQuery(object queryTypeCookie)
          : base(queryTypeCookie)
        {
            this._passportTicketType = EPassportPolicyId.None;
            this._cachePolicy = HttpRequestCachePolicy.Default;
            this._keepAlive = true;
            this._ignoreNamespacePrefix = true;
            this._ignoreDuplicateGenerationRequests = true;
            this.Result = XmlDataProviderObjectFactory.CreateObject(this, this.ResultTypeCookie);
        }

        protected override void OnDispose()
        {
            base.OnDispose();
            if (this._autoRefreshTimer == null)
                return;
            this._autoRefreshTimer.Stop();
            this._autoRefreshTimer.Dispose();
            this._autoRefreshTimer = null;
        }

        public object ErrorCode => this._errorCode;

        public HttpRequestCachePolicy CachePolicy
        {
            get => this._cachePolicy;
            set => this._cachePolicy = value;
        }

        public EPassportPolicyId PassportTicketType
        {
            get => this._passportTicketType;
            set => this._passportTicketType = value;
        }

        public bool IgnoreDuplicateGenerationRequests
        {
            get => this._ignoreDuplicateGenerationRequests;
            set => this._ignoreDuplicateGenerationRequests = value;
        }

        public bool RefreshOnCacheExpire
        {
            get => this._refreshOnCacheExpire;
            set => this._refreshOnCacheExpire = value;
        }

        protected override void BeginExecute()
        {
            if (this.GetProperty("SendPassportTicket") is bool passportProperty)
                this._passportTicketType = passportProperty ? EPassportPolicyId.MBI : EPassportPolicyId.None;
            if (this.GetProperty("SendSecurePassportTicket") is bool securePassportProperty)
                this._passportTicketType = securePassportProperty ? EPassportPolicyId.MBI_SSL : EPassportPolicyId.None;
            if (this.GetProperty("RefreshOnCacheExpire") is bool expireProperty)
                this._refreshOnCacheExpire = expireProperty;
            string resourceUri = this.GetResourceUri();
            string postBody = this.GetPostBody();
            if (string.IsNullOrEmpty(resourceUri))
                return;
            this.GetDataFromResource(resourceUri, postBody, true);
        }

        protected virtual string GetResourceUri() => (string)null;

        protected virtual string GetPostBody() => (string)null;

        internal virtual bool FilterDataProviderObject(XmlDataProviderObject dataObject) => false;

        protected override void OnPropertyChanged(string propertyName)
        {
            if (propertyName == "LocalSortBy" && this.Result != null)
                ((XmlDataProviderObject)this.Result).ChangeListSort((string)this.GetProperty(propertyName));
            base.OnPropertyChanged(propertyName);
        }

        internal void GetDataFromResource(string uri, string body, bool fNewGeneration)
        {
            GetDataFromResourceArgs fromResourceArgs = new GetDataFromResourceArgs(uri, body, fNewGeneration);
            if (Application.IsApplicationThread)
                this.GetDataFromResource(fromResourceArgs);
            else
                Application.DeferredInvoke(new DeferredInvokeHandler(this.GetDataFromResource), fromResourceArgs);
        }

        private void GetDataFromResource(object obj)
        {
            GetDataFromResourceArgs fromResourceArgs = (GetDataFromResourceArgs)obj;
            string requestUri = fromResourceArgs.Uri;
            string requestBody = fromResourceArgs.Body;
            bool newGeneration = fromResourceArgs.NewGeneration;
            string property1 = (string)this.GetProperty("LocalSortBy");
            bool fPaged = this.GetProperty("Paged") is bool property2 && property2;
            XmlDataProviderObject result = null;
            if (newGeneration)
            {
                ++this._requestGeneration;
                result = XmlDataProviderObjectFactory.CreateObject(this, this.ResultTypeCookie);
                if (property1 != null)
                    result.ChangeListSort(property1);
            }
            else
            {
                result = (XmlDataProviderObject)this.Result;
                if (this._ignoreDuplicateGenerationRequests && string.Equals(requestUri, this._lastUri, StringComparison.CurrentCultureIgnoreCase))
                    return;
            }
            this._lastUri = requestUri;
            this.SetWorkerStatus(this._requestGeneration, DataProviderQueryStatus.RequestingData);
            bool flag = false;
            string localUri = null;
            if (!flag)
                ThreadPool.QueueUserWorkItem(arg =>
               {
                   int requestGeneration = (int)arg;
                   Microsoft.Zune.Service.HttpWebRequest httpWebRequest = this.ConstructWebRequest(requestUri, requestBody);
                   RequestArgs requestArgs = new RequestArgs(requestGeneration, requestUri, requestBody, localUri, result, fPaged, DateTime.Now, Environment.TickCount, httpWebRequest.CachePolicy);
                   httpWebRequest.GetResponseAsync(new AsyncRequestComplete(this.OnRequestComplete), requestArgs);
               }, _requestGeneration);
            PerfTrace.TraceUICollectionEvent(UICollectionEvent.DataProviderQueryBegin, this._lastUri);
        }

        private void OnRequestComplete(Microsoft.Zune.Service.HttpWebResponse response, object requestArgs)
        {
            RequestArgs requestArgs1 = (RequestArgs)requestArgs;
            Stream xmlStream = null;
            try
            {
                xmlStream = response.StatusCode == HttpStatusCode.OK ? response.GetResponseStream() : throw new HttpWebException(response);
                this.ParseXml(xmlStream, requestArgs1.m_requestGeneration, requestArgs1.m_requestUri, requestArgs1.m_requestBody, requestArgs1.m_result, requestArgs1.m_fPaged, requestArgs1.m_tmStartTime, requestArgs1.m_tcStart);
                if (requestArgs1.m_cachePolicy == HttpRequestCachePolicy.Refresh && this._cachePolicy == HttpRequestCachePolicy.Default && requestArgs1.m_result.NextPage != null)
                    UriResourceTracker.Instance.SetResourceModified(requestArgs1.m_result.NextPage.GetPageUrl(0), true);
                this.SetAutoRefreshTimer(response.Expires);
            }
            catch (Exception ex)
            {
                if (ex is HttpWebException)
                {
                    object statusCode = ((HttpWebException)ex).Response.StatusCode;
                    this.SetWorkerStatus(requestArgs1.m_requestGeneration, DataProviderQueryStatus.Error, statusCode);
                }
                else
                    this.SetWorkerStatus(requestArgs1.m_requestGeneration, DataProviderQueryStatus.Error, null);
                int num = TraceSwitches.DataProviderSwitch.TraceWarning ? 1 : 0;
            }
            finally
            {
                xmlStream?.Close();
                response.Close();
                PerfTrace.TraceUICollectionEvent(UICollectionEvent.DataProviderQueryComplete, this._lastUri);
            }
        }

        private void ParseXml(
          Stream xmlStream,
          int requestGeneration,
          string requestUri,
          string requestBody,
          XmlDataProviderObject result,
          bool fPaged,
          DateTime tmStartTime,
          int tcStart)
        {
            int num1 = 0;
            int num2 = 0;
            bool flag1 = false;
            XmlDataProviderReader xmlReader = null;
            try
            {
                num1 = Environment.TickCount - tcStart;
                this.SetWorkerStatus(requestGeneration, DataProviderQueryStatus.ProcessingData);
                StringBuilder stringBuilder = new StringBuilder(80);
                int[] numArray = new int[20];
                xmlReader = new XmlDataProviderReader(xmlStream);
                List<XPathMatch> xpathMatchList = new List<XPathMatch>(2);
                bool flag2 = false;
                int num3 = TraceSwitches.DataProviderSwitch.TraceVerbose ? 1 : 0;
                XmlNodeType xmlNodeType = XmlNodeType.None;
                while (xmlNodeType != XmlNodeType.None || xmlReader.Read())
                {
                    xmlNodeType = XmlNodeType.None;
                    if (requestGeneration != this._requestGeneration)
                    {
                        flag2 = true;
                        break;
                    }
                    if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Depth < numArray.Length)
                    {
                        int depth = xmlReader.Depth;
                        stringBuilder.Length = depth > 0 ? numArray[depth - 1] : 0;
                        stringBuilder.Append('/');
                        if (this._ignoreNamespacePrefix)
                            stringBuilder.Append(xmlReader.LocalName);
                        else
                            stringBuilder.Append(xmlReader.Name);
                        numArray[depth] = stringBuilder.Length;
                        string str = stringBuilder.ToString();
                        if (fPaged)
                        {
                            IPageInfo nextPageInfo = this.ExtractNextPageInfo(requestUri, requestBody, str, xmlReader);
                            if (nextPageInfo != null)
                                result.NextPage = nextPageInfo;
                        }
                        Hashtable attributes = new Hashtable(3);
                        if (xmlReader.MoveToFirstAttribute())
                        {
                            do
                            {
                                attributes[xmlReader.Name] = xmlReader.Value;
                            }
                            while (xmlReader.MoveToNextAttribute());
                        }
                        result.ProcessXPath(str, attributes, xpathMatchList);
                        if (xpathMatchList.Count > 0)
                        {
                            flag1 = true;
                            string xmlValue = null;
                            if (xmlReader.Read() && (xmlNodeType = xmlReader.NodeType) == XmlNodeType.Text)
                            {
                                xmlNodeType = XmlNodeType.None;
                                xmlValue = xmlReader.Value;
                            }
                            ProcessXPathMatches(xpathMatchList, attributes, xmlValue, xmlReader);
                        }
                        foreach (string key in attributes.Keys)
                        {
                            result.ProcessXPath(str + "@" + key, attributes, xpathMatchList);
                            if (xpathMatchList.Count > 0)
                            {
                                flag1 = true;
                                ProcessXPathMatches(xpathMatchList, attributes, null, null);
                            }
                        }
                    }
                }
                if (!flag2)
                {
                    Application.DeferredInvoke(new DeferredInvokeHandler(this.DeferredSetResult), new DeferredSetResultArgs(requestGeneration, result));
                    this.SetWorkerStatus(requestGeneration, DataProviderQueryStatus.Complete);
                    if (TraceSwitches.DataProviderSwitch.TraceWarning)
                    {
                        num2 = Environment.TickCount - tcStart;
                        int num4 = flag1 ? 1 : 0;
                    }
                }
            }
            catch (Exception ex)
            {
                Application.DeferredInvoke(new DeferredInvokeHandler(this.DeferredSetResult), new DeferredSetResultArgs(requestGeneration, result));
                this.SetWorkerStatus(requestGeneration, DataProviderQueryStatus.Error);
                throw ex;
            }
            finally
            {
                xmlReader?.Close();
            }
            int num5 = TraceSwitches.DataProviderSwitch.TraceVerbose ? 1 : 0;
        }

        internal virtual IPageInfo ExtractNextPageInfo(
          string requestUri,
          string requestBody,
          string strElementPath,
          XmlDataProviderReader xmlReader)
        {
            if (strElementPath == "/feed/link")
            {
                bool flag = false;
                if (xmlReader.MoveToFirstAttribute())
                {
                    do
                    {
                        if (xmlReader.Name == "rel")
                            flag = xmlReader.Value == "next";
                        else if (xmlReader.Name == "href" && flag && !string.IsNullOrEmpty(xmlReader.Value))
                            return new LinkPageInfo(ConstructLinkUrl(requestUri, xmlReader.Value), requestBody);
                    }
                    while (xmlReader.MoveToNextAttribute());
                }
            }
            return null;
        }

        private Microsoft.Zune.Service.HttpWebRequest ConstructWebRequest(
          string requestUri,
          string requestBody)
        {
            return requestBody != null ? WebRequestHelper.ConstructWebPostRequest(requestUri, requestBody, this._passportTicketType, this._cachePolicy, this._keepAlive, this._acceptGZipEncoding) : WebRequestHelper.ConstructWebRequest(requestUri, this._passportTicketType, this._cachePolicy, this._keepAlive, this._acceptGZipEncoding);
        }

        private static string ConstructLinkUrl(string baseUrl, string relativeUrl)
        {
            string str = null;
            if (relativeUrl.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
            {
                str = relativeUrl;
            }
            else
            {
                int num = baseUrl.IndexOf("//");
                if (num > 0)
                {
                    int length = baseUrl.IndexOf('/', num + 2);
                    if (length > 0)
                        str = baseUrl.Substring(0, length) + relativeUrl;
                }
            }
            return str;
        }

        private static void ProcessXPathMatches(
          List<XPathMatch> xpathMatches,
          Hashtable attributes,
          string xmlValue,
          XmlDataProviderReader xmlReader)
        {
            foreach (XPathMatch xpathMatch in xpathMatches)
            {
                string str = xmlValue;
                if (xpathMatch.matchingAttributeName != null)
                    str = (string)attributes[xpathMatch.matchingAttributeName];
                if (xpathMatch.encodedXml && str != null && xmlReader != null)
                    xmlReader.PushElement(str);
                else if (str != null)
                    xpathMatch.instance.SetPropertyFromStringValue(xpathMatch.propertyMapping, str);
            }
            xpathMatches.Clear();
        }

        protected void SetWorkerStatus(int requestGeneration, DataProviderQueryStatus eStatus) => this.SetWorkerStatus(requestGeneration, eStatus, null);

        protected void SetWorkerStatus(
          int requestGeneration,
          DataProviderQueryStatus eStatus,
          object errorCode)
        {
            Application.DeferredInvoke(new DeferredInvokeHandler(this.DeferredSetStatus), new DeferredSetStatusArgs(requestGeneration, eStatus, errorCode));
        }

        private void DeferredSetStatus(object args)
        {
            if (!(args is DeferredSetStatusArgs deferredSetStatusArgs) || deferredSetStatusArgs.m_requestGeneration != this._requestGeneration)
                return;
            this.Status = deferredSetStatusArgs.m_eStatus;
            this._errorCode = this.Status != DataProviderQueryStatus.Error ? null : deferredSetStatusArgs.m_errorCode;
            if (this.Status == DataProviderQueryStatus.Error)
                this._lastUri = null;
            if (this.Result == null || this.Status != DataProviderQueryStatus.Complete)
                return;
            ((XmlDataProviderObject)this.Result).OnQueryComplete();
        }

        private void SetAutoRefreshTimer(DateTime expires)
        {
            if (!this._refreshOnCacheExpire)
                return;
            Application.DeferredInvoke(new DeferredInvokeHandler(this.DeferredSetAutoRefreshTimer), expires);
        }

        private void DeferredSetAutoRefreshTimer(object args)
        {
            DateTime utcNow = DateTime.UtcNow;
            DateTime dateTime = (DateTime)args;
            if (dateTime == DateTime.MaxValue || dateTime <= utcNow)
            {
                int refreshQueryFallback = ClientConfiguration.Service.AutoRefreshQueryFallback;
                dateTime = utcNow.AddMilliseconds(refreshQueryFallback);
            }
            if (!(dateTime != DateTime.MaxValue))
                return;
            if (this._autoRefreshTimer == null)
            {
                this._autoRefreshTimer = new Microsoft.Iris.Timer();
                this._autoRefreshTimer.Tick += (sender, eventArgs) =>
               {
                   this._autoRefreshTimer.Stop();
                   this.Refresh();
               };
            }
            int num1 = new Random().Next(1, 300000);
            if (dateTime > utcNow)
            {
                long num2 = dateTime.Subtract(utcNow).Ticks / 10000L;
                if (num2 > int.MaxValue - num1)
                    num1 += 900000;
                else
                    num1 += (int)num2;
            }
            this._autoRefreshTimer.Stop();
            this._autoRefreshTimer.Interval = num1;
            this._autoRefreshTimer.Start();
        }

        private void DeferredSetResult(object argsObj)
        {
            if (!(argsObj is DeferredSetResultArgs deferredSetResultArgs) || deferredSetResultArgs.m_requestGeneration != this._requestGeneration)
                return;
            deferredSetResultArgs.m_result.TransferToAppThread();
            if (this.Result == deferredSetResultArgs.m_result)
                return;
            this.Result = deferredSetResultArgs.m_result;
        }

        private class GetDataFromResourceArgs
        {
            public readonly string Uri;
            public readonly string Body;
            public readonly bool NewGeneration;

            public GetDataFromResourceArgs(string uri, string body, bool fNewGeneration)
            {
                this.Uri = uri;
                this.Body = body;
                this.NewGeneration = fNewGeneration;
            }
        }

        private class RequestArgs
        {
            public readonly int m_requestGeneration;
            public readonly string m_requestUri;
            public readonly string m_requestBody;
            public readonly string m_localUri;
            public readonly XmlDataProviderObject m_result;
            public readonly bool m_fPaged;
            public readonly DateTime m_tmStartTime;
            public readonly int m_tcStart;
            public readonly HttpRequestCachePolicy m_cachePolicy;

            public RequestArgs(
              int requestGeneration,
              string requestUri,
              string requestBody,
              string localUri,
              XmlDataProviderObject result,
              bool fPaged,
              DateTime tmStartTime,
              int tcStart,
              HttpRequestCachePolicy cachePolicy)
            {
                this.m_requestGeneration = requestGeneration;
                this.m_requestUri = requestUri;
                this.m_requestBody = requestBody;
                this.m_localUri = localUri;
                this.m_result = result;
                this.m_fPaged = fPaged;
                this.m_tmStartTime = tmStartTime;
                this.m_tcStart = tcStart;
                this.m_cachePolicy = cachePolicy;
            }
        }

        private class DeferredSetStatusArgs
        {
            public readonly DataProviderQueryStatus m_eStatus;
            public readonly int m_requestGeneration;
            public readonly object m_errorCode;

            public DeferredSetStatusArgs(
              int requestGeneration,
              DataProviderQueryStatus eStatus,
              object errorCode)
            {
                this.m_eStatus = eStatus;
                this.m_requestGeneration = requestGeneration;
                this.m_errorCode = errorCode;
            }
        }

        private class DeferredSetResultArgs
        {
            public readonly XmlDataProviderObject m_result;
            public readonly int m_requestGeneration;

            public DeferredSetResultArgs(int requestGeneration, XmlDataProviderObject result)
            {
                this.m_requestGeneration = requestGeneration;
                this.m_result = result;
            }
        }

        public struct XPathMatch
        {
            public XmlDataProviderObject instance;
            public DataProviderMapping propertyMapping;
            public string matchingAttributeName;
            public bool encodedXml;

            public XPathMatch(
              XmlDataProviderObject instance,
              DataProviderMapping propertyMapping,
              string matchingAttributeName,
              bool encodedXml)
            {
                this.instance = instance;
                this.propertyMapping = propertyMapping;
                this.matchingAttributeName = matchingAttributeName;
                this.encodedXml = encodedXml;
            }
        }
    }
}
