using System.Collections.Generic;
using System.Text.RegularExpressions;
public static void Main()
"1 chocolate bar at 0.85"
"1 imported box of chocolates at 10.00",
"1 imported bottle of perfume at 47.50"
"1 imported bottle of perfume at 27.99",
"1 bottle of perfume at 18.99",
"1 packet of headache pills at 9.75",
"1 box of imported chocolates at 11.25"
Console.WriteLine("--------------------------------------------------");
Console.WriteLine("--------------------------------------------------");
Console.WriteLine("--------------------------------------------------");
private static void ProcessInput(string[] input)
foreach (var item in input)
var shoppringCart = ItemParser.Parse(input);
var taxCalculator = new TaxCalculator();
taxCalculator.Calculate(shoppringCart);
ShopingCartPrinter.Print(shoppringCart);
private static readonly IDictionary<ProductType, string[]> itemType_Identifiers = new Dictionary<ProductType, string[]>
{ProductType.Food, new[]{ "chocolate", "chocolates" }},
{ProductType.Medical, new[]{ "pills" }},
{ProductType.Book, new[]{ "book" }}
public decimal ShelfPrice { get; set; }
public string Name { get; set; }
public bool IsImported { get { return Name.Contains("imported "); } }
public bool IsTypeOf(ProductType productType)
return itemType_Identifiers.ContainsKey(productType) &&
itemType_Identifiers[productType].Any(x => Name.Contains(x));
public override string ToString()
return string.Format("{0} at {1}", Name, ShelfPrice);
abstract public bool IsApplicable(Product item);
abstract public decimal Rate { get; }
public decimal Calculate(Product item)
var tax = (item.ShelfPrice * Rate) / 100;
tax = Math.Ceiling(tax / 0.05m) * 0.05m;
class BasicSalesTax : SalesTax
private ProductType[] _taxExcemptions = new[] { ProductType.Food, ProductType.Medical, ProductType.Book };
public override bool IsApplicable(Product item)
return !(_taxExcemptions.Any(x => item.IsTypeOf(x)));
public override decimal Rate { get { return 10.00M; } }
class ImportedDutySalesTax : SalesTax
public override bool IsApplicable(Product item)
public override decimal Rate { get { return 5.00M; } }
private SalesTax[] _Taxes = new SalesTax[] { new BasicSalesTax(), new ImportedDutySalesTax() };
public void Calculate(ShoppringCart shoppringCart)
foreach (var cartItem in shoppringCart.CartItems)
cartItem.Tax = _Taxes.Sum(x => x.Calculate(cartItem.Product));
public IList<ShoppringCartItem> CartItems { get; set; }
public decimal TotalTax { get { return CartItems.Sum(x => x.Tax); } }
public decimal TotalCost { get { return CartItems.Sum(x => x.Cost); } }
public Product Product { get; set; }
public int Quantity { get; set; }
public decimal Tax { get; set; }
public decimal Cost { get { return Quantity * (Tax + Product.ShelfPrice); } }
public override string ToString()
return string.Format("{0} {1} : {2:N2}", Quantity, Product.Name, Cost);
private static readonly string ITEM_ENTRY_REGEX = "(\\d+) ([\\w\\s]* )at (\\d+.\\d{2})";
private static readonly string[] food_identifier = { "chocolate", "chocolates" };
private static readonly string[] medical_identifier = { "pills" };
private static readonly string[] book_identifier = { "book" };
public static ShoppringCart Parse(string[] listOfItemfullDesc)
CartItems = listOfItemfullDesc.Select(Parse).ToList(),
public static ShoppringCartItem Parse(string itemfullDesc)
var regex = new Regex(ITEM_ENTRY_REGEX);
var match = regex.Match(itemfullDesc);
var quantity = int.Parse(match.Groups[1].Value);
var price = decimal.Parse(match.Groups[3].Value);
var itemName = match.Groups[2].Value.Trim();
var shopp = new ShoppringCartItem
Product = new Product { Name = itemName, ShelfPrice = price }
public static void Print(ShoppringCart shoppringCart)
foreach (var cartItem in shoppringCart.CartItems)
Console.WriteLine(cartItem.ToString());
Console.WriteLine("Taxes: {0:N2}", shoppringCart.TotalTax);
Console.WriteLine("Total: {0:N2}", shoppringCart.TotalCost);