using System.Collections.Generic;
using System.Threading.Tasks;
public string Url { get; set; }
public string CurrentPrice { get; set; }
public string ProductStatus { get; set; }
public string LastCheck { get; set; }
public bool HasChanged { get; set; }
private Dictionary<string, Product> products;
private readonly string dataFile = "product_data.json";
private readonly HttpClient client;
client = new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
if (File.Exists(dataFile))
string jsonString = File.ReadAllText(dataFile);
products = JsonSerializer.Deserialize<Dictionary<string, Product>>(jsonString);
products = new Dictionary<string, Product>();
string jsonString = JsonSerializer.Serialize(products, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(dataFile, jsonString);
public async Task<(string price, string status)> CheckProduct(string url)
var response = await client.GetStringAsync(url);
var doc = new HtmlDocument();
var priceElement = doc.DocumentNode.SelectSingleNode("//div[contains(@class, 'listing-details-heading large-now-price with-sale')]");
string price = priceElement?.InnerText.Trim() ?? "Price not found";
var specialOfferIcon = doc.DocumentNode.SelectSingleNode("//img[@class='special-offer-icon']");
string status = "REGULAR";
if (specialOfferIcon != null)
string src = specialOfferIcon.GetAttributeValue("src", "");
if (src.Contains("RIBBONS_FINAL-19.png"))
status = "SPECIAL OFFER";
else if (src.Contains("RIBBONS_FINAL-18.png"))
status = "UNKNOWN OFFER";
Console.WriteLine($"Error checking product: {ex.Message}");
public void AddProduct(string productCode, string url)
if (!products.ContainsKey(productCode))
products[productCode] = new Product
Console.WriteLine($"Added new product: {productCode}");
Console.WriteLine($"Product {productCode} already exists");
public void RemoveProduct(string productCode)
if (products.Remove(productCode))
Console.WriteLine($"Removed product: {productCode}");
Console.WriteLine($"Product {productCode} not found");
public async Task UpdateProducts()
string currentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
foreach (var (productCode, data) in products)
Console.WriteLine($"\nChecking product: {productCode}");
var (price, status) = await CheckProduct(data.Url);
if (price != null && status != null)
bool hasChanged = price != data.CurrentPrice || status != data.ProductStatus;
Console.WriteLine($"CHANGE DETECTED for {productCode}:");
if (price != data.CurrentPrice)
Console.WriteLine($"Price changed: {data.CurrentPrice} -> {price}");
if (status != data.ProductStatus)
Console.WriteLine($"Status changed: {data.ProductStatus} -> {status}");
data.CurrentPrice = price;
data.ProductStatus = status;
data.LastCheck = currentTime;
data.HasChanged = hasChanged;
Console.WriteLine($"\nUpdate completed at {currentTime}");
public void DisplayStatus()
Console.WriteLine("\nNo products being tracked. Use option 1 to add products.");
Console.WriteLine("\nCurrent Product Status:");
Console.WriteLine(new string('-', 80));
foreach (var (productCode, data) in products)
string status = data.HasChanged ? "CHANGED" : "NO CHANGE";
Product Code: {productCode}
Price: {data.CurrentPrice}
Status: {data.ProductStatus}
Last Check: {data.LastCheck}
var tracker = new ProductTracker();
Console.WriteLine("\nProduct Price Tracker");
Console.WriteLine("1. Add product");
Console.WriteLine("2. Remove product");
Console.WriteLine("3. Check all products");
Console.WriteLine("4. Display current status");
Console.WriteLine("5. Start monitoring (checks every hour)");
Console.WriteLine("6. Exit");
Console.Write("\nEnter your choice (1-6): ");
string choice = Console.ReadLine();
Console.Write("Enter product code: ");
string code = Console.ReadLine();
Console.Write("Enter product URL: ");
string url = Console.ReadLine();
tracker.AddProduct(code, url);
Console.Write("Enter product code to remove: ");
tracker.RemoveProduct(Console.ReadLine());
await tracker.UpdateProducts();
Console.WriteLine("Starting monitoring (Press Ctrl+C to stop)...");
await tracker.UpdateProducts();
Console.WriteLine("\nWaiting for 1 hour...");
for (int i = 0; i < 60; i++)
Console.Write($"\rNext check in {60 - i} minutes...");
catch (OperationCanceledException)
Console.WriteLine("\nMonitoring stopped");
Console.WriteLine("Exiting...");
Console.WriteLine("Invalid choice. Please try again.");
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine("Please try again.");