-- ******************************************************************
--  T A B L E S
-- ******************************************************************

drop table if exists "comment_history";
drop table if exists "comment";
drop table if exists "post_history";
drop table if exists "post";
drop table if exists "sub_category";
drop table if exists "category";
drop table if exists "user";
drop table if exists "role";

-- creation of table "role"
create table "role" (
	"id"  serial,
	"name" varchar,
	constraint role_pk primary key ("id"),
	constraint role_name_unique unique ("name")
);

-- creation of table "user"
create table "user" (
	"id"  serial,
	"key" varchar,
	"name" varchar,
	"email" varchar,
	"password" varchar,
	"image" varchar,
	"inscription_date" timestamp,
	"role_id" integer,
	constraint user_pk primary key ("id"),
	constraint user_fk_role_id foreign key ("role_id") references role ("id"),
	constraint user_key_unique unique ("key"),
	constraint user_email_unique unique ("email")
);

-- creation of table "image"
create table "image" (
	"id" serial,
	"link" varchar,
	"date" timestamp,
	"user_id" integer,
	constraint image_pk primary key ("id"),
	constraint image_link_unique unique ("link"),
	constraint image_fk_user_id foreign key ("user_id") references "user" ("id")
);

-- creation of table "category"
create table "category" (
	"id"  serial,
	"name" varchar,
	"creator_id" integer,
	constraint category_pk primary key ("id"),
	constraint category_fk_creator_id foreign key ("creator_id") references "user" ("id"),
	constraint category_name_unique unique ("name")
);

-- creation of table "sub_category"
create table "sub_category" (
	"id"  serial,
	"main_category" integer,
	constraint sub_category_pk primary key ("id"),
	constraint sub_category_fk_id foreign key ("id") references "category" ("id"),
	constraint sub_category_fk_main_category foreign key ("main_category") references "category" ("id")
);

-- creation of table "post"
create table "post" (
	"id"  serial,
	"key" varchar,
	"title" varchar,
	"text" varchar,
	"description" varchar(250),
	"creation_date" timestamp,
	"image" varchar,
	"creator_id" integer,
	"category_id" integer,
	constraint post_pk primary key ("id"),
	constraint post_fk_creator_id foreign key ("creator_id") references "user" ("id"),
	constraint post_fk_category_id foreign key ("category_id") references "category" ("id"),
	constraint post_key_unique unique ("key")
);

-- creation of table "post_history"
create table "post_history" (
	"id"  serial,
	"title" varchar,
	"image" varchar,
	"description" varchar,
	"text" varchar,
	"update_date" timestamp,
	"post_id" integer,
	constraint post_history_pk primary key ("id"),
	constraint post_history_fk_post_id foreign key ("post_id") references "post" ("id")
);

--  creation of table "comment"
create table "comment" (
	"id"  serial ,
	"key" varchar,
	"text" varchar ,
	"creation_date" timestamp ,
	"author" integer ,
	"post_id" integer ,
	constraint comment_pk primary key ("id"),
	constraint comment_fk_author foreign key ("author") references "user" ("id"),
	constraint comment_fk_post_id foreign key ("post_id") references "post" ("id"),
	constraint comment_key_unique unique ("key")
);

create table "comment_history" (
	"id"  serial ,
	"text" varchar ,
	"update_date" timestamp ,
	"comment_id" integer ,
	constraint comment_history_pk primary key ("id"),
	constraint comment_history_fk_comment_id foreign key ("comment_id") references "comment" ("id")
);

-- ******************************************************************
--  F U N C T I O N S
-- ******************************************************************

-- Function which generate a random number in the given range in parameters.
CREATE OR REPLACE FUNCTION random_range(min INTEGER, max INTEGER) RETURNS INTEGER AS $random_range$
	SELECT (min + FLOOR((max - min + 1) * RANDOM()))::INTEGER;
$random_range$ LANGUAGE sql;

