-- computerman is multiway user tools.
-- Computerman is Copyright (C) 2024 Manuel De Girardi ; 
--
--   This program is free software; you can redistribute it and/or modify
--   it under the terms of the GNU General Public License as published by
--   the Free Software Foundation; either version 2 of the License, or
--   (at your option) any later version.
--
--   This program is distributed in the hope that it will be useful,
--   but WITHOUT ANY WARRANTY; without even the implied warranty of
--   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--   GNU General Public License for more details.
--
--   You should have received a copy of the GNU General Public License
--   along with this program; if not, write to the Free Software
--   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
--
-- Date := "2024-05-10 09:03:04"
-- Version := "0.0.0r"
with Ada.Calendar.Formatting;
package body Computer.Tools is
   procedure Difference_In_Years(Top_Date : in Time;
				 Bot_Date : in Time;
                                 Years    : out Natural;
                                 Months   : out Natural;
                                 Days     : out Natural;
                                 Houres   : out Natural;
                                 Minutes  : out Natural;
                                 Second   : out Natural;
                                 Rest     : out Duration) is      
      
      function Is_Leap_Year (Year : Integer) return Boolean is
      begin
         return (Year rem 4 = 0) and ((Year rem 100 /= 0) or (Year rem 16 = 0));
      end Is_Leap_Year;
      
      pragma Inline (Is_Leap_Year);
      
      Days_Months_Count : constant array (Month_Number) of Day_Number := (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
      
      
      function Last_Days(Years , Months : in Natural) return Natural is         
      begin         
         if Months = 1 then
            return Days_Months_Count(12);
         elsif Months /= 3 then
            return Days_Months_Count(Months-1);
	 elsif Is_Leap_Year(Years) then
            return Days_Months_Count(2) + 1;
         else
            return Days_Months_Count(2);
         end if;
      end Last_Days;

      
      Top_Seconds : constant Day_Duration := Seconds(Top_Date);
      Bot_Seconds : constant Day_Duration := Seconds(Bot_Date);
      Top_Day     : constant Day_Number := Day(Top_Date);
      Bot_Day     : constant Day_Number := Day(Bot_Date);
      Top_Year    : constant Year_Number := Year(Top_Date);
      Bot_Year    : constant Year_Number := Year(Bot_Date);
      Top_Month   : constant Month_Number := Month(Top_Date);
      Bot_Month   : constant Month_Number := Month(Bot_Date);
      
      Years_Number  : Integer := 0;
      Months_Number : Integer := 0;
      Days_Number   : Integer := 0;            
      
      Total_Duration : Duration := Bot_Seconds - Top_Seconds;
   begin
      
      if Top_Date > Bot_Date then
         raise Constraint_Error;
      end if;
      
      Years    := 0;
      Months   := 0;
      Days     := 0;
      Houres   := 0;
      Minutes  := 0;
      Second   := 0;
      Rest     := 0.0;
      
      Years_Number := (Bot_Year - Top_Year - 1);
      
      Months_Number := Bot_Month;
      
      if (Bot_Month > Top_Month) or ((Bot_Month = Top_Month) and (Bot_Day >= Top_Day)) then         

         Years_Number := Years_Number + 1;
         
      else         
         Months_Number := Bot_Month + 12;
      end if;
      
      Months_Number := (Months_Number - Top_Month - 1);
      
      if Bot_Day >= Top_Day then

         Months_Number := Months_Number + 1;
         Days_Number := Bot_Day - Top_Day;
      else
         Days_Number := Last_Days (Bot_Year, Bot_Month);
	 Days_Number := Days_Number - Top_Day;
	 Days_Number := Days_Number + Bot_Day;
      end if;
      Days := Days_Number;
      Months := Months_Number;
      Years := Years_Number;
      
      if Bot_Seconds >= Top_seconds then
         Total_Duration := (Bot_Seconds - Top_Seconds);
      else
         Total_Duration := (86400.0 - Top_Seconds) + Bot_Seconds;
         Days := Days - 1;
      end if;
      Formatting.Split(Total_Duration, Houres, Minutes, Second, Rest);         
   end Difference_In_Years;
end Computer.Tools ;