with GNAT.Regexp;
with GNAT.Calendar.Time_IO;

with Ada.Calendar;
with Ada.Exceptions;
5with Ada.Text_IO;
with Ada.Text_IO.Editing;
with Ada.Characters.Latin_9;

with AWS.Dispatchers.Callback;
10with AWS.Messages;
with AWS.MIME;
with AWS.Parameters;
with AWS.Response;
with AWS.Session;
15with AWS.Status;
with AWS.Templates;

with Bookstore.Books;
with Bookstore.Carts;
20with Bookstore.Cart_Items;
with Bookstore.Cart_Items.Lists;
with Bookstore.Exceptions;
with Bookstore.Messages.Localize;

25with Bookstore_2.Book_DAO;

package body Bookstore_2.Requests_Processing is

   package Msg renames Bookstore.Messages.Localize;
30
   --
   -- todo : catch exceptions raised by book_dao
   --

35   ----------------------
   -- constant strings --
   ----------------------

   -- prefixes used in url
40
   Image_Web_Prefix : constant String := "/images/";
   Page_Web_Prefix  : constant String := "/books/";

   -- prefixes used internally
45
   Image_Local_Prefix : constant String := "web/img/";
   Page_Local_Prefix : constant String := "web/books/";

   -- images names
50
   Image_Adains_Name   : constant String := "adains.png";
   Image_Aws_Logo_Name : constant String := "aws_logo.png";

   -- pages names
55
   Store    : constant String := "bookstore";
   Catalog  : constant String := "bookcatalog";
   Details  : constant String := "bookdetails";
   Showcart : constant String := "bookshowcart";
60   Cashier  : constant String := "bookcashier";
   Receipt  : constant String := "bookreceipt";

   -- extension used for template files
   Ext : constant String := ".thtml";
65
   --------------------------
   -- web pages processing --
   --------------------------

70   -- welcome page
   function Page_Store (Request : in AWS.Status.Data) return AWS.Response.Data;

   -- all books
   function Page_Catalog (Request : in AWS.Status.Data)
75                         return AWS.Response.Data;

   -- data about a book
   function Page_Details (Request : in AWS.Status.Data)
                         return AWS.Response.Data;
80
   -- cart content
   function Page_Showcart (Request : in AWS.Status.Data)
                          return AWS.Response.Data;

85   -- form to buy
   function Page_Cashier (Request : in AWS.Status.Data)
                         return AWS.Response.Data;

   -- receipt send after buying
90   function Page_Receipt (Request : in AWS.Status.Data)
                         return AWS.Response.Data;

   ----------------------
   -- image processing --
95   ----------------------

   function Image_Adains (Request : in AWS.Status.Data)
                         return AWS.Response.Data;

100   function Image_Aws_Logo (Request : in AWS.Status.Data)
                           return AWS.Response.Data;

   function Process_Image (Image : in String) return AWS.Response.Data;

105   -----------------------
   -- Unknown_Resources --
   -----------------------

   function Unknown_Resources
110     (Request : in AWS.Status.Data) return AWS.Response.Data;

   -------------
   -- Process --
   -------------
115
   procedure Process
     (H : in out AWS.Services.Dispatchers.URI.Handler) is

      package URI renames AWS.Services.Dispatchers.URI;
