/* Extracts the order from an grubhub html file and returns an Order object */
        public Order ParseOrder(string html, DateTime dateTime, string messageId)
        {
            Order order = new Order();

            order.Service      = "GrubHub";
            order.TimeReceived = dateTime;
            order.MessageId    = messageId;

            var htmlDoc = new HtmlDocument();

            htmlDoc.LoadHtml(html);

            //We begin setting the possible locations of the relevant information, and then choose which one depending on the format on the html doc
            string metaInfoLoc1 = "//body/table/tbody/tr/td/table/tbody/tr/td/table[3]/tbody/tr/th[2]/table/tbody/tr/th/div/div[2]/div/div";
            string metaInfoLoc2 = "//body/table/tbody/tr/td/table/tbody/tr/td/table[4]/tbody/tr/th[2]/table/tbody/tr/th/div/div/div/div";
            string metaInfoLoc3 = "//body/table/tbody/tr/td/table/tbody/tr/td/table[5]/tbody/tr/th[2]/table/tbody/tr/th/div/div/div/div";

            string metaInfoBaseLoc1 = "//body/table/tbody/tr/td/table/tbody/tr/td/table[3]";
            string metaInfoBaseLoc2 = "//body/table/tbody/tr/td/table/tbody/tr/td/table[4]";
            string metaInfoBaseLoc3 = "//body/table/tbody/tr/td/table/tbody/tr/td/table[5]";

            string delivMethodLoc1 = @"/tbody/tr/th/table/tbody/tr/th/div/div[2]/div/span/span";
            string delivMethodLoc2 = @"/tbody/tr/th/table/tbody/tr/th/div/div/div/span/span";
            string delivMethodLoc3 = @"/tbody/tr/th/table/tbody/tr/th/div/div/div/span/span";

            string pickUpTimeLoc1 = @"/tbody/tr/th/table/tbody/tr/th/div/div[2]/div[2]/span";
            string pickUpTimeLoc2 = @"/tbody/tr/th/table/tbody/tr/th/div/div/div[2]/span";
            string pickUpTimeLoc3 = @"/tbody/tr/th/table/tbody/tr/th/div/div/div[2]/span";

            HtmlNodeCollection metaInfoNodes      = null;
            HtmlNode           deliveryMethodNode = null;
            HtmlNode           pickupTimeNode     = null;

            //If this is not null, the order is in standard format
            if (htmlDoc.DocumentNode.SelectNodes(metaInfoLoc1) != null)
            {
                //Debug.WriteLine("Using Standard format");
                metaInfoNodes      = htmlDoc.DocumentNode.SelectNodes(metaInfoLoc1);
                deliveryMethodNode = htmlDoc.DocumentNode.SelectSingleNode(metaInfoBaseLoc1 + delivMethodLoc1);
                pickupTimeNode     = htmlDoc.DocumentNode.SelectSingleNode(metaInfoBaseLoc1 + pickUpTimeLoc1);
            }
            //Otherwise the previous loc is null and there's an extra <table> "SCHEDULED ORDER" before the pickup/delivery <table>
            //so we use location 2
            else if (htmlDoc.DocumentNode.SelectNodes(metaInfoLoc2) != null)
            {
                //Debug.WriteLine("Using Scheduled Order format");
                metaInfoNodes      = htmlDoc.DocumentNode.SelectNodes(metaInfoLoc2);
                deliveryMethodNode = htmlDoc.DocumentNode.SelectSingleNode(metaInfoBaseLoc2 + delivMethodLoc2);
                pickupTimeNode     = htmlDoc.DocumentNode.SelectSingleNode(metaInfoBaseLoc2 + pickUpTimeLoc2);
            }
            //Otherwise the previous loc is null and there's also an extra <table> "ORDER ADJUSTMENT" before the relevant <table>
            //so we use location 3
            else if (htmlDoc.DocumentNode.SelectNodes(metaInfoLoc3) != null)
            {
                //Debug.WriteLine("Using Adjusted Order format");
                metaInfoNodes      = htmlDoc.DocumentNode.SelectNodes(metaInfoLoc3);
                deliveryMethodNode = htmlDoc.DocumentNode.SelectSingleNode(metaInfoBaseLoc3 + delivMethodLoc3);
                pickupTimeNode     = htmlDoc.DocumentNode.SelectSingleNode(metaInfoBaseLoc3 + pickUpTimeLoc3);
            }
            //If location 3 is still null, then the format is not recognized
            else
            {
                //Debug.WriteLine("Cannot parse order - format not recognized");
                return(null);
            }

            var orderNumberNode = htmlDoc.DocumentNode.SelectSingleNode("//body/table/tbody/tr/td/table/tbody/tr/td/table[2]/tbody/tr/th/table/tbody/tr/th/div/div[4]/span[2]");

            ParseOrderNumber(orderNumberNode, order);
            ParsePickUpTime(pickupTimeNode, order);

            int metaDivCount     = metaInfoNodes.Count; //the # of <div> elems
            int nonItemCount     = 5;                   //the last 5 <tr>'s of the <tbody> is meta information
            int lastAddressIndex = metaDivCount - 3;

            //We need to know whether it's DELIVERY or PICKUP because there's a difference in the html structure
            if (deliveryMethodNode.InnerHtml.Trim() == "DELIVERY")
            {
                nonItemCount = 6;
            }
            else
            {
                order.DeliveryMethod = "Pickup";
            }

            var pickupByNameNode = metaInfoNodes.ElementAt(1);

            ParsePickupName(pickupByNameNode, order);
            ParseContactNumber(metaInfoNodes.ElementAt(metaDivCount - 1), order);

            var orderContentNodes = htmlDoc.DocumentNode.SelectNodes("//td[@class='orderSummary__data']");
            //order.UniqueItemCount = orderContentNodes.Count - nonItemCount;

            //Loops through all the td nodes with class = "orderSummary__data"
            //Parses itemName from td's with inner structure <div>
            //Parses   addOns from td's with inner structure <div> <ul>
            //Does nothing for td's with no css child nodes
            //Stops parsing when hitting the td with inner node <span>, or when there are no more tdNodes to scan
            bool parsedItemName = false;
            Item item           = null;

            for (int i = 0; i < orderContentNodes.Count; i++)
            {
                var tdNode = orderContentNodes[i];

                string spanNodePath = tdNode.XPath + "/span";
                var    spanNode     = tdNode.SelectSingleNode(spanNodePath);

                if (spanNode != null)
                {
                    //Debug.WriteLine("Hit td with <span> - breaking");
                    break;
                }

                var divNode = tdNode.Element("div");

                if (divNode == null)
                {
                    //Debug.WriteLine("No childs nodes - no addons");
                    continue;
                }

                if (divNode.Element("ul") != null)
                {
                    //Debug.WriteLine("contains addOns");
                    ParseAddOns(divNode.Element("ul"), item);
                }
                else
                {
                    //Since Special Instructions and ItemNames have the same html strucuture,
                    //we need manually check the innerHTML to decide which it is
                    if (divNode.InnerHtml.Trim().StartsWith("Instructions"))
                    {
                        ParseSpecialInstruction(divNode, item);
                    }
                    else
                    {
                        //Debug.WriteLine("is an itemName");
                        if (item != null)
                        {
                            order.ItemList.Add(item); //add the previous item if it's not null, then handle the new item
                        }
                        item = new Item();
                        ParseItemName(divNode, item);
                        ParseQuantity(tdNode, item);
                        ParseItemType(divNode, item);
                    }
                }
                //SetItemCount(i + 1, order.UniqueItemCount, item);
            }
            order.ItemList.Add(item); //add the last item since it won't be added without a next item

            DoorDashParser.SetDrinkAndSnackCount(order);
            DoorDashParser.SetOrderSize(order); //Need to move function to be general
            ParseConfirmURL(order, htmlDoc);
            return(order);
        }