DROP FUNCTION IF EXISTS discard_scores();

CREATE FUNCTION discard_scores (keep INTEGER) RETURNS VOID AS $$
BEGIN

  DELETE FROM scores WHERE score_dt <
    (SELECT score_dt FROM scores s WHERE s.alocidispid = scores.alocidispid AND s.blocidispid = scores.blocidispid ORDER BY score_dt DESC LIMIT 1 OFFSET (keep - 1));

	RETURN;
END;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION update_current_network_scores(aloc BIGINT, bloc BIGINT) RETURNS VOID
STRICT VOLATILE AS $$
  DECLARE
    newscore INTEGER;
    newscore_dt TIMESTAMP;
    newscore_limited BOOL;
    sum INTEGER;
    kount INTEGER;
    r RECORD;
    avgscore INTEGER;
    maxscore INTEGER;
    minscore INTEGER;
  BEGIN
    -- find the 6 most recent scores
    -- (supposedly newscore is the first...)
    -- hybrid scheme: compute the average of some recent scores, then limit newscore to be between 4/5 and 6/5 of the average
    newscore := NULL;
    newscore_dt := NULL;
    newscore_limited := FALSE;
    sum := 0;
    kount := 0;
    FOR r IN SELECT score, score_dt FROM scores WHERE alocidispid = aloc AND blocidispid = bloc ORDER BY score_dt DESC LIMIT 6 LOOP
      IF newscore IS NULL THEN
        newscore := r.score;
        newscore_dt := r.score_dt;
      ELSE
        sum := sum + r.score;
        kount := kount + 1;
      END IF;
    END LOOP;

    -- if no scores in query at all, then delete any current entry
    IF newscore IS NULL THEN
      DELETE FROM current_network_scores WHERE alocidispid = aloc AND blocidispid = bloc;
      IF aloc != bloc THEN
        DELETE FROM current_network_scores WHERE alocidispid = bloc AND blocidispid = aloc;
      END IF;
    END IF;

    -- if there are scores older than newscore, then use their average to limit the range of newscore
    IF kount > 0 THEN
      avgscore := sum / kount;
      maxscore := avgscore*6/5;
      minscore := avgscore*4/5;
      -- the score newscore will be inserted as the current value in current_network_scores, but we will limit it
      -- to be no greater than 120% of the average and no less than 80% of the average. this will dampen wild
      -- swings in the scores.
      IF newscore > maxscore THEN
        newscore := maxscore;
        newscore_limited := TRUE;
      ELSEIF newscore < minscore THEN
        newscore := minscore;
        newscore_limited := TRUE;
      END IF;
    END IF;

    UPDATE current_network_scores SET score = newscore, limited = newscore_limited, score_dt = newscore_dt WHERE alocidispid = aloc AND blocidispid = bloc;
    IF NOT FOUND THEN
      INSERT INTO current_network_scores (alocidispid, blocidispid, score, limited, score_dt) VALUES (aloc, bloc, newscore, newscore_limited, newscore_dt);
    END IF;

    IF aloc != bloc THEN
      UPDATE current_network_scores SET score = newscore, limited = newscore_limited, score_dt = newscore_dt WHERE alocidispid = bloc AND blocidispid = aloc;
      IF NOT FOUND THEN
        INSERT INTO current_network_scores (alocidispid, blocidispid, score, limited, score_dt) VALUES (bloc, aloc, newscore, newscore_limited, newscore_dt);
      END IF;
    END IF;

    -- keep the scores table clean, meaning  only up to the most 5 recent scores per group & direction (scorer)
    DELETE FROM scores WHERE alocidispid = aloc AND blocidispid = bloc AND scorer = 0 AND score_dt <
    (SELECT score_dt FROM scores s WHERE s.alocidispid = aloc AND s.blocidispid = bloc AND s.scorer = 0 ORDER BY score_dt DESC LIMIT 1 OFFSET 4);
    DELETE FROM scores WHERE alocidispid = bloc AND blocidispid = aloc AND scorer = 1 AND score_dt <
    (SELECT score_dt FROM scores s WHERE s.alocidispid = bloc AND s.blocidispid = aloc AND s.scorer = 1 ORDER BY score_dt DESC LIMIT 1 OFFSET 4);

  END;
$$ LANGUAGE plpgsql;