-- Function which generate a random string of 10 chars.
CREATE OR REPLACE FUNCTION random_string(prefix VARCHAR) RETURNS TEXT AS $random_string$
	DECLARE
		possible_chars TEXT := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
		length INTEGER := 10;
		result TEXT := '';
		i INTEGER;
		pos INTEGER;
	BEGIN
		IF prefix IS NOT NULL THEN
			result := prefix;
		END IF;
		
		FOR i IN 1..length LOOP
			pos := random_range(1, length(possible_chars));
			result := result || substr(possible_chars, pos, 1);
		END LOOP;
		
		RETURN result;
	END 
$random_string$ LANGUAGE plpgsql;

-- Before inserts into "user", if the new user to insert don't have
-- any value for "role_id", this procedure adds the "user" role id
-- for this column.
-- It generate the "key" attribute too. 
CREATE OR REPLACE FUNCTION set_role_and_key_for_users() RETURNS TRIGGER AS $set_role_and_key_for_users$
	DECLARE
		prefix TEXT := 'USER';
	BEGIN
		-- Association of role "user" for the new user to insert.
		IF NEW.role_id IS NULL THEN
			NEW.role_id := (SELECT id FROM "role" WHERE name = 'user');
		END IF;
		
		-- Generation of the "key" attribute for new user
		NEW.key := random_string(prefix);
		
		RETURN NEW;
	END 
$set_role_and_key_for_users$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS set_role_and_key_for_users ON "user";

CREATE TRIGGER set_role_and_key_for_users BEFORE INSERT ON "user"
	FOR EACH ROW EXECUTE PROCEDURE set_role_and_key_for_users();

-- Before inserts into "post", it generates the "key" attribute.
CREATE OR REPLACE FUNCTION set_key_for_posts() RETURNS TRIGGER AS $set_key_for_posts$
	DECLARE
		prefix TEXT := 'POST';
	BEGIN
		-- Generation of the "key" attribute for new user
		NEW.key := random_string(prefix);
		
		RETURN NEW;
	END 
$set_key_for_posts$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS set_key_for_posts ON "post";

CREATE TRIGGER set_key_for_posts BEFORE INSERT ON "post"
	FOR EACH ROW EXECUTE PROCEDURE set_key_for_posts();

-- Before update into "post", it populates the table "post_history".
CREATE OR REPLACE FUNCTION create_post_history() RETURNS TRIGGER AS $create_post_history$
	BEGIN
		INSERT INTO "post_history" (title, image, description, update_date, text, post_id) VALUES (OLD.title, OLD.image, OLD.description, OLD.creation_date, OLD.text, NEW.id);
	
		RETURN NEW;
	END
$create_post_history$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS create_post_history ON "post";

CREATE TRIGGER create_post_history BEFORE UPDATE ON "post"
	FOR EACH ROW EXECUTE PROCEDURE create_post_history();

-- Before inserts into "comment", it generates the "key" attribute.
CREATE OR REPLACE FUNCTION set_key_for_comments() RETURNS TRIGGER AS $set_key_for_comments$
	DECLARE
		prefix TEXT := 'COMM';
	BEGIN
		-- Generation of the "key" attribute for new user
		NEW.key := random_string(prefix);
		
		RETURN NEW;
	END 
$set_key_for_comments$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS set_key_for_comments ON "comment";

CREATE TRIGGER set_key_for_comments BEFORE INSERT ON "comment"
	FOR EACH ROW EXECUTE PROCEDURE set_key_for_comments();

-- ******************************************************************
--  D E F A U L T   D A T A   I N   T A B L E S
-- ******************************************************************

insert into "role" (name) values
('admin'),
('user');

insert into "user" (name, email, password, inscription_date, role_id) values
('Administrator','admin@admin.adm','$2a$10$0StXSF/n9fbLM8onEmzjAOUdUqX1uIo5u.IdE22C5NlB1ue5KzYaa','2017-09-25 12:42:44.952', 1);

insert into category (name, creator_id) values
('Développement', 1),
('Administration système', 1),
('Administration réseau', 1),
('Divers', 1),
('Java', 1),
('C++', 1),
('Android', 1),
('Sql', 1),
('Linux', 1),
('Autre', 1),
('TypeScript', 1);

insert into sub_category (id, main_category) values
(5, 1),
(6, 1),
(7, 1),
(8, 1),
(9, 2),
(10, 4),
(11, 1);
