/// <summary>
 /// Async callback for webclients get file operation
 /// ,gets called if the file was retrieved successfully
 /// </summary>
 /// <param name="sender">event sending webclient instance</param>
 /// <param name="e">event arguments of the download operation</param>
 private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
 {
     try
     {
         if (e.Cancelled)
         {
             return;
         }
         if (e.Result == null || e.Result.Length == 0)
         {
             error_code = Connection.ErrorCodes.UrlNotFound;
             Console.WriteLine("Error downloading hublist.");
             if (UnableToFetch != null)
             {
                 UnableToFetch(this);
             }
             return;
         }
         //Console.WriteLine("Error:"+e.Error.Data.Values.ToString());
         //if its a bz2 uncompress the data stream
         //Stream input = new StreamReader(e.Result);
         byte[] input_bytes = e.Result;
         ProcessDownloadedBytes(input_bytes);
     }
     catch (Exception ex)
     {
         error_code = Connection.ErrorCodes.Exception;
         Console.WriteLine("exception during hublist fetch: " + ex.Message);
         if (UnableToFetch != null)
         {
             UnableToFetch(this);
         }
         busy = false;
     }
 }
 /// <summary>
 /// Start fetching a hublist
 /// needs url to point to a valid hublist to complete successfully
 /// [Non Blocking]
 /// </summary>
 public void FetchHubs()
 {
     if (!busy && !string.IsNullOrEmpty(url))
     {
         busy = true;
         //hubs.Clear();
         columns.Clear();
         percentage = 0;
         if (ProgressChanged != null)
         {
             ProgressChanged(this);
         }
         try
         {
             wc.DownloadDataAsync(new Uri(url));
         }
         catch (Exception ex)
         {
             Console.WriteLine("Exception occured during download: " + ex.Message);
             error_code = Connection.ErrorCodes.Exception;
             if (UnableToFetch != null)
             {
                 UnableToFetch(this);
             }
             busy = false;
         }
     }
 }
        /// <summary>
        /// Async callback for webclients get file operation
        /// ,gets called if the file was retrieved successfully
        /// </summary>
        /// <param name="sender">event sending webclient instance</param>
        /// <param name="e">event arguments of the download operation</param>
        private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled) return;
                //ASCIIEncoding ascii = new ASCIIEncoding();
                //UTF8Encoding utf = new UTF8Encoding();
                //string page_string = utf.GetString(e.Result);
                if (e.Result.Length <= 0) return;

                string page_string = "";
                try
                {
                    page_string = System.Text.Encoding.Default.GetString(e.Result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception after download: " + ex.Message);
                    return;
                }

                int start = page_string.IndexOf("<h1>Your IP address is<BR>\n");
                if (start != -1)
                {
                    string temp_ip = page_string.Substring(start + "<h1>Your IP address is<BR>".Length);
                    int end = temp_ip.IndexOf("</h1>");
                    if (end != -1)
                    {
                        temp_ip = temp_ip.Substring(0, end);
                        char[] trims = { '\n', ' ' };
                        temp_ip = temp_ip.Trim(trims);

                        //Console.WriteLine("temp_ip: '"+temp_ip+"'");
                        my_ip = temp_ip;
                        busy = false;
                        try
                        {
                            if (Completed != null)
                                Completed(this);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Exception during callback of own external ip resolve: " + ex.Message);
                        }
                    }
                }
            }
            catch (Exception out_ex)
            {
                Console.WriteLine("Exception during download of ip page: "+out_ex.Message);
                error_code = Connection.ErrorCodes.Exception;
                if (UnableToFetch != null)
                    UnableToFetch(this);

            }
        }
        /// <summary>
        /// Read a hublist from a xml string
        /// </summary>
        /// <param name="xml">the xml representation of a hublist</param>
        private bool ReadXmlStringAsync(string xml)
        {
            XmlDocument doc = new XmlDocument();
            bool try_again = false;
            try
            {
                //Console.WriteLine("Starting to parse xml data.");
                doc.LoadXml(xml);
                //Console.WriteLine("Finished parsing.");

            }
            catch (XmlException xe)
            {

                string error_message = "Unexpected end of file has occurred. The following elements are not closed: ";
                if (xe.Message.StartsWith(error_message))
                {
                    string tags = xe.Message.Substring(error_message.Length);
                    int end = tags.IndexOf(".");
                    if (end != -1)
                    {
                        tags = tags.Substring(0, end);
                        int last = 0;
                        int split = 0;
                        while ((split = tags.IndexOf(",", split)) != -1)
                        {
                            string tag = tags.Substring(last, split);
                            last = split + 1;
                            split++;
                            //int line = xe.LineNumber;
                            tag = tag.Trim();
                            xml = xml + "</" + tag + ">\r\n";
                        }
                        string last_tag = tags.Substring(last);
                        last_tag = last_tag.Trim();
                        xml = xml + "</" + last_tag + ">\r\n";

                    }
                    try_again = true;
                }
                else
                {
                    error_code = Connection.ErrorCodes.Exception;
                    Console.WriteLine("xml exception:" + xe.Message);
                    if (UnableToFetch != null)
                        UnableToFetch(this);
                    busy = false;
                    return (false);
                }

            }

            if (try_again)
            {
                try
                {
                    //Console.WriteLine("Starting to parse xml data for a second time.");
                    doc.LoadXml(xml);
                    //Console.WriteLine("Finished parsing.");

                }
                catch (XmlException xe)
                {
                    Console.WriteLine("xml exception:" + xe.Message);
                    return (false);
                }

            }

            //TODO change this to a non xpath workarround version
            try
            {
                XmlNodeList nodelist = doc.SelectNodes("/");
                foreach (XmlNode node in nodelist)
                {
                    if (node.HasChildNodes)
                    {
                        foreach (XmlNode child in node.ChildNodes)
                        {
                            if (child.Name.Equals("Hublist")) ReadHubList(child);
                        }
                    }

                }

            }
            catch (XmlException xmle)
            {
                error_code = Connection.ErrorCodes.Exception;
                Console.WriteLine(xmle.Message);
                if (UnableToFetch != null)
                    UnableToFetch(this);
                busy = false;
                return (false);

            }

            return (true);
        }
        /// <summary>
        /// Process the downloaded bytes from the webserver
        /// (uncompressing and reading of xml hublist)
        /// </summary>
        /// <param name="input_bytes">array of bytes received from a webserver</param>
        private void ProcessDownloadedBytesAsync(byte[] input_bytes)
        {
            MemoryStream input = new MemoryStream(input_bytes);
            MemoryStream output = new MemoryStream();
            ASCIIEncoding ascii = new ASCIIEncoding();
            UTF8Encoding utf = new UTF8Encoding();
            UnicodeEncoding unicode = new UnicodeEncoding();

            try
            {
                ICSharpCode.SharpZipLib.BZip2.BZip2.Decompress(input, output);
            }
            catch (Exception ex)
            {
                error_code = Connection.ErrorCodes.Exception;
                Console.WriteLine("Error uncompressing hublist: " + ex.Message);
                if (UnableToFetch != null)
                    UnableToFetch(this);
                busy = false;
                return;
            }
            input.Flush();
            byte[] out_data = output.GetBuffer();
            //string hubs_string = ascii.GetString(out_data);

            string hubs_string = System.Text.Encoding.Default.GetString(out_data);
            //string hubs_string = utf.GetString(out_data);
            int end = hubs_string.IndexOf((char)0);
            if (end != -1) hubs_string = hubs_string.Remove(end);
            //string hubs_string = unicode.GetString(out_data);
            for (int i = 0; i < 0x1f; i++)
                if (i != 0x09 && i != 0x0a && i != 0x0d) hubs_string = hubs_string.Replace((char)i, ' ');//"&#x00"+i+";"

            hubs_string = hubs_string.Replace("&", "&amp;"); // TODO change this ---- no good solution would change &amp; to &amp;amp;
            bool inside_quotes = false;
            for (int i = 0; i < hubs_string.Length; i++)
            {
                if (hubs_string[i] == '\"' && inside_quotes == false)
                {
                    inside_quotes = true;
                }
                else if (hubs_string[i] == '\"' && inside_quotes == true)
                {
                    inside_quotes = false;
                }

                if (inside_quotes && hubs_string[i] == '<')
                {
                    hubs_string = hubs_string.Remove(i, 1);
                    hubs_string = hubs_string.Insert(i, "&lt;");
                }

                if (inside_quotes && hubs_string[i] == '>')
                {
                    hubs_string = hubs_string.Remove(i, 1);
                    hubs_string = hubs_string.Insert(i, "&gt;");
                }

                if (inside_quotes && hubs_string[i] == '')
                {
                    hubs_string = hubs_string.Remove(i, 1);
                    hubs_string = hubs_string.Insert(i, " ");
                }

            }
            //hubs_string = hubs_string.Replace("&", "&amp;");
            //Console.WriteLine(hubs_string);
            //File.WriteAllText("hublist.uncompressed.xml", hubs_string);
            //output.Position = 0;
            ReadXmlStringAsync(hubs_string);
            /*busy = false;
            if (Completed != null)
                Completed(this);*/
        }
 /// <summary>
 /// Async callback for webclients get file operation
 /// ,gets called if the file was retrieved successfully
 /// </summary>
 /// <param name="sender">event sending webclient instance</param>
 /// <param name="e">event arguments of the download operation</param>
 private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
 {
     try
     {
         if (e.Cancelled) return;
         if (e.Result == null || e.Result.Length == 0)
         {
             error_code = Connection.ErrorCodes.UrlNotFound;
             Console.WriteLine("Error downloading hublist.");
             if (UnableToFetch != null)
                 UnableToFetch(this);
             return;
         }
         //Console.WriteLine("Error:"+e.Error.Data.Values.ToString());
         //if its a bz2 uncompress the data stream
         //Stream input = new StreamReader(e.Result);
         byte[] input_bytes = e.Result;
         ProcessDownloadedBytes(input_bytes);
     }
     catch (Exception ex)
     {
         error_code = Connection.ErrorCodes.Exception;
         Console.WriteLine("exception during hublist fetch: " + ex.Message);
         if (UnableToFetch != null)
             UnableToFetch(this);
         busy = false;
     }
 }
 /// <summary>
 /// Start fetching a hublist
 /// needs url to point to a valid hublist to complete successfully
 /// [Non Blocking]
 /// </summary>
 public void FetchHubs()
 {
     if (!busy && !string.IsNullOrEmpty(url))
     {
         busy = true;
         //hubs.Clear();
         columns.Clear();
         percentage = 0;
         if (ProgressChanged != null)
             ProgressChanged(this);
         try
         {
             wc.DownloadDataAsync(new Uri(url));
         }
         catch (Exception ex)
         {
             Console.WriteLine("Exception occured during download: " + ex.Message);
             error_code = Connection.ErrorCodes.Exception;
             if (UnableToFetch != null)
                 UnableToFetch(this);
             busy = false;
         }
     }
 }
        /// <summary>
        /// Async callback for webclients get file operation
        /// ,gets called if the file was retrieved successfully
        /// </summary>
        /// <param name="sender">event sending webclient instance</param>
        /// <param name="e">event arguments of the download operation</param>
        private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled) return;
                if (e.Result.Length <= 0) return;
                string page_string = "";
                page_string = System.Text.Encoding.Default.GetString(e.Result);
                //Console.WriteLine("port page: " + page_string);
                int start = page_string.IndexOf("<strong class=\"");
                if (start != -1)
                {
                    string temp = page_string.Substring(start + "<strong class=\"".Length);
                    int end = temp.IndexOf("\"");
                    if (end != -1)
                    {
                        string tcp = temp.Substring(0, end);
                        if (tcp == "green small")
                            OpenPorts = Ports.Tcp;
                        else OpenPorts = Ports.None;

                        start = temp.IndexOf("<strong class=\"");
                        if (start != -1)
                        {
                            string temp2 = temp.Substring(start + "<strong class=\"".Length);
                            end = temp2.IndexOf("\"");
                            if (end != -1)
                            {
                                string udp = temp2.Substring(0, end);
                                if (udp == "green small" && OpenPorts == Ports.None)
                                    OpenPorts = Ports.Udp;
                                if (udp == "green small" && OpenPorts == Ports.Tcp)
                                    OpenPorts = Ports.UdpAndTcp;

                                busy = false;
                                if (Completed != null)
                                    Completed(this);
                            }
                        }
                    }
                }
            }
            catch (Exception out_ex)
            {
                Console.WriteLine("Exception during download of port page: " + out_ex.Message);
                error_code = Connection.ErrorCodes.Exception;
                if (UnableToFetch != null)
                    UnableToFetch(this);

            }
        }
        /// <summary>
        /// Read a hublist from a xml string
        /// </summary>
        /// <param name="xml">the xml representation of a hublist</param>
        private bool ReadXmlStringAsync(string xml)
        {
            XmlDocument doc       = new XmlDocument();
            bool        try_again = false;

            try
            {
                //Console.WriteLine("Starting to parse xml data.");
                doc.LoadXml(xml);
                //Console.WriteLine("Finished parsing.");
            }
            catch (XmlException xe)
            {
                string error_message = "Unexpected end of file has occurred. The following elements are not closed: ";
                if (xe.Message.StartsWith(error_message))
                {
                    string tags = xe.Message.Substring(error_message.Length);
                    int    end  = tags.IndexOf(".");
                    if (end != -1)
                    {
                        tags = tags.Substring(0, end);
                        int last  = 0;
                        int split = 0;
                        while ((split = tags.IndexOf(",", split)) != -1)
                        {
                            string tag = tags.Substring(last, split);
                            last = split + 1;
                            split++;
                            //int line = xe.LineNumber;
                            tag = tag.Trim();
                            xml = xml + "</" + tag + ">\r\n";
                        }
                        string last_tag = tags.Substring(last);
                        last_tag = last_tag.Trim();
                        xml      = xml + "</" + last_tag + ">\r\n";
                    }
                    try_again = true;
                }
                else
                {
                    error_code = Connection.ErrorCodes.Exception;
                    Console.WriteLine("xml exception:" + xe.Message);
                    if (UnableToFetch != null)
                    {
                        UnableToFetch(this);
                    }
                    busy = false;
                    return(false);
                }
            }

            if (try_again)
            {
                try
                {
                    //Console.WriteLine("Starting to parse xml data for a second time.");
                    doc.LoadXml(xml);
                    //Console.WriteLine("Finished parsing.");
                }
                catch (XmlException xe)
                {
                    Console.WriteLine("xml exception:" + xe.Message);
                    return(false);
                }
            }

            //TODO change this to a non xpath workarround version
            try
            {
                XmlNodeList nodelist = doc.SelectNodes("/");
                foreach (XmlNode node in nodelist)
                {
                    if (node.HasChildNodes)
                    {
                        foreach (XmlNode child in node.ChildNodes)
                        {
                            if (child.Name.Equals("Hublist"))
                            {
                                ReadHubList(child);
                            }
                        }
                    }
                }
            }
            catch (XmlException xmle)
            {
                error_code = Connection.ErrorCodes.Exception;
                Console.WriteLine(xmle.Message);
                if (UnableToFetch != null)
                {
                    UnableToFetch(this);
                }
                busy = false;
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Process the downloaded bytes from the webserver
        /// (uncompressing and reading of xml hublist)
        /// </summary>
        /// <param name="input_bytes">array of bytes received from a webserver</param>
        private void ProcessDownloadedBytesAsync(byte[] input_bytes)
        {
            MemoryStream    input   = new MemoryStream(input_bytes);
            MemoryStream    output  = new MemoryStream();
            ASCIIEncoding   ascii   = new ASCIIEncoding();
            UTF8Encoding    utf     = new UTF8Encoding();
            UnicodeEncoding unicode = new UnicodeEncoding();

            try
            {
                ICSharpCode.SharpZipLib.BZip2.BZip2.Decompress(input, output);
            }
            catch (Exception ex)
            {
                error_code = Connection.ErrorCodes.Exception;
                Console.WriteLine("Error uncompressing hublist: " + ex.Message);
                if (UnableToFetch != null)
                {
                    UnableToFetch(this);
                }
                busy = false;
                return;
            }
            input.Flush();
            byte[] out_data = output.GetBuffer();
            //string hubs_string = ascii.GetString(out_data);

            string hubs_string = System.Text.Encoding.Default.GetString(out_data);
            //string hubs_string = utf.GetString(out_data);
            int end = hubs_string.IndexOf((char)0);

            if (end != -1)
            {
                hubs_string = hubs_string.Remove(end);
            }
            //string hubs_string = unicode.GetString(out_data);
            for (int i = 0; i < 0x1f; i++)
            {
                if (i != 0x09 && i != 0x0a && i != 0x0d)
                {
                    hubs_string = hubs_string.Replace((char)i, ' ');                                     //"&#x00"+i+";"
                }
            }
            hubs_string = hubs_string.Replace("&", "&amp;"); // TODO change this ---- no good solution would change &amp; to &amp;amp;
            bool inside_quotes = false;
            for (int i = 0; i < hubs_string.Length; i++)
            {
                if (hubs_string[i] == '\"' && inside_quotes == false)
                {
                    inside_quotes = true;
                }
                else if (hubs_string[i] == '\"' && inside_quotes == true)
                {
                    inside_quotes = false;
                }

                if (inside_quotes && hubs_string[i] == '<')
                {
                    hubs_string = hubs_string.Remove(i, 1);
                    hubs_string = hubs_string.Insert(i, "&lt;");
                }

                if (inside_quotes && hubs_string[i] == '>')
                {
                    hubs_string = hubs_string.Remove(i, 1);
                    hubs_string = hubs_string.Insert(i, "&gt;");
                }

                if (inside_quotes && hubs_string[i] == '')
                {
                    hubs_string = hubs_string.Remove(i, 1);
                    hubs_string = hubs_string.Insert(i, " ");
                }
            }
            //hubs_string = hubs_string.Replace("&", "&amp;");
            //Console.WriteLine(hubs_string);
            //File.WriteAllText("hublist.uncompressed.xml", hubs_string);
            //output.Position = 0;
            ReadXmlStringAsync(hubs_string);

            /*busy = false;
             * if (Completed != null)
             *  Completed(this);*/
        }
        /// <summary>
        /// Async callback for webclients get file operation
        /// ,gets called if the file was retrieved successfully
        /// </summary>
        /// <param name="sender">event sending webclient instance</param>
        /// <param name="e">event arguments of the download operation</param>
        private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled)
                {
                    return;
                }
                if (e.Result.Length <= 0)
                {
                    return;
                }
                string page_string = "";
                page_string = System.Text.Encoding.Default.GetString(e.Result);
                //Console.WriteLine("port page: " + page_string);
                int start = page_string.IndexOf("<strong class=\"");
                if (start != -1)
                {
                    string temp = page_string.Substring(start + "<strong class=\"".Length);
                    int    end  = temp.IndexOf("\"");
                    if (end != -1)
                    {
                        string tcp = temp.Substring(0, end);
                        if (tcp == "green small")
                        {
                            OpenPorts = Ports.Tcp;
                        }
                        else
                        {
                            OpenPorts = Ports.None;
                        }

                        start = temp.IndexOf("<strong class=\"");
                        if (start != -1)
                        {
                            string temp2 = temp.Substring(start + "<strong class=\"".Length);
                            end = temp2.IndexOf("\"");
                            if (end != -1)
                            {
                                string udp = temp2.Substring(0, end);
                                if (udp == "green small" && OpenPorts == Ports.None)
                                {
                                    OpenPorts = Ports.Udp;
                                }
                                if (udp == "green small" && OpenPorts == Ports.Tcp)
                                {
                                    OpenPorts = Ports.UdpAndTcp;
                                }

                                busy = false;
                                if (Completed != null)
                                {
                                    Completed(this);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception out_ex)
            {
                Console.WriteLine("Exception during download of port page: " + out_ex.Message);
                error_code = Connection.ErrorCodes.Exception;
                if (UnableToFetch != null)
                {
                    UnableToFetch(this);
                }
            }
        }
        /// <summary>
        /// Async callback for webclients get file operation
        /// ,gets called if the file was retrieved successfully
        /// </summary>
        /// <param name="sender">event sending webclient instance</param>
        /// <param name="e">event arguments of the download operation</param>
        private void DownloadFileCallback(object sender, DownloadDataCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled) return;
                //ASCIIEncoding ascii = new ASCIIEncoding();
                //UTF8Encoding utf = new UTF8Encoding();
                //string page_string = utf.GetString(e.Result);
                if (e.Result.Length <= 0) return;

                string page_string = "";
                try
                {
                    page_string = System.Text.Encoding.Default.GetString(e.Result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception after download: " + ex.Message);
                    return;
                }

                int start = page_string.IndexOf("<h1>Your IP address is<BR>\n");
                if (start != -1)
                {
                    string temp_ip = page_string.Substring(start + "<h1>Your IP address is<BR>".Length);
                    int end = temp_ip.IndexOf("</h1>");
                    if (end != -1)
                    {
                        temp_ip = temp_ip.Substring(0, end);
                        char[] trims = { '\n', ' ' };
                        temp_ip = temp_ip.Trim(trims);

                        //Console.WriteLine("temp_ip: '"+temp_ip+"'");
                        my_ip = temp_ip;
                        busy = false;
                        try
                        {
                            if (Completed != null)
                                Completed(this);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Exception during callback of own external ip resolve: " + ex.Message);
                        }
                    }
                }
            }
            catch (Exception out_ex)
            {
                Console.WriteLine("Exception during download of ip page: "+out_ex.Message);
                error_code = Connection.ErrorCodes.Exception;
                if (UnableToFetch != null)
                    UnableToFetch(this);

            }
        }