BEGIN;
SET search_path TO donau;
CREATE OR REPLACE FUNCTION amount_normalize(
    IN amount taler_amount
  ,OUT normalized taler_amount
)
LANGUAGE plpgsql
AS $$
BEGIN
  normalized.val = amount.val + amount.frac / 100000000;
  normalized.frac = amount.frac % 100000000;
END $$;
COMMENT ON FUNCTION amount_normalize
  IS 'Returns the normalized amount by adding to the .val the value of (.frac / 100000000) and removing the modulus 100000000 from .frac.';
CREATE OR REPLACE FUNCTION amount_add(
   IN a taler_amount
  ,IN b taler_amount
  ,OUT sum taler_amount
)
LANGUAGE plpgsql
AS $$
BEGIN
  sum = (a.val + b.val, a.frac + b.frac);
  SELECT * FROM amount_normalize(sum) INTO sum;
  IF (sum.val > (1<<52))
  THEN
    RAISE EXCEPTION 'addition overflow';
  END IF;
END $$;
COMMENT ON FUNCTION amount_add
  IS 'Returns the normalized sum of two amounts. It raises an exception when the resulting .val is larger than 2^52';
CREATE OR REPLACE FUNCTION amount_left_minus_right(
  IN l taler_amount
 ,IN r taler_amount
 ,OUT diff taler_amount
 ,OUT ok BOOLEAN
)
LANGUAGE plpgsql
AS $$
BEGIN
IF (l.val > r.val)
THEN
  ok = TRUE;
  IF (l.frac >= r.frac)
  THEN
    diff.val = l.val - r.val;
    diff.frac = l.frac - r.frac;
  ELSE
    diff.val = l.val - r.val - 1;
    diff.frac = l.frac + 100000000 - r.frac;
  END IF;
ELSE
  IF (l.val = r.val) AND (l.frac >= r.frac)
  THEN
    diff.val = 0;
    diff.frac = l.frac - r.frac;
    ok = TRUE;
  ELSE
    diff = (-1, -1);
    ok = FALSE;
  END IF;
END IF;
RETURN;
END $$;
COMMENT ON FUNCTION amount_left_minus_right
  IS 'Subtracts the right amount from the left and returns the difference and TRUE, if the left amount is larger than the right, or an invalid amount and FALSE otherwise.';
DROP FUNCTION IF EXISTS do_insert_submitted_receipts;
CREATE FUNCTION do_insert_submitted_receipts(
  IN in_h_tax_number BYTEA,
  IN ina_h_donation_unit_pubs BYTEA[],
  IN ina_nonces BYTEA[],
  IN ina_donation_unit_sigs BYTEA[],
  IN in_donation_year INT8,
  OUT out_conflict BOOL[]
 )
LANGUAGE plpgsql
AS $$
DECLARE
  i INT4;
  ini_nonce BYTEA;
  ini_h_donation_unit_pub BYTEA;
  ini_donation_unit_sig BYTEA;
BEGIN
FOR i IN 1..array_length(ina_h_donation_unit_pubs,1)
LOOP
  ini_nonce = ina_nonces[i];
  ini_h_donation_unit_pub = ina_h_donation_unit_pubs[i];
  ini_donation_unit_sig = ina_donation_unit_sigs[i];
  out_conflict[i] = FALSE;
  INSERT INTO receipts_submitted
    (h_tax_number
    ,nonce
    ,h_donation_unit_pub
    ,donation_unit_sig
    ,donation_year
    )
    VALUES
    (in_h_tax_number
    ,ini_nonce
    ,ini_h_donation_unit_pub
    ,ini_donation_unit_sig
    ,in_donation_year
    )
    ON CONFLICT DO NOTHING;
  IF NOT FOUND
  THEN
    PERFORM FROM receipts_submitted
      WHERE h_tax_number=in_h_tax_number
        AND donation_unit_sig=ini_donation_unit_sig; 
    out_conflict[i] = NOT FOUND;
  END IF;
END LOOP; 
END $$;
CREATE OR REPLACE FUNCTION do_insert_issued_receipts (
  IN in_charity_id BIGINT 
  ,IN in_blinded_sig BYTEA[] 
  ,IN in_receipt_hash BYTEA 
  ,IN in_amount taler_amount 
  ,OUT out_smaller_than_max_per_year BOOLEAN
)
LANGUAGE plpgsql
AS $$
DECLARE
  old_receipts_to_date taler_amount;
  new_receipts_to_date taler_amount;
  max_per_year taler_amount;
BEGIN
  SELECT
     (chari.receipts_to_date).val
    ,(chari.receipts_to_date).frac
    ,(chari.max_per_year).val
    ,(chari.max_per_year).frac
   INTO
      old_receipts_to_date.val
     ,old_receipts_to_date.frac
     ,max_per_year.val
     ,max_per_year.frac
   FROM charities chari
   WHERE charity_id=in_charity_id;
  SELECT *
    FROM amount_add(old_receipts_to_date, in_amount)
    INTO new_receipts_to_date;
  IF ( (max_per_year.val > new_receipts_to_date.val) OR
       ( (max_per_year.val = new_receipts_to_date.val) AND
         (max_per_year.frac > new_receipts_to_date.frac) ) )
  THEN
    out_smaller_than_max_per_year=TRUE;
    UPDATE charities
      SET receipts_to_date=new_receipts_to_date
      WHERE charity_id=in_charity_id;
    INSERT INTO receipts_issued (blinded_sig, charity_id, receipt_hash, amount)
      VALUES (in_blinded_sig, in_charity_id, in_receipt_hash, in_amount);
  ELSE
    out_smaller_than_max_per_year=FALSE;
  END IF;
END $$;
COMMIT;
COMMENT ON FUNCTION do_insert_issued_receipts
  IS 'This is a transaction for updating the current amount of receipts of a year of a charity and saves the receipts request what makes it idempotent';
DROP FUNCTION IF EXISTS do_insert_charity;
CREATE FUNCTION do_insert_charity (
   IN in_charity_pub BYTEA
  ,IN in_charity_name TEXT
  ,IN in_charity_url TEXT
  ,IN in_max_per_year taler_amount
  ,IN in_current_year INT4
  ,OUT out_charity_id INT8
)
LANGUAGE plpgsql
AS $$
BEGIN
  INSERT INTO charities
    (charity_pub
    ,charity_name
    ,charity_url
    ,max_per_year
    ,current_year
   ) VALUES (
    in_charity_pub
   ,in_charity_name
   ,in_charity_url
   ,in_max_per_year
   ,in_current_year)
   ON CONFLICT DO NOTHING
   RETURNING charity_id
        INTO out_charity_id;
  IF NOT FOUND
  THEN
    SELECT charity_id
      INTO out_charity_id
      FROM charities
     WHERE charity_pub=in_charity_pub
       AND charity_url=in_charity_url
       AND charity_name=in_charity_name
       AND max_per_year=in_max_per_year;
   IF NOT FOUND
   THEN
     out_charity_id = 0;
   END IF;
 END IF;
END $$;
COMMIT;
COMMENT ON FUNCTION do_insert_charity
  IS 'Insert a charity. Also succeeds if a charity with the same parameters already exists. If a conflicting charity exists, the out_charity_id is set to 0.';
COMMIT;