120
   begin
      -- dispatches requests for web pages

      URI.Register_Regexp (H, Page_Web_Prefix & Store & ".*",
125                           Page_Store'Access);
      URI.Register_Regexp (H, Page_Web_Prefix & Cashier & ".*",
                           Page_Cashier'Access);
      URI.Register_Regexp (H, Page_Web_Prefix & Catalog & ".*",
                           Page_Catalog'Access);
130      URI.Register_Regexp (H, Page_Web_Prefix & Details & ".*",
                           Page_Details'Access);
      URI.Register_Regexp (H, Page_Web_Prefix & Showcart & ".*",
                           Page_Showcart'Access);
      URI.Register_Regexp (H, Page_Web_Prefix & Receipt & ".*",
135                           Page_Receipt'Access);

      -- dispatches requests for images

      URI.Register (H, Image_Web_Prefix & Image_Adains_Name,
140                    Image_Adains'Access);
      URI.Register (H, Image_Web_Prefix & Image_Aws_Logo_Name,
                    Image_Aws_Logo'Access);

      -- unknown resources
145
      URI.Register_Default_Callback
        (H, AWS.Dispatchers.Callback.Create (Unknown_Resources'Access));
   end Process;

150   ---------------------------------
   -- used for session management --
   ---------------------------------

   package Session_Cart is new AWS.Session.Generic_Data
155     (Data      => Bookstore.Carts.Shopping_Cart,
      Null_Data => Bookstore.Carts.Empty_Cart);


   use Bookstore.Messages; -- xxx_key
160
   ----------------
   -- Page_Store --
   ----------------

165   function Page_Store
     (Request : in AWS.Status.Data) return AWS.Response.Data is

      Book_ID : constant String := "203"; -- id used in the web page

170      B : constant Bookstore.Books.Book :=
        Book_DAO.Get_Book (Book_ID);

      use AWS.Templates; -- function Assoc
      use Bookstore.Books.Strings; -- function To_String
175      Translations : constant AWS.Templates.Translate_Table :=
        (Assoc ("LANG", "en"), -- used by header.thtml
         Msg.Association (What_Key),
         Msg.Association (Talk_Key),
         Assoc ("BOOK_TITLE", To_String (B.Get_Title)),
180         Msg.Association (Start_Key));

   begin
      return AWS.Response.Build
        (AWS.MIME.Text_Html,
185         String '(AWS.Templates.Parse
                    (Page_Local_Prefix & Store & Ext, Translations)));
   end Page_Store;

   ------------------
190   -- page_catalog --
   ------------------

   function Page_Catalog
     (Request : in AWS.Status.Data) return AWS.Response.Data is
195
      Session_ID : constant AWS.Session.ID := AWS.Status.Session (Request);
      Translations : AWS.Templates.Translate_Set;

      use AWS.Templates; -- procedure Insert
200                         -- function Assoc
   begin

  Add_Book: -- if the url has the parameter 'Add', there's a book to buy
      declare
205         P : constant AWS.Parameters.List := AWS.Status.Parameters (Request);
         Cart : Bookstore.Carts.Shopping_Cart
           := Session_Cart.Get (Session_ID, "cart");
         Book : Bookstore.Books.Book;

210         use Bookstore.Books.Strings; -- function To_String
      begin
         if P.Exist ("Add") and then P.Get ("Add") /= "" then
            Book := Book_DAO.Get_Book (P.Get ("Add"));
            Cart.Add (Book.Get_ID, Book);
215            Session_Cart.Set (Session_ID, "cart", Cart);

            Insert (Translations, Msg.Association (Cart_Added_1_Key));
            Insert (Translations, Msg.Association (Cart_Added_2_Key));
            Insert (Translations, Assoc
220                      ("ADDED_BOOK_TITLE", To_String (Book.Get_Title)));
         end if;
      end Add_Book;

  Get_Cart: -- gets the size of the cart
225      declare
         Cart : constant Bookstore.Carts.Shopping_Cart
           := Session_Cart.Get (Session_ID, "cart");
      begin
         Insert (Translations, Msg.Association (Cart_Check_Key));
230         Insert (Translations, Msg.Association (Buy_Key));
         Insert (Translations, Assoc
                   ("SIZE_OF_CART", Integer (Cart.Get_Number_Of_Items)));
      end Get_Cart;

235  Get_All_Books: -- retrieves data of all books
      declare
         Books_ID         : AWS.Templates.Vector_Tag;
         Books_Title      : AWS.Templates.Vector_Tag;
         Books_Price      : AWS.Templates.Vector_Tag;
240         Books_First_Name : AWS.Templates.Vector_Tag;
         Books_Surname    : AWS.Templates.Vector_Tag;

         All_Books : constant Bookstore.Books.Book_Array := Book_DAO.Get_Books;

245         use type AWS.Templates.Tag;
         use Bookstore.Books.Strings; -- function To_String
      begin
         Insert (Translations, Msg.Association (Choose_Key));
         Insert (Translations, Msg.Association (Cart_Add_Key));
250         Insert (Translations, Msg.Association (By_Key));

         for I in All_Books'First .. All_Books'Last loop
            Books_ID := Books_ID
              & To_String (All_Books (I).Get_ID);
255            Books_Title := Books_Title
              & To_String (All_Books (I).Get_Title);
            Books_Price := Books_Price
              & Msg.To_String (All_Books (I).Get_Price);
            Books_First_Name := Books_First_Name
260              & To_String (All_Books (I).Get_First_Name);
            Books_Surname := Books_Surname
              & To_String (All_Books (I).Get_Surname);
         end loop;

265         Insert (Translations, Assoc ("BOOK_ID", Books_ID));
         Insert (Translations, Assoc ("BOOK_TITLE", Books_Title));
         Insert (Translations, Assoc ("BOOK_PRICE", Books_Price));
         Insert (Translations, Assoc ("BOOK_FIRST_NAME", Books_First_Name));
         Insert (Translations, Assoc ("BOOK_SURNAME", Books_Surname));
270      end Get_All_Books;

      return AWS.Response.Build (AWS.MIME.Text_Html,
                                 String '(AWS.Templates.Parse
                                            (Page_Local_Prefix & Catalog & Ext,
275                                             Translations)));
   end Page_Catalog;

   ------------------
   -- Page_Details --
280   ------------------

   function Page_Details
     (Request : in AWS.Status.Data) return AWS.Response.Data
   is
285      P : constant AWS.Parameters.List := AWS.Status.Parameters (Request);

      use AWS.Templates; -- function Assoc
   begin

290      if P.Exist ("bookId") then

     Get_Book_Data:
         declare
            Book : constant Bookstore.Books.Book
295              := Book_DAO.Get_Book (P.Get ("bookId"));

            use type Bookstore.Books.Value;

            use Bookstore.Books.Strings; -- function To_String
300            Translations : constant AWS.Templates.Translate_Table :=
              (-- used by header.thtml
               Assoc ("LANG", "en"),

               -- book's data
305               Assoc ("BOOK_ID", To_String (Book.Get_ID)),
               Assoc ("BOOK_TITLE", To_String (Book.Get_Title)),
               Assoc ("BOOK_FIRSTNAME", To_String (Book.Get_First_Name)),
               Assoc ("BOOK_SURNAME", To_String (Book.Get_Surname)),
               Assoc ("BOOK_CALENDAR_YEAR", Integer (Book.Get_Calendar_Year)),
310               Assoc ("BOOK_DESCRIPTION", To_String (Book.Get_Description)),
               Assoc ("BOOK_PRICE", Msg.To_String (Book.Get_Price)),

               -- messages
               Msg.Association (By_Key),
315               Msg.Association (Critics_Key),
               Msg.Association (Item_Price_Key),
               Msg.Association (Cart_Add_Key),
               Msg.Association (Continue_Shopping_Key));

320            Response : constant String
              := String '(AWS.Templates.Parse
                            (Page_Local_Prefix & Details & Ext,
                             Translations));
         begin
325            return AWS.Response.Build (AWS.MIME.Text_Html, Response);
         end Get_Book_Data;

      else
         return AWS.Response.Build
330           (AWS.MIME.Text_Html,
            String '(AWS.Templates.Parse
                       (Page_Local_Prefix & Details & Ext)));
      end if;
   end Page_Details;
335
   -------------------
   -- Page_Showcart --
   -------------------

340   function Page_Showcart
     (Request : in AWS.Status.Data) return AWS.Response.Data is
      Session_ID : constant AWS.Session.ID := AWS.Status.Session (Request);
      Translations : AWS.Templates.Translate_Set;
      Cart : Bookstore.Carts.Shopping_Cart
345        := Session_Cart.Get (Session_ID, "cart");

      use AWS.Templates; -- procedure Insert
                         -- function Assoc

350   begin

  Process_Parameters:
      declare
         P : constant AWS.Parameters.List := AWS.Status.Parameters (Request);
355      begin
         if P.Exist ("Clear") and then P.Get ("Clear") = "clear" then
            Cart.Clear;
            Session_Cart.Set (Session_ID, "cart", Cart);
            Insert (Translations, Msg.Association (Cart_Cleared_Key));
360         end if;

         if P.Exist ("Remove") then
            declare
               Book : constant Bookstore.Books.Book
365                 := Book_DAO.Get_Book (P.Get ("Remove"));
               use Bookstore.Books.Strings; -- function To_String
            begin
               Cart.Remove (Book.Get_ID);
               Session_Cart.Set (Session_ID, "cart", Cart);
370
               Insert (Translations, Msg.Association (Cart_Removed_Key));
               Insert (Translations,
                       Assoc ("REMOVED_BOOK_TITLE",
                              To_String (Book.Get_Title)));
375            exception
               when Error : Bookstore.Exceptions.Book_Not_Found_Exception =>
                  -- todo : book to remove was not found by Book_DAO
                  Ada.Exceptions.Reraise_Occurrence (Error);
            end;
380         end if;
      end Process_Parameters;

  Cart_Content:
      declare
385         Number : constant Natural := Natural (Cart.Get_Number_Of_Items);

         Item_Quantity : AWS.Templates.Vector_Tag;
         Books_ID : AWS.Templates.Vector_Tag;
         Books_Title : AWS.Templates.Vector_Tag;
390         Books_Price : AWS.Templates.Vector_Tag;

         package Lists renames Bookstore.Cart_Items.Lists;
         All_Books : constant Lists.List := Cart.Get_Items;

395         procedure Process_Book (Position : Lists.Cursor) is
            Cart_Item : Bookstore.Cart_Items.Shopping_Cart_Item
              := Lists.Element (Position);
            use Bookstore.Books.Strings; -- function To_String
         begin
400            Item_Quantity := Item_Quantity & Integer (Cart_Item.Get_Quantity);
            Books_ID := Books_ID
              & To_String (Cart_Item.Get_Item.Get_ID);
            Books_Title := Books_Title
              & To_String (Cart_Item.Get_Item.Get_Title);
405            Books_Price := Books_Price
              & Msg.To_String (Cart_Item.Get_Item.Get_Price);
         end Process_Book;

      begin
410         Insert (Translations, Assoc ("CART_NUMBER_OF_ITEMS", Number));
         Insert (Translations, Msg.Association (Cart_Contents_Key));
         Insert (Translations, Msg.Association (Cart_Item_Key));
         Insert (Translations, Msg.Association (Cart_Items_Key));

415         Insert (Translations, Msg.Association (Item_Quantity_Key));
         Insert (Translations, Msg.Association (Item_Title_Key));
         Insert (Translations, Msg.Association (Item_Price_Key));

         All_Books.Iterate (Process_Book'Access);
420         Insert (Translations, Assoc ("ITEM_QUANTITY", Item_Quantity));
         Insert (Translations, Assoc ("BOOK_ID", Books_ID));
         Insert (Translations, Assoc ("BOOK_TITLE", Books_Title));
         Insert (Translations, Assoc ("BOOK_PRICE", Books_Price));

425         Insert (Translations, Msg.Association (Remove_Item_Key));

         Insert (Translations, Msg.Association (Subtotal_Key));
         Insert (Translations,
                 Assoc ("CART_TOTAL", Msg.To_String (Cart.Get_Total)));
430      end Cart_Content;

      Insert (Translations, Msg.Association (Continue_Shopping_Key));
      Insert (Translations, Msg.Association (Checkout_Key));
      Insert (Translations, Msg.Association (Clear_Cart_Key));
435
      Insert (Translations, Msg.Association (Cart_Empty_Key));
      Insert (Translations, Msg.Association (Catalog_Key));

      return AWS.Response.Build (AWS.MIME.Text_Html,
440                                 String '(AWS.Templates.Parse
                                            (Page_Local_Prefix & Showcart & Ext,
                                             Translations)));

   end Page_Showcart;
445
   ------------------
   -- Page_Cashier --
   ------------------

450   function Page_Cashier
     (Request : in AWS.Status.Data) return AWS.Response.Data is

      Session_ID : constant AWS.Session.ID := AWS.Status.Session (Request);

455      Cart : constant Bookstore.Carts.Shopping_Cart
        := Session_Cart.Get (Session_ID, "cart");

      use AWS.Templates; -- function Assoc
      Translations : constant AWS.Templates.Translate_Table :=
460        (Assoc ("LANG", "en"),
         Msg.Association (Amount_Key),
         Assoc ("CART_TOTAL", Msg.To_String (Cart.Get_Total)),
         Msg.Association (Purchase_Key),
         Msg.Association (Name_Key),
465         Msg.Association (CC_Number_Key),
         Msg.Association (Submit_Key));

   begin
      return AWS.Response.Build
470        (AWS.MIME.Text_Html,
         String '(AWS.Templates.Parse (Page_Local_Prefix & Cashier & Ext,
                                       Translations)));
   end Page_Cashier;

475   ------------------
   -- Page_Receipt --
   ------------------

   function Page_Receipt
480     (Request : in AWS.Status.Data) return AWS.Response.Data is

      P : constant AWS.Parameters.List := AWS.Status.Parameters (Request);

      use type Ada.Calendar.Time;
485      Now : Ada.Calendar.Time := Ada.Calendar.Clock
        + Ada.Calendar.Day_Duration'Last * 5;

      use AWS.Templates; -- function Assoc
      use GNAT.Calendar.Time_IO; -- function Image
490                                 -- constant ISO_Date
      Translations : constant AWS.Templates.Translate_Table :=
        (Assoc ("LANG", "en"),
         Msg.Association (Thank_You_Key),
         Assoc ("CARD_NAME", P.Get ("cardname")),
495         Msg.Association (Ship_Date_Key),
         Assoc ("NOW", Msg.To_String (Now)),
         Msg.Association (Continue_Shopping_Key));

      Session_ID : constant AWS.Session.ID := AWS.Status.Session (Request);
500   begin
      AWS.Session.Remove (Session_ID, "cart");

      return AWS.Response.Build
        (AWS.MIME.Text_Html,
505         String '(AWS.Templates.Parse (Page_Local_Prefix & Receipt & Ext,
                                       Translations)));
   end Page_Receipt;

   -------------------
510   -- Process_Image --
   -------------------

   function Process_Image (Image : in String) return AWS.Response.Data is
   begin
515      return AWS.Response.File (AWS.MIME.Image_Png, Image_Local_Prefix & Image);
   end Process_Image;

   ------------------
   -- Image_Adains --
520   ------------------

   function Image_Adains (Request : in AWS.Status.Data)
                         return AWS.Response.Data is
   begin
525      return Process_Image (Image_Adains_Name);
   end Image_Adains;

   --------------------
   -- Image_Aws_Logo --
530   --------------------

   function Image_Aws_Logo (Request : in AWS.Status.Data)
                           return AWS.Response.Data is
   begin
535      return Process_Image (Image_Aws_Logo_Name);
   end Image_Aws_Logo;

   -----------------------
   -- Unknown_Resources --
540   -----------------------

   function Unknown_Resources
     (Request : in AWS.Status.Data) return AWS.Response.Data is
   begin
545      return AWS.Response.Acknowledge
        (Status_Code => AWS.Messages.S404,
         Message_Body => "The requested resource doesn't exist: "
           & AWS.Status.URI (Request),
         Content_Type => AWS.MIME.Text_Plain);
550   end Unknown_Resources;

end Bookstore_2.Requests_Processing;

top