Inheritance: IStreamSocketInformation
        private async Task writeResponseAsync(string request, IOutputStream os, StreamSocketInformation socketInfo)
        {
            try
            {
                request = request.TrimEnd('\0'); //remove possible null from POST request

                string[] requestParts = request.Split('/');

                // Request for the root page, so redirect to home page
                if (request.Equals("/"))
                {
                    await redirectToPage(NavConstants.HOME_PAGE, os);
                }
                // Request for the home page
                else if (request.Contains(NavConstants.HOME_PAGE))
                {
                    // Generate the default config page
                    string html = await GeneratePageHtml(NavConstants.HOME_PAGE);
                    string onState = (this.playbackManager.PlaybackState == PlaybackState.Playing) ? "On" : "Off";

                    html = html.Replace("#onState#", onState);
                    html = html.Replace("#radioVolume#", (this.playbackManager.Volume * 100).ToString());
                    html = html.Replace("#currentTrack#", this.playlistManager.CurrentTrack.Name);

                    await WebHelper.WriteToStream(html, os);

                }
                // Request for the settings page
                else if (request.Contains(NavConstants.SETTINGS_PAGE))
                {
                    if (!string.IsNullOrEmpty(request))
                    {
                        string settingParam = "";
                        IDictionary<string, string> parameters = WebHelper.ParseGetParametersFromUrl(new Uri(string.Format("http://0.0.0.0/{0}", request)));
                        bool waitForPlaying = (this.playbackManager.PlaybackState == PlaybackState.Playing);
                        bool waitForTrackChange = false;
                        string trackName = this.playlistManager.CurrentTrack.Name;

                        settingParam = "onStateVal";
                        if (parameters.ContainsKey(settingParam) && !string.IsNullOrWhiteSpace(parameters[settingParam]))
                        {
                            switch (parameters[settingParam])
                            {
                                case "On":
                                    if (!waitForPlaying)
                                        this.playbackManager.Play(new Uri(this.playlistManager.CurrentTrack.Address));
                                    waitForPlaying = true;
                                    break;
                                case "Off":
                                    this.playbackManager.Pause();
                                    waitForPlaying = false;
                                    break;
                            }
                        }
                        settingParam = "volumeSlide";
                        if (parameters.ContainsKey(settingParam) && !string.IsNullOrWhiteSpace(parameters[settingParam]))
                        {
                            double newVolume = this.playbackManager.Volume;
                            if (double.TryParse(parameters[settingParam], out newVolume))
                            {
                                newVolume = Math.Round(newVolume / 100, 2);
                                if (newVolume >= 0 && newVolume <= 1 && newVolume != this.playbackManager.Volume)
                                {
                                    this.playbackManager.Volume = newVolume;
                                }
                            }
                        }
                        settingParam = "trackAction";
                        if (parameters.ContainsKey(settingParam) && !string.IsNullOrWhiteSpace(parameters[settingParam]))
                        {
                            waitForTrackChange = true;
                            switch (parameters[settingParam])
                            {
                                case "prev":
                                    this.playbackManager.Pause();
                                    this.playlistManager.PreviousTrack();
                                    break;
                                case "next":
                                    this.playbackManager.Pause();
                                    this.playlistManager.NextTrack();
                                    break;
                                case "track":
                                    if (parameters.ContainsKey("trackName") && !string.IsNullOrWhiteSpace(parameters["trackName"]))
                                    {
                                        if (trackName != parameters["trackName"])
                                        {
                                            this.playbackManager.Pause();
                                            this.playlistManager.PlayTrack(parameters["trackName"]);
                                        }
                                        else
                                            waitForTrackChange = false;
                                    }
                                    break;
                            }
                            if (waitForTrackChange) { waitForPlaying = true; }
                        }

                        DateTime timeOut = DateTime.Now.AddSeconds(30);
                        Debug.WriteLine("Waiting on State: playback={0}; trackname={1}", (waitForPlaying)?"Playing":"NotPlaying", trackName);
                        while (DateTime.Now.CompareTo(timeOut) < 0 && (
                            (this.playbackManager.PlaybackState == PlaybackState.Playing) != waitForPlaying
                            || (this.playlistManager.CurrentTrack.Name != trackName) != waitForTrackChange
                            ));

                        if (DateTime.Now.CompareTo(timeOut) >= 0)
                        {
                            Debug.WriteLine("track did not start playing in time limit");
                        }
                    }
                    //handle UI interaction
                    await redirectToPage(NavConstants.HOME_PAGE, os);
                }
                else if (request.Contains(NavConstants.ADDSTATION_PAGE))
                {
                    string html = await GeneratePageHtml(NavConstants.ADDSTATION_PAGE);
                    string trackName = "";
                    string trackUrl = "";
                    if (!string.IsNullOrEmpty(request))
                    {
                        string settingParam = "trackName";
                        IDictionary<string, string> parameters = WebHelper.ParseGetParametersFromUrl(new Uri(string.Format("http://0.0.0.0/{0}", request)));
                        if (parameters.ContainsKey(settingParam) && !string.IsNullOrWhiteSpace(parameters[settingParam]))
                        {
                            Track trackToUpdate = playlistManager.CurrentPlaylist.Tracks.First(t => t.Name == parameters[settingParam]);
                            if (null != trackToUpdate)
                            {
                                trackName = trackToUpdate.Name;
                                trackUrl = trackToUpdate.Address;
                            }
                        }
                    }
                    html = html.Replace("var stationName = '';", string.Format("var stationName = '{0}';", trackName));
                    html = html.Replace("var stationUrl = '';", string.Format("var stationUrl = '{0}';", trackUrl));
                    await WebHelper.WriteToStream(html, os);
                }
                else if (request.Contains(NavConstants.ADDSTATIONSET_PAGE))
                {
                    if (!string.IsNullOrEmpty(request))
                    {
                        Track origTrack = null;
                        Track newTrack = null;
                        string trackAction = "";
                        IDictionary<string, string> parameters = WebHelper.ParseGetParametersFromUrl(new Uri(string.Format("http://0.0.0.0/{0}", request)));
                        if (parameters.ContainsKey("name") && !string.IsNullOrWhiteSpace(parameters["name"]))
                        {
                            if (parameters.ContainsKey("url") && !string.IsNullOrWhiteSpace(parameters["url"]))
                            {
                                newTrack = new Track() { Name = parameters["name"], Address = parameters["url"] };
                            }
                        }
                        if (parameters.ContainsKey("nameOrig") && !string.IsNullOrWhiteSpace(parameters["nameOrig"]))
                        {
                            origTrack = this.playlistManager.CurrentPlaylist.Tracks.First(t => t.Name == parameters["nameOrig"]);
                        }
                        if (parameters.ContainsKey("trackAction") && !string.IsNullOrWhiteSpace(parameters["trackAction"]))
                        {
                            trackAction = parameters["trackAction"];
                        }

                        if (null != newTrack)
                        {
                            switch (trackAction)
                            {
                                case "Update":
                                    if (null != origTrack)
                                    {
                                        this.playlistManager.CurrentPlaylist.Tracks[this.playlistManager.CurrentPlaylist.Tracks.IndexOf(origTrack)] = newTrack;
                                    }
                                    else
                                    { 
                                        this.playlistManager.CurrentPlaylist.Tracks.Add(newTrack);
                                    }
                                    break;
                                case "Remove":
                                    if (null != origTrack)
                                        this.playlistManager.CurrentPlaylist.Tracks.Remove(origTrack);
                                    break;
                                case "":
                                case "Add":
                                    this.playlistManager.CurrentPlaylist.Tracks.Add(newTrack);
                                    break;
                            }
                        }
                    }
                    await redirectToPage(NavConstants.HOME_PAGE, os);
                }
                // Request for a file that is in the Assets\Web folder (e.g. logo, css file)
                else
                {
                    using (Stream resp = os.AsStreamForWrite())
                    {
                        bool exists = true;
                        try
                        {
                            var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;

                            // Map the requested path to Assets\Web folder
                            string filePath = NavConstants.ASSETSWEB + request.Replace('/', '\\');

                            // Open the file and write it to the stream
                            using (Stream fs = await folder.OpenStreamForReadAsync(filePath))
                            {
                                string contentType = "";
                                if (request.Contains("css"))
                                {
                                    contentType = "Content-Type: text/css\r\n";
                                }
                                if (request.Contains("htm"))
                                {
                                    contentType = "Content-Type: text/html\r\n";
                                }
                                string header = String.Format("HTTP/1.1 200 OK\r\n" +
                                                "Content-Length: {0}\r\n{1}" +
                                                "Connection: close\r\n\r\n",
                                                fs.Length,
                                                contentType);
                                byte[] headerArray = Encoding.UTF8.GetBytes(header);
                                await resp.WriteAsync(headerArray, 0, headerArray.Length);
                                await fs.CopyToAsync(resp);
                            }
                        }
                        catch (FileNotFoundException ex)
                        {
                            exists = false;

                            // Log telemetry event about this exception
                            var events = new Dictionary<string, string> { { "WebServer", ex.Message } };
                            TelemetryManager.WriteTelemetryEvent("FailedToOpenStream", events);
                        }

                        // Send 404 not found if can't find file
                        if (!exists)
                        {
                            byte[] headerArray = Encoding.UTF8.GetBytes(
                                                  "HTTP/1.1 404 Not Found\r\n" +
                                                  "Content-Length:0\r\n" +
                                                  "Connection: close\r\n\r\n");
                            await resp.WriteAsync(headerArray, 0, headerArray.Length);
                        }

                        await resp.FlushAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception in writeResponseAsync(): " + ex.Message);
                Debug.WriteLine(ex.StackTrace);

                // Log telemetry event about this exception
                var events = new Dictionary<string, string> { { "WebServer", ex.Message } };
                TelemetryManager.WriteTelemetryEvent("FailedToWriteResponse", events);

                try
                {
                    // Try to send an error page back if there was a problem servicing the request
                    string html = helper.GenerateErrorPage("There's been an error: " + ex.Message + "<br><br>" + ex.StackTrace);
                    await WebHelper.WriteToStream(html, os);
                }
                catch (Exception e)
                {
                    TelemetryManager.WriteTelemetryException(e);
                }
            }
        }
        private async Task writeResponseAsync(string request, IOutputStream os, StreamSocketInformation socketInfo)
        {
            try
            {
                string[] requestParts = request.Split('/');

                // Request for the root page, so redirect to home page
                if (request.Equals("/"))
                {
                    await redirectToPage(NavConstants.HOME_PAGE, os);
                }
                // Request for the home page
                else if(request.Contains(NavConstants.HOME_PAGE))
                {
                    // Generate the default config page
                    string html = await helper.GenerateStatusPage();
                    await WebHelper.WriteToStream(html, os);
                }
                // Request for the settings page
                else if (request.Contains(NavConstants.SETTINGS_PAGE))
                {
                    // Process the GET parameters
                    if (request.Contains("?"))
                    {
                        // Format the URI with the get parameters
                        Uri uri = new Uri("http://1.2.3.4:8000" + request);

                        // Take the parameters from the URL and put it into Settings
                        helper.ParseUriIntoSettings(uri);
                        await AppSettings.SaveAsync(App.Controller.XmlSettings, "Settings.xml");

                        // This is an event that lets us know what the controller is done restarting after the settings are applied
                        AutoResetEvent ase = new AutoResetEvent(false);

                        // Dispose and Initialize need to be called on UI thread because of DispatcherTimers
                        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
                        {
                            try
                            {
                                // Restart the controller to apply new settings
                                App.Controller.Dispose();
                                await App.Controller.Initialize();

                                // Create the settings page and add a confirmation message that the settings were applied successfully
                                string html = helper.GeneratePage("Security System Config", "Security System Config", helper.CreateHtmlFormFromSettings(), "<span style='color:Green'>Configuration saved!</span><br><br>");
                                await WebHelper.WriteToStream(html, os);
                            }
                            catch (Exception ex)
                            {
                                Debug.WriteLine("Error restarting controller: " + ex.Message);
                            }

                            // Signal that the restart is done
                            ase.Set();
                        });

                        // Wait for controller restart to finish
                        ase.WaitOne();
                    }
                    else
                    {
                        // Generate the default config page
                        string html = helper.GeneratePage("Security System Config", "Security System Config", helper.CreateHtmlFormFromSettings());
                        await WebHelper.WriteToStream(html, os);
                    }
                }
                // Request for the OneDrive page
                else if (request.Contains(NavConstants.ONEDRIVE_PAGE))
                {
                    // Take in the parameters and try to login to OneDrive
                    if (request.Contains("?"))
                    {
                        // I just put some arbitrary IP and port just so I have a correctly formatted URI, it's not important to have an actual IP + port
                        Uri uri = new Uri("http://1.2.3.4:8000" + request);
                        await helper.ParseOneDriveUri(uri);

                        var oneDrive = App.Controller.Storage as OneDrive;
                        if (oneDrive != null)
                        {
                            if (oneDrive.IsLoggedIn())
                            {
                                // Save tokens to settings file if we successfully logged in
                                await AppSettings.SaveAsync(App.Controller.XmlSettings, "Settings.xml");
                            }
                        }
                    }

                    // Generate page and write to stream
                    string html = helper.GenerateOneDrivePage();
                    await WebHelper.WriteToStream(html, os);
                }
                // Request for gallery page
                else if(request.Contains(NavConstants.GALLERY_PAGE))
                {
                    string html = "";
                    var storageType = App.Controller.Storage.GetType();
                    // If the storage type is OneDrive, generate page with link to OneDrive
                    if (storageType == typeof(OneDrive))
                    {
                        html = helper.GeneratePage("Gallery", "Gallery", "<b>" + storageType.Name + "</b> is set as your storage provider.&nbsp;&nbsp;"
                            + "Please view your pictures on <a href='http://www.onedrive.com' target='_blank'>OneDrive</a>.<br><br>"
                            + "To view your pictures here, please select <b>" + StorageProvider.Local + "</b> as your storage provider.");
                    }
                    // Otherwise show the gallery for the files on the device
                    else
                    {
                        StorageFolder folder = KnownFolders.PicturesLibrary;
                        int page = 1;
                        int pageSize = 30;

                        // Parse GET parameters
                        if (request.Contains("?"))
                        {
                            Uri uri = new Uri("http://1.2.3.4:8000" + request);
                            var parameters = helper.ParseGetParametersFromUrl(uri);
                            try
                            {
                                // Find the folder that's specified in the parameters
                                folder = await StorageFolder.GetFolderFromPathAsync(parameters["folder"]);

                                if(parameters.ContainsKey("page"))
                                {
                                    try
                                    {
                                        page = Convert.ToInt32(parameters["page"]);
                                    }
                                    catch (Exception) { }
                                }

                                if (parameters.ContainsKey("pageSize"))
                                {
                                    try
                                    {
                                        pageSize = Convert.ToInt32(parameters["pageSize"]);
                                    }
                                    catch (Exception) { }
                                }
                            }
                            catch (Exception ex)
                            {
                                Debug.WriteLine("Exception finding folder: " + ex.Message);
                                folder = await folder.GetFolderAsync(AppSettings.FolderName);

                                // Log telemetry event about this exception
                                var events = new Dictionary<string, string> { { "WebServer", ex.Message } };
                                TelemetryHelper.TrackEvent("FailedToGetFolderFromPath", events);
                            }
                        }
                        else
                        {
                            folder = await folder.GetFolderAsync(AppSettings.FolderName);
                        }

                        // Generate gallery page and write to stream
                        string galleryHtml = await helper.GenerateGallery(folder, page, pageSize);
                        html = helper.GeneratePage("Gallery", "Gallery", galleryHtml);
                    }

                    await WebHelper.WriteToStream(html, os);
                }
                // Request for API
                else if(request.Contains("api"))
                {
                    try
                    {
                        if (requestParts.Length > 2)
                        {
                            switch (requestParts[2].ToLower())
                            {
                                // An image from the gallery was requested
                                case "gallery":
                                    var temp = request.Split(new string[] { "gallery/" }, StringSplitOptions.None);
                                    // HTML decode the file path
                                    string decodedPath = WebUtility.UrlDecode(temp[1]);

                                    // Retrieve the file
                                    StorageFile file = await StorageFile.GetFileFromPathAsync(decodedPath);

                                    // Write the file to the stream
                                    await WebHelper.WriteFileToStream(file, os);
                                    break;
                            }
                        }
                    }catch(Exception ex)
                    {
                        Debug.WriteLine("Exception in web API: " + ex.Message);

                        // Log telemetry event about this exception
                        var events = new Dictionary<string, string> { { "WebServer", ex.Message } };
                        TelemetryHelper.TrackEvent("FailedToProcessApiRequest", events);
                    }
                }
                // Request for a file that is in the Assets\Web folder (e.g. logo, css file)
                else
                {
                    using (Stream resp = os.AsStreamForWrite())
                    {
                        bool exists = true;
                        try
                        {
                            var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;

                            // Map the requested path to Assets\Web folder
                            string filePath = @"Assets\Web" + request.Replace('/', '\\');
                            
                            // Open the file and write it to the stream
                            using (Stream fs = await folder.OpenStreamForReadAsync(filePath))
                            {
                                string header = String.Format("HTTP/1.1 200 OK\r\n" +
                                                "Content-Length: {0}\r\n{1}" +
                                                "Connection: close\r\n\r\n",
                                                fs.Length,
                                                ((request.Contains("css")) ? "Content-Type: text/css\r\n" : ""));
                                byte[] headerArray = Encoding.UTF8.GetBytes(header);
                                await resp.WriteAsync(headerArray, 0, headerArray.Length);
                                await fs.CopyToAsync(resp);
                            }
                        }
                        catch (FileNotFoundException ex)
                        {
                            exists = false;

                            // Log telemetry event about this exception
                            var events = new Dictionary<string, string> { { "WebServer", ex.Message } };
                            TelemetryHelper.TrackEvent("FailedToOpenStream", events);
                        }

                        // Send 404 not found if can't find file
                        if (!exists)
                        {
                            byte[] headerArray = Encoding.UTF8.GetBytes(
                                                  "HTTP/1.1 404 Not Found\r\n" +
                                                  "Content-Length:0\r\n" +
                                                  "Connection: close\r\n\r\n");
                            await resp.WriteAsync(headerArray, 0, headerArray.Length);
                        }

                        await resp.FlushAsync();
                    }
                }
            }catch(Exception ex)
            {
                Debug.WriteLine("Exception in writeResponseAsync(): " + ex.Message);
                Debug.WriteLine(ex.StackTrace);

                // Log telemetry event about this exception
                var events = new Dictionary<string, string> { { "WebServer", ex.Message } };
                TelemetryHelper.TrackEvent("FailedToWriteResponse", events);

                try
                {
                    // Try to send an error page back if there was a problem servicing the request
                    string html = helper.GeneratePage("Error", "Error", "There's been an error: " + ex.Message + "<br><br>" + ex.StackTrace);
                    await WebHelper.WriteToStream(html, os);
                }
                catch (Exception e)
                {
                    TelemetryHelper.TrackException(e);
                }
            }
        }
 /// <summary>
 /// Creates a new ClientConnectedEventArgs object
 /// </summary>
 /// <param name="clientInformation">Client socket information</param>
 /// <param name="clientId">Client's GUID</param>
 public ClientConnectedEventArgs(StreamSocketInformation clientInformation, string clientId)
     : base()
 {
     this.clientInformation = clientInformation;
     this.ClientId = clientId;
 }