-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION "bgValidators"" to load this file. \quit

-- Function: validate_bulstat(text)
-- DROP FUNCTION validate_bulstat(text);

CREATE OR REPLACE FUNCTION validate_bulstat(bulstat text DEFAULT ''::text)
  RETURNS boolean AS
$BODY$
DECLARE
	i integer;
	checksum integer;
	checkval text;
	bslength integer;
	weights9A integer[] := array[1, 2, 3, 4, 5, 6, 7,  8];
	weights9B integer[] := array[3, 4, 5, 6, 7, 8, 9, 10];
	weights13A integer[] := array[2, 7, 3, 5];
	weights13B integer[] := array[4, 9, 5, 7];
BEGIN
bulstat := LTRIM(RTRIM(bulstat));
bslength := LENGTH(bulstat);
IF NOT ((bulstat ~ '^[\d]{9}$') OR (bulstat ~ '^[\d]{13}$')) THEN	-- 9 or 13 digits
	RETURN FALSE;
END IF;

IF (bslength = 9) THEN
	checksum := 0;
	FOR i IN 1 .. 8 LOOP
		checksum := checksum + CAST(SUBSTR(bulstat, i, 1) AS integer) * weights9A[i];
	END LOOP;
	checksum := checksum % 11;
	IF (checksum <> 10) THEN
		checkval := CAST (checksum AS text);
		RETURN (checkval = SUBSTR(bulstat, 9, 1));
	END IF;
	
	checksum := 0;
	FOR i IN 1 .. 8 LOOP
		checksum := checksum + CAST(SUBSTR(bulstat, i, 1) AS integer) * weights9B[i];
	END LOOP;
	checksum := (checksum % 11) % 10;
	checkval := CAST (checksum AS text);
	RETURN (checkval = SUBSTR(bulstat, 9, 1));
END IF;

IF (bslength = 13) THEN
	IF NOT validate_egn(SUBSTR(bulstat, 1, 9)) THEN
		RETURN FALSE;
	END IF;
	checksum := 0;
	FOR i in 9 .. 12 LOOP
		checksum := checksum + CAST(SUBSTR(bulstat, i, 1) AS integer) * weights13A[i - 8];
	END LOOP;
	checksum := checksum % 11;
	IF (checksum <> 10) THEN
		checkval := CAST (checksum AS text);
		RETURN (checkval = SUBSTR(bulstat, 13, 1));
	END IF;
	
	checksum := 0;
	FOR i in 9 .. 12 LOOP
		checksum := checksum + CAST(SUBSTR(bulstat, i, 1) AS integer) * weights13B[i - 8];
	END LOOP;
	checksum := (checksum % 11) % 10;
	checkval := CAST (checksum AS text);
	RETURN (checkval = SUBSTR(bulstat, 9, 1));
ELSE
	RETURN FALSE;
END IF;
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE LEAKPROOF
  COST 100;
ALTER FUNCTION validate_bulstat(text)
  OWNER TO postgres;


-- Function: validate_egn(text)
-- DROP FUNCTION validate_egn(text);

CREATE OR REPLACE FUNCTION validate_egn(egn text DEFAULT ''::text)
  RETURNS boolean AS
$BODY$
DECLARE
	retval boolean;
	weights integer[] := array[2, 4, 8, 5, 10, 9, 7, 3, 6];
	checksum integer := 0;
	checkval integer;
	i integer;
BEGIN
egn := LTRIM(RTRIM(egn));
IF NOT (egn ~ '^[\d]{10}$') THEN	-- 10 digits
	RETURN false;
END IF;

checkval := CAST(SUBSTR(egn, 10, 1) AS integer);
FOR i IN 1..9 LOOP
	checksum := checksum + CAST(SUBSTR(egn, i, 1) AS integer) * weights[i];
END LOOP;

checksum := (checksum % 11) % 10;
RETURN (checkval = checksum);
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE LEAKPROOF
  COST 100;
ALTER FUNCTION validate_egn(text)
  OWNER TO postgres;


-- Function: validate_iban(text)
-- DROP FUNCTION validate_iban(text);

CREATE OR REPLACE FUNCTION validate_iban(iban text DEFAULT ''::text)
  RETURNS boolean AS
$BODY$
DECLARE
	ibantext text := '';
	ibanlength integer;
	ibansum numeric(50);
	c char(1);
	i integer;
BEGIN
iban = LTRIM(RTRIM(UPPER(iban)));
IF NOT (iban ~ '^[\dA-Z]+$') THEN
	RETURN FALSE;
END IF;

ibanlength := LENGTH(iban);
iban := SUBSTR(iban, 5) || SUBSTR(iban, 1, 4);
FOR i IN 1 .. ibanlength LOOP
	c = SUBSTR(iban, i, 1);
	IF (c ~ '[0-9]') THEN
		ibantext := ibantext || c;
	ELSE
		ibantext := ibantext || CAST(ASCII(c) - ASCII('A') + 10 AS text);
	END IF;
END LOOP;

ibansum := CAST(ibantext AS numeric(50));
RETURN ((ibansum % 97) = 1);
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE LEAKPROOF
  COST 100;
ALTER FUNCTION validate_iban(text)
  OWNER TO postgres;


-- Function: validate_lnch(text)
-- DROP FUNCTION validate_lnch(text);

CREATE OR REPLACE FUNCTION validate_lnch(lnch text DEFAULT ''::text)
  RETURNS boolean AS
$BODY$
DECLARE
	weights integer[] := array[21, 19, 17, 13, 11, 9, 7, 3, 1];
	checksum integer := 0;
	checkval integer;
	i integer;
BEGIN
lnch := LTRIM(RTRIM(lnch));
IF NOT (lnch ~ '^[\d]{10}$') THEN	-- 10 digits
	RETURN false;
END IF;

checkval := CAST(SUBSTR(lnch, 10, 1) AS integer);
FOR i IN 1..9 LOOP
	checksum := checksum + CAST(SUBSTR(lnch, i, 1) AS integer) * weights[i];
END LOOP;

checksum := (checksum % 10);
RETURN (checkval = checksum);
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE LEAKPROOF
  COST 100;
ALTER FUNCTION validate_lnch(text)
  OWNER TO postgres;